55
66import typing
77from typing import (
8+ Generator ,
89 Optional ,
10+ Tuple ,
911 Union ,
1012 List ,
1113)
@@ -1523,7 +1525,7 @@ def _getIA2TargetsForRelationsOfType(
15231525 self ,
15241526 relationType : "IAccessibleHandler.RelationType" ,
15251527 maxRelations : int = 1 ,
1526- ) -> typing . List [IUnknown ]:
1528+ ) -> Generator [IUnknown , None , None ]:
15271529 """Gets the target IAccessible (actually IUnknown; use QueryInterface or
15281530 normalizeIAccessible to resolve) for the relations with given type.
15291531 Allows escape of exception: COMError(-2147417836, 'Requested object does not exist.'),
@@ -1539,17 +1541,20 @@ def _getIA2TargetsForRelationsOfType(
15391541 raise ValueError
15401542 if not isinstance (acc , IA2 .IAccessible2_2 ):
15411543 acc = acc .QueryInterface (IA2 .IAccessible2_2 )
1544+
15421545 targets , count = acc .relationTargetsOfType (
15431546 relationType .value ,
1547+ # Bug in relationTargetsOfType, Chrome does not respect maxRelations param.
1548+ # https://crbug.com/1399184
15441549 maxRelations
15451550 )
1551+ log .debug (f"Got { count } relations, given maxRelations: { maxRelations } " )
15461552 if count == 0 :
1547- return list ()
1548- relationsGen = (
1553+ return
1554+ yield from (
15491555 targets [i ]
15501556 for i in range (min (maxRelations , count ))
15511557 )
1552- return list (relationsGen )
15531558
15541559 def _getIA2RelationFirstTarget (
15551560 self ,
@@ -1568,17 +1573,18 @@ def _getIA2RelationFirstTarget(
15681573
15691574 try :
15701575 # rather than fetch all the relations and querying the type, do that in process for performance reasons
1571- targets = self ._getIA2TargetsForRelationsOfType (relationType , maxRelations = 1 )
1572- if targets :
1573- ia2Object = IAccessibleHandler .normalizeIAccessible (targets [0 ])
1576+ targetsGen = self ._getIA2TargetsForRelationsOfType (relationType , maxRelations = 1 )
1577+ for target in targetsGen :
1578+ ia2Object = IAccessibleHandler .normalizeIAccessible (target )
1579+ # Just take the first.
15741580 return IAccessible (
15751581 IAccessibleObject = ia2Object ,
15761582 IAccessibleChildID = 0
15771583 )
15781584 except (NotImplementedError , COMError ):
15791585 log .debugWarning ("Unable to use _getIA2TargetsForRelationsOfType, fallback to _IA2Relations." )
15801586
1581- # eg IA2_2 is not available, fall back to old approach
1587+ # IA2_2 is not available, fall back to old approach
15821588 try :
15831589 for relation in self ._IA2Relations :
15841590 if relation .relationType == relationType :
@@ -1594,21 +1600,74 @@ def _getIA2RelationFirstTarget(
15941600 pass
15951601 return None
15961602
1603+ def _getIA2RelationTargetsOfType (
1604+ self ,
1605+ relationType : Union [str , IAccessibleHandler .RelationType ]
1606+ ) -> typing .Iterable ["IAccessible" ]:
1607+ """ Get the targets for the relation of type.
1608+ Higher level function than _getIA2TargetsForRelationsOfType
1609+ @param relationType: The type of relation to fetch.
1610+ """
1611+ if not isinstance (relationType , IAccessibleHandler .RelationType ):
1612+ if isinstance (relationType , str ):
1613+ relationType = IAccessibleHandler .RelationType (relationType )
1614+ else :
1615+ raise TypeError (f"Bad type for 'relationType' arg, got: { type (relationType )} " )
1616+
1617+ relationType = typing .cast (IAccessibleHandler .RelationType , relationType )
1618+
1619+ try :
1620+ # rather than fetch all the relations and querying the type, do that in process for performance reasons
1621+ # Bug in Chrome, Chrome does not respect maxRelations param.
1622+ # https://crbug.com/1399184. In future, uncomment the next line.
1623+ # maxRelsToFetch = self.IAccessibleObject.nRelations # they may or may not all match 'relationType'
1624+ maxRelsToFetch = 10
1625+ targetsGen = self ._getIA2TargetsForRelationsOfType (relationType , maxRelations = maxRelsToFetch )
1626+ for target in targetsGen :
1627+ ia2Object = IAccessibleHandler .normalizeIAccessible (target )
1628+ ia = IAccessible (
1629+ IAccessibleObject = ia2Object ,
1630+ IAccessibleChildID = 0
1631+ )
1632+ yield ia
1633+ # NotImplementedError is expected to occur for all targets or none.
1634+ return # Iterated all targets without error.
1635+ except (NotImplementedError , COMError ):
1636+ log .debugWarning ("Unable to use _getIA2TargetsForRelationsOfType, fallback to _IA2Relations." )
1637+
1638+ # IA2_2 is not available, fall back to old approach
1639+ log .debugWarning ("IA2_2 is not available, fall back to old approach" )
1640+ try :
1641+ for relation in self ._IA2Relations :
1642+ if relation .relationType == relationType :
1643+ # Take the first of 'relation.nTargets' see IAccessibleRelation._methods_
1644+ for i in range (0 , relation .nTargets ):
1645+ target = relation .target (i )
1646+ ia2Object = IAccessibleHandler .normalizeIAccessible (target )
1647+ yield IAccessible (
1648+ IAccessibleObject = ia2Object ,
1649+ IAccessibleChildID = 0
1650+ )
1651+ return
1652+ except (NotImplementedError , COMError ):
1653+ log .debug ("Unable to fetch _IA2Relations" , exc_info = True )
1654+ pass
1655+ return None
1656+
15971657 #: Type definition for auto prop '_get_detailsRelations'
1598- detailsRelations : typing .Iterable ["IAccessible" ]
1658+ detailsRelations : Tuple ["IAccessible" ]
1659+
1660+ def _get_detailsRelations (self ) -> Tuple ["IAccessible" ]:
1661+ detailsRelsGen = self ._getIA2RelationTargetsOfType (IAccessibleHandler .RelationType .DETAILS )
1662+ # due to caching of baseObject.AutoPropertyObject, do not attempt to return a generator.
1663+ return tuple (detailsRelsGen )
15991664
16001665 def _get_controllerFor (self ) -> List [NVDAObject ]:
16011666 control = self ._getIA2RelationFirstTarget (IAccessibleHandler .RelationType .CONTROLLER_FOR )
16021667 if control :
16031668 return [control ]
16041669 return []
16051670
1606- def _get_detailsRelations (self ) -> typing .Iterable ["IAccessible" ]:
1607- relationTarget = self ._getIA2RelationFirstTarget (IAccessibleHandler .RelationType .DETAILS )
1608- if not relationTarget :
1609- return ()
1610- return (relationTarget , )
1611-
16121671 #: Type definition for auto prop '_get_flowsTo'
16131672 flowsTo : typing .Optional ["IAccessible" ]
16141673
@@ -1763,7 +1822,7 @@ def _get_devInfo(self):
17631822 ret = "exception: %s" % e
17641823 info .append ("IAccessible2 attributes: %s" % ret )
17651824 try :
1766- ret = ", " .join (r .RelationType for r in self ._IA2Relations )
1825+ ret = ", " .join (f" { r .RelationType } * { r . nTargets } " for r in self ._IA2Relations )
17671826 except Exception as e :
17681827 ret = f"exception: { e } "
17691828 info .append (f"IAccessible2 relations: { ret } " )
0 commit comments