script_bindings: Add type definitions for configuration.py (#38450)

*Describe the changes that this pull request makes here. This will be
the commit message.*

Testing: *Describe how this pull request is tested or why it doesn't
require tests*
Fixes: *Link to an issue this pull requests fixes or remove this line if
there is no issue*

---------

Signed-off-by: Jerens Lensun <jerensslensun@gmail.com>
This commit is contained in:
Jerens Lensun 2025-08-06 13:44:05 +08:00 committed by GitHub
parent 62b181dc85
commit 5b148cf5de
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 66 additions and 45 deletions

View file

@ -136,10 +136,9 @@ def isDomInterface(t: IDLObject, logging: bool = False) -> bool:
t = t.inner t = t.inner
if isinstance(t, IDLInterface): if isinstance(t, IDLInterface):
return True return True
# pyrefly: ignore # missing-attribute assert isinstance(t, IDLType)
if t.isCallback() or t.isPromise(): if t.isCallback() or t.isPromise():
return True return True
# pyrefly: ignore # missing-attribute
return t.isInterface() and (t.isSpiderMonkeyInterface() and not t.isBufferSource()) return t.isInterface() and (t.isSpiderMonkeyInterface() and not t.isBufferSource())
@ -160,9 +159,9 @@ def containsDomInterface(t: IDLObject, logging: bool = False) -> bool:
return any(map(lambda x: containsDomInterface(x), t.members)) or (t.parent and containsDomInterface(t.parent)) return any(map(lambda x: containsDomInterface(x), t.members)) or (t.parent and containsDomInterface(t.parent))
if isDomInterface(t): if isDomInterface(t):
return True return True
# pyrefly: ignore # missing-attribute assert isinstance(t, IDLType)
if t.isSequence(): if t.isSequence():
# pyrefly: ignore # missing-attribute assert isinstance(t, IDLSequenceType)
return containsDomInterface(t.inner) return containsDomInterface(t.inner)
return False return False
@ -2674,11 +2673,13 @@ def getAllTypes(
for dictionary in dictionaries: for dictionary in dictionaries:
for t in getTypesFromDictionary(dictionary): for t in getTypesFromDictionary(dictionary):
if t.isRecord(): if t.isRecord():
# pyrefly: ignore # missing-attribute
yield (t.inner, None) yield (t.inner, None)
yield (t, None) yield (t, None)
for callback in callbacks: for callback in callbacks:
for t in getTypesFromCallback(callback): for t in getTypesFromCallback(callback):
if t.isRecord(): if t.isRecord():
# pyrefly: ignore # missing-attribute
yield (t.inner, None) yield (t.inner, None)
yield (t, None) yield (t, None)
for typedef in typedefs: for typedef in typedefs:
@ -2713,7 +2714,7 @@ def UnionTypes(
t = t.unroll() t = t.unroll()
if not t.isUnion(): if not t.isUnion():
continue continue
# pyrefly: ignore # missing-attribute assert isinstance(t, IDLUnionType) and t.flatMemberTypes is not None
for memberType in t.flatMemberTypes: for memberType in t.flatMemberTypes:
if memberType.isDictionary() or memberType.isEnum() or memberType.isCallback(): if memberType.isDictionary() or memberType.isEnum() or memberType.isCallback():
memberModule = getModuleFromObject(memberType) memberModule = getModuleFromObject(memberType)
@ -7828,43 +7829,38 @@ def type_needs_tracing(t: IDLObject):
assert isinstance(t, IDLObject), (t, type(t)) assert isinstance(t, IDLObject), (t, type(t))
if t.isType(): if t.isType():
assert isinstance(t, IDLType)
if isinstance(t, IDLWrapperType): if isinstance(t, IDLWrapperType):
return type_needs_tracing(t.inner) return type_needs_tracing(t.inner)
# pyrefly: ignore # missing-attribute
if t.nullable(): if t.nullable():
# pyrefly: ignore # missing-attribute assert isinstance(t, IDLNullableType)
return type_needs_tracing(t.inner) return type_needs_tracing(t.inner)
# pyrefly: ignore # missing-attribute
if t.isAny(): if t.isAny():
return True return True
# pyrefly: ignore # missing-attribute
if t.isObject(): if t.isObject():
return True return True
# pyrefly: ignore # missing-attribute
if t.isSequence() : if t.isSequence() :
# pyrefly: ignore # missing-attribute assert isinstance(t, IDLSequenceType)
return type_needs_tracing(t.inner) return type_needs_tracing(t.inner)
if t.isUnion(): if t.isUnion():
# pyrefly: ignore # not-iterable assert isinstance(t, IDLUnionType) and t.flatMemberTypes is not None
return any(type_needs_tracing(member) for member in t.flatMemberTypes) return any(type_needs_tracing(member) for member in t.flatMemberTypes)
# pyrefly: ignore # bad-argument-type
if is_typed_array(t): if is_typed_array(t):
return True return True
return False return False
if t.isDictionary(): if t.isDictionary():
# pyrefly: ignore # missing-attribute, bad-argument-type assert isinstance(t, IDLDictionary)
if t.parent and type_needs_tracing(t.parent): if t.parent and type_needs_tracing(t.parent):
return True return True
# pyrefly: ignore # missing-attribute
if any(type_needs_tracing(member.type) for member in t.members): if any(type_needs_tracing(member.type) for member in t.members):
return True return True

View file

@ -4,8 +4,21 @@
import functools import functools
import os import os
from typing import Any
from WebIDL import IDLExternalInterface, IDLSequenceType, IDLWrapperType, WebIDLError from WebIDL import (
IDLExternalInterface,
IDLSequenceType,
IDLWrapperType,
WebIDLError,
IDLObject,
IDLType,
IDLInterface,
IDLDictionary,
IDLCallback,
IDLAttribute,
IDLMethod,
)
class Configuration: class Configuration:
@ -13,7 +26,14 @@ class Configuration:
Represents global configuration state based on IDL parse data and Represents global configuration state based on IDL parse data and
the configuration file. the configuration file.
""" """
def __init__(self, filename, parseData) -> None: glbl: dict[str, Any]
enumConfig: dict[str, Any]
dictConfig: dict[str, Any]
unionConfig: dict[str, Any]
descriptors: list["Descriptor"]
interfaces: dict[str, IDLInterface]
def __init__(self, filename: str, parseData: list[IDLInterface]) -> None:
# Read the configuration file. # Read the configuration file.
glbl = {} glbl = {}
exec(compile(open(filename).read(), filename, 'exec'), glbl) exec(compile(open(filename).read(), filename, 'exec'), glbl)
@ -70,15 +90,15 @@ class Configuration:
return (x > y) - (x < y) return (x > y) - (x < y)
self.descriptors.sort(key=functools.cmp_to_key(lambda x, y: cmp(x.name, y.name))) self.descriptors.sort(key=functools.cmp_to_key(lambda x, y: cmp(x.name, y.name)))
def getInterface(self, ifname): def getInterface(self, ifname: str) -> IDLInterface:
return self.interfaces[ifname] return self.interfaces[ifname]
def getDescriptors(self, **filters): def getDescriptors(self, **filters) -> list["Descriptor"]:
"""Gets the descriptors that match the given filters.""" """Gets the descriptors that match the given filters."""
curr = self.descriptors curr = self.descriptors
for key, val in filters.items(): for key, val in filters.items():
if key == 'webIDLFile': if key == 'webIDLFile':
def getter(x): def getter(x: Descriptor):
return x.interface.location.filename return x.interface.location.filename
elif key == 'hasInterfaceObject': elif key == 'hasInterfaceObject':
def getter(x): def getter(x):
@ -110,36 +130,36 @@ class Configuration:
curr = [x for x in curr if getter(x) == val] curr = [x for x in curr if getter(x) == val]
return curr return curr
def getEnums(self, webIDLFile): def getEnums(self, webIDLFile: str) -> list[IDLInterface]:
return [e for e in self.enums if e.filename == webIDLFile] return [e for e in self.enums if e.filename == webIDLFile]
def getEnumConfig(self, name): def getEnumConfig(self, name: str) -> dict[str, Any]:
return self.enumConfig.get(name, {}) return self.enumConfig.get(name, {})
def getTypedefs(self, webIDLFile): def getTypedefs(self, webIDLFile: str) -> list[IDLInterface]:
return [e for e in self.typedefs if e.filename == webIDLFile] return [e for e in self.typedefs if e.filename == webIDLFile]
@staticmethod @staticmethod
def _filterForFile(items, webIDLFile=""): def _filterForFile(items: list[IDLInterface], webIDLFile: str = "") -> list[IDLInterface]:
"""Gets the items that match the given filters.""" """Gets the items that match the given filters."""
if not webIDLFile: if not webIDLFile:
return items return items
return [x for x in items if x.filename == webIDLFile] return [x for x in items if x.filename == webIDLFile]
def getUnionConfig(self, name): def getUnionConfig(self, name: str) -> dict[str, Any]:
return self.unionConfig.get(name, {}) return self.unionConfig.get(name, {})
def getDictionaries(self, webIDLFile=""): def getDictionaries(self, webIDLFile: str = "") -> list[IDLInterface]:
return self._filterForFile(self.dictionaries, webIDLFile=webIDLFile) return self._filterForFile(self.dictionaries, webIDLFile=webIDLFile)
def getDictConfig(self, name): def getDictConfig(self, name: str) -> dict[str, Any]:
return self.dictConfig.get(name, {}) return self.dictConfig.get(name, {})
def getCallbacks(self, webIDLFile=""): def getCallbacks(self, webIDLFile: str = "") -> list[IDLInterface]:
return self._filterForFile(self.callbacks, webIDLFile=webIDLFile) return self._filterForFile(self.callbacks, webIDLFile=webIDLFile)
def getDescriptor(self, interfaceName): def getDescriptor(self, interfaceName: str) -> "Descriptor":
""" """
Gets the appropriate descriptor for the given interface name. Gets the appropriate descriptor for the given interface name.
""" """
@ -152,7 +172,7 @@ class Configuration:
+ str(len(descriptors)) + " matches") + str(len(descriptors)) + " matches")
return descriptors[0] return descriptors[0]
def getDescriptorProvider(self): def getDescriptorProvider(self) -> "DescriptorProvider":
""" """
Gets a descriptor provider that can provide descriptors as needed. Gets a descriptor provider that can provide descriptors as needed.
""" """
@ -171,7 +191,7 @@ class DescriptorProvider:
def __init__(self, config) -> None: def __init__(self, config) -> None:
self.config = config self.config = config
def getDescriptor(self, interfaceName): def getDescriptor(self, interfaceName: str) -> "Descriptor":
""" """
Gets the appropriate descriptor for the given interface name given the Gets the appropriate descriptor for the given interface name given the
context of the current descriptor. context of the current descriptor.
@ -179,7 +199,7 @@ class DescriptorProvider:
return self.config.getDescriptor(interfaceName) return self.config.getDescriptor(interfaceName)
def MemberIsLegacyUnforgeable(member, descriptor): def MemberIsLegacyUnforgeable(member: IDLAttribute | IDLMethod, descriptor: "Descriptor") -> bool:
return ((member.isAttr() or member.isMethod()) return ((member.isAttr() or member.isMethod())
and not member.isStatic() and not member.isStatic()
and (member.isLegacyUnforgeable() and (member.isLegacyUnforgeable()
@ -190,7 +210,10 @@ class Descriptor(DescriptorProvider):
""" """
Represents a single descriptor for an interface. See Bindings.conf. Represents a single descriptor for an interface. See Bindings.conf.
""" """
def __init__(self, config, interface, desc) -> None: interface: IDLInterface
uniqueImplementation: bool
def __init__(self, config, interface: IDLInterface, desc: dict[str, Any]) -> None:
DescriptorProvider.__init__(self, config) DescriptorProvider.__init__(self, config)
self.interface = interface self.interface = interface
@ -211,6 +234,7 @@ class Descriptor(DescriptorProvider):
# functionality. # functionality.
prefix = "D::" prefix = "D::"
if self.interface.isIteratorInterface(): if self.interface.isIteratorInterface():
assert self.interface.iterableInterface is not None
itrName = self.interface.iterableInterface.identifier.name itrName = self.interface.iterableInterface.identifier.name
itrDesc = self.getDescriptor(itrName) itrDesc = self.getDescriptor(itrName)
nativeTypeDefault = iteratorNativeType(itrDesc) nativeTypeDefault = iteratorNativeType(itrDesc)
@ -290,7 +314,7 @@ class Descriptor(DescriptorProvider):
self.hasDefaultToJSON = True self.hasDefaultToJSON = True
if self.concrete: if self.concrete:
iface = self.interface iface: IDLInterface | None = self.interface
while iface: while iface:
for m in iface.members: for m in iface.members:
if not m.isMethod(): if not m.isMethod():
@ -346,7 +370,7 @@ class Descriptor(DescriptorProvider):
else: else:
assert isinstance(config, str) assert isinstance(config, str)
if config == '*': if config == '*':
iface = self.interface iface: IDLInterface | None = self.interface
while iface: while iface:
add('all', [m.name for m in iface.members], attribute) add('all', [m.name for m in iface.members], attribute)
iface = iface.parent iface = iface.parent
@ -373,7 +397,7 @@ class Descriptor(DescriptorProvider):
# Build the prototype chain. # Build the prototype chain.
self.prototypeChain = [] self.prototypeChain = []
parent = interface parent: IDLInterface | None = interface
while parent: while parent:
self.prototypeChain.insert(0, parent.identifier.name) self.prototypeChain.insert(0, parent.identifier.name)
parent = parent.parent parent = parent.parent
@ -392,10 +416,10 @@ class Descriptor(DescriptorProvider):
return filename return filename
return None return None
def binaryNameFor(self, name, isStatic): def binaryNameFor(self, name: str, isStatic: bool):
return self._binaryNames.get((name, isStatic), name) return self._binaryNames.get((name, isStatic), name)
def internalNameFor(self, name): def internalNameFor(self, name: str):
return self._internalNames.get(name, name) return self._internalNames.get(name, name)
def hasNamedPropertiesObject(self) -> bool: def hasNamedPropertiesObject(self) -> bool:
@ -487,15 +511,15 @@ def MakeNativeName(name):
return name[0].upper() + name[1:] return name[0].upper() + name[1:]
def getIdlFileName(object): def getIdlFileName(object: IDLObject):
return os.path.basename(object.location.filename).split('.webidl')[0] return os.path.basename(object.location.filename).split('.webidl')[0]
def getModuleFromObject(object): def getModuleFromObject(object: IDLObject):
return ('crate::codegen::GenericBindings::' + getIdlFileName(object) + 'Binding') return ('crate::codegen::GenericBindings::' + getIdlFileName(object) + 'Binding')
def getTypesFromDescriptor(descriptor): def getTypesFromDescriptor(descriptor: Descriptor):
""" """
Get all argument and return types for all members of the descriptor Get all argument and return types for all members of the descriptor
""" """
@ -515,7 +539,7 @@ def getTypesFromDescriptor(descriptor):
return types return types
def getTypesFromDictionary(dictionary): def getTypesFromDictionary(dictionary: IDLDictionary) -> list[IDLType]:
""" """
Get all member types for this dictionary Get all member types for this dictionary
""" """
@ -529,7 +553,7 @@ def getTypesFromDictionary(dictionary):
return types return types
def getTypesFromCallback(callback): def getTypesFromCallback(callback: IDLCallback) -> list[IDLType]:
""" """
Get the types this callback depends on: its return type and the Get the types this callback depends on: its return type and the
types of its arguments. types of its arguments.
@ -540,13 +564,14 @@ def getTypesFromCallback(callback):
return types return types
def getUnwrappedType(type): def getUnwrappedType(type: IDLType) -> IDLType:
while isinstance(type, IDLSequenceType): while isinstance(type, IDLSequenceType):
type = type.inner type = type.inner
return type return type
def iteratorNativeType(descriptor, infer=False): def iteratorNativeType(descriptor: Descriptor, infer: bool = False):
assert descriptor.interface.maplikeOrSetlikeOrIterable is not None
iterableDecl = descriptor.interface.maplikeOrSetlikeOrIterable iterableDecl = descriptor.interface.maplikeOrSetlikeOrIterable
assert (iterableDecl.isIterable() and iterableDecl.isPairIterator()) \ assert (iterableDecl.isIterable() and iterableDecl.isPairIterator()) \
or iterableDecl.isSetlike() or iterableDecl.isMaplike() or iterableDecl.isSetlike() or iterableDecl.isMaplike()