@@ -1713,7 +1713,7 @@ async def _find_keyword(self, name: Optional[str]) -> Optional[KeywordDoc]:
1713
1713
result = await self ._get_explicit_keyword (name )
1714
1714
1715
1715
if not result :
1716
- result = await self ._get_implicit_keyword (name )
1716
+ result = self ._get_implicit_keyword (name )
1717
1717
1718
1718
if not result and self .handle_bdd_style :
1719
1719
result = await self ._get_bdd_style_keyword (name )
@@ -1723,27 +1723,54 @@ async def _find_keyword(self, name: Optional[str]) -> Optional[KeywordDoc]:
1723
1723
async def _get_keyword_from_self (self , name : str ) -> Optional [KeywordDoc ]:
1724
1724
if self .self_library_doc is None :
1725
1725
self .self_library_doc = await self .namespace .get_library_doc ()
1726
- try :
1727
- return self .self_library_doc .keywords .get (name , None )
1728
- except KeywordError as e :
1729
- self .diagnostics .append (
1730
- DiagnosticsEntry (
1731
- str (e ),
1732
- DiagnosticSeverity .ERROR ,
1733
- "KeywordError" ,
1726
+
1727
+ if get_robot_version () >= (6 , 0 , 0 ):
1728
+ found : List [Tuple [Optional [LibraryEntry ], KeywordDoc ]] = [
1729
+ (None , v ) for v in self .self_library_doc .keywords .get_all (name )
1730
+ ]
1731
+ if len (found ) > 1 :
1732
+ found = self ._select_best_matches (found )
1733
+ if len (found ) > 1 :
1734
+ self .diagnostics .append (
1735
+ DiagnosticsEntry (
1736
+ self ._create_multiple_keywords_found_message (name , found , implicit = False ),
1737
+ DiagnosticSeverity .ERROR ,
1738
+ "KeywordError" ,
1739
+ )
1740
+ )
1741
+ raise CancelSearchError ()
1742
+
1743
+ if len (found ) == 1 :
1744
+ # TODO warning if keyword found is defined in resource and suite
1745
+ return found [0 ][1 ]
1746
+
1747
+ return None
1748
+ else :
1749
+ try :
1750
+ return self .self_library_doc .keywords .get (name , None )
1751
+ except KeywordError as e :
1752
+ self .diagnostics .append (
1753
+ DiagnosticsEntry (
1754
+ str (e ),
1755
+ DiagnosticSeverity .ERROR ,
1756
+ "KeywordError" ,
1757
+ )
1734
1758
)
1735
- )
1736
- raise CancelSearchError () from e
1759
+ raise CancelSearchError () from e
1737
1760
1738
1761
async def _yield_owner_and_kw_names (self , full_name : str ) -> AsyncGenerator [Tuple [str , ...], None ]:
1739
1762
tokens = full_name .split ("." )
1740
1763
for i in range (1 , len (tokens )):
1741
1764
yield "." .join (tokens [:i ]), "." .join (tokens [i :])
1742
1765
1743
1766
async def _get_explicit_keyword (self , name : str ) -> Optional [KeywordDoc ]:
1744
- found : List [Tuple [LibraryEntry , KeywordDoc ]] = []
1767
+ found : List [Tuple [Optional [ LibraryEntry ] , KeywordDoc ]] = []
1745
1768
async for owner_name , kw_name in self ._yield_owner_and_kw_names (name ):
1746
1769
found .extend (await self .find_keywords (owner_name , kw_name ))
1770
+
1771
+ if get_robot_version () >= (6 , 0 , 0 ) and len (found ) > 1 :
1772
+ found = self ._select_best_matches (found )
1773
+
1747
1774
if len (found ) > 1 :
1748
1775
self .diagnostics .append (
1749
1776
DiagnosticsEntry (
@@ -1756,36 +1783,50 @@ async def _get_explicit_keyword(self, name: str) -> Optional[KeywordDoc]:
1756
1783
1757
1784
return found [0 ][1 ] if found else None
1758
1785
1759
- async def find_keywords (self , owner_name : str , name : str ) -> Sequence [Tuple [LibraryEntry , KeywordDoc ]]:
1786
+ async def find_keywords (self , owner_name : str , name : str ) -> List [Tuple [LibraryEntry , KeywordDoc ]]:
1760
1787
if self ._all_keywords is None :
1761
1788
self ._all_keywords = [
1762
1789
v for v in chain (self .namespace ._libraries .values (), self .namespace ._resources .values ())
1763
1790
]
1764
- return [
1765
- (v , v .library_doc .keywords [name ])
1766
- for v in self ._all_keywords
1767
- if eq (v .alias or v .name , owner_name ) and name in v .library_doc .keywords
1768
- ]
1791
+
1792
+ if get_robot_version () >= (6 , 0 , 0 ):
1793
+ result : List [Tuple [LibraryEntry , KeywordDoc ]] = []
1794
+ for v in self ._all_keywords :
1795
+ if eq (v .alias or v .name , owner_name ):
1796
+ result .extend ((v , kw ) for kw in v .library_doc .keywords .get_all (name ))
1797
+ return result
1798
+ else :
1799
+ result = []
1800
+ for v in self ._all_keywords :
1801
+ if eq (v .alias or v .name , owner_name ):
1802
+ kw = v .library_doc .keywords .get (name , None )
1803
+ if kw is not None :
1804
+ result .append ((v , kw ))
1805
+ return result
1769
1806
1770
1807
def _create_multiple_keywords_found_message (
1771
- self , name : str , found : Sequence [Tuple [LibraryEntry , KeywordDoc ]], implicit : bool = True
1808
+ self , name : str , found : Sequence [Tuple [Optional [ LibraryEntry ] , KeywordDoc ]], implicit : bool = True
1772
1809
) -> str :
1810
+ if any (e [1 ].is_embedded for e in found ):
1811
+ error = f"Multiple keywords matching name '{ name } ' found"
1812
+ else :
1813
+ error = f"Multiple keywords with name '{ name } ' found"
1773
1814
1774
- error = "Multiple keywords with name '%s' found" % name
1775
- if implicit :
1776
- error += ". Give the full name of the keyword you want to use"
1777
- names = sorted (f"{ e [0 ] .alias or e [0 ].name } .{ e [1 ].name } " for e in found )
1815
+ if implicit :
1816
+ error += ". Give the full name of the keyword you want to use"
1817
+
1818
+ names = sorted (f"{ e [1 ]. name if e [ 0 ] is None else f' { e [ 0 ] .alias or e [0 ].name } .{ e [1 ].name } ' } " for e in found )
1778
1819
return "\n " .join ([error + ":" ] + names )
1779
1820
1780
- async def _get_implicit_keyword (self , name : str ) -> Optional [KeywordDoc ]:
1781
- result = await self ._get_keyword_from_resource_files (name )
1821
+ def _get_implicit_keyword (self , name : str ) -> Optional [KeywordDoc ]:
1822
+ result = self ._get_keyword_from_resource_files (name )
1782
1823
if not result :
1783
- result = await self ._get_keyword_from_libraries (name )
1824
+ result = self ._get_keyword_from_libraries (name )
1784
1825
return result
1785
1826
1786
1827
def _prioritize_same_file_or_public (
1787
- self , entries : List [Tuple [LibraryEntry , KeywordDoc ]]
1788
- ) -> List [Tuple [LibraryEntry , KeywordDoc ]]:
1828
+ self , entries : List [Tuple [Optional [ LibraryEntry ] , KeywordDoc ]]
1829
+ ) -> List [Tuple [Optional [ LibraryEntry ] , KeywordDoc ]]:
1789
1830
1790
1831
matches = [h for h in entries if h [1 ].source == self .namespace .source ]
1791
1832
if matches :
@@ -1796,8 +1837,8 @@ def _prioritize_same_file_or_public(
1796
1837
return matches or entries
1797
1838
1798
1839
def _select_best_matches (
1799
- self , entries : List [Tuple [LibraryEntry , KeywordDoc ]]
1800
- ) -> List [Tuple [LibraryEntry , KeywordDoc ]]:
1840
+ self , entries : List [Tuple [Optional [ LibraryEntry ] , KeywordDoc ]]
1841
+ ) -> List [Tuple [Optional [ LibraryEntry ] , KeywordDoc ]]:
1801
1842
1802
1843
normal = [hand for hand in entries if not hand [1 ].is_embedded ]
1803
1844
if normal :
@@ -1807,7 +1848,9 @@ def _select_best_matches(
1807
1848
return matches or entries
1808
1849
1809
1850
def _is_worse_match_than_others (
1810
- self , candidate : Tuple [LibraryEntry , KeywordDoc ], alternatives : List [Tuple [LibraryEntry , KeywordDoc ]]
1851
+ self ,
1852
+ candidate : Tuple [Optional [LibraryEntry ], KeywordDoc ],
1853
+ alternatives : List [Tuple [Optional [LibraryEntry ], KeywordDoc ]],
1811
1854
) -> bool :
1812
1855
for other in alternatives :
1813
1856
if (
@@ -1819,31 +1862,47 @@ def _is_worse_match_than_others(
1819
1862
return False
1820
1863
1821
1864
def _is_better_match (
1822
- self , candidate : Tuple [LibraryEntry , KeywordDoc ], other : Tuple [LibraryEntry , KeywordDoc ]
1865
+ self , candidate : Tuple [Optional [ LibraryEntry ] , KeywordDoc ], other : Tuple [Optional [ LibraryEntry ] , KeywordDoc ]
1823
1866
) -> bool :
1824
1867
return (
1825
1868
other [1 ].matcher .embedded_arguments .match (candidate [1 ].name ) is not None
1826
1869
and candidate [1 ].matcher .embedded_arguments .match (other [1 ].name ) is None
1827
1870
)
1828
1871
1829
- async def _get_keyword_from_resource_files (self , name : str ) -> Optional [KeywordDoc ]:
1872
+ def _get_keyword_from_resource_files (self , name : str ) -> Optional [KeywordDoc ]:
1830
1873
if self ._resource_keywords is None :
1831
1874
self ._resource_keywords = [v for v in chain (self .namespace ._resources .values ())]
1832
1875
1833
- found : List [Tuple [LibraryEntry , KeywordDoc ]] = [
1834
- (v , v .library_doc .keywords [name ]) for v in self ._resource_keywords if name in v .library_doc .keywords
1835
- ]
1876
+ if get_robot_version () >= (6 , 0 , 0 ):
1877
+ found : List [Tuple [Optional [LibraryEntry ], KeywordDoc ]] = []
1878
+ for v in self ._resource_keywords :
1879
+ r = v .library_doc .keywords .get_all (name )
1880
+ if r :
1881
+ found .extend ([(v , k ) for k in r ])
1882
+ else :
1883
+ found = []
1884
+ for k in self ._resource_keywords :
1885
+ s = k .library_doc .keywords .get (name , None )
1886
+ if s is not None :
1887
+ found .append ((k , s ))
1888
+
1836
1889
if not found :
1837
1890
return None
1891
+
1838
1892
if get_robot_version () >= (6 , 0 , 0 ):
1839
1893
if len (found ) > 1 :
1840
1894
found = self ._prioritize_same_file_or_public (found )
1841
1895
1896
+ if len (found ) > 1 :
1897
+ found = self ._select_best_matches (found )
1898
+
1899
+ if len (found ) > 1 :
1900
+ found = self ._get_keyword_based_on_search_order (found )
1901
+
1902
+ else :
1842
1903
if len (found ) > 1 :
1843
- found = self ._select_best_matches (found )
1904
+ found = self ._get_keyword_based_on_search_order (found )
1844
1905
1845
- if len (found ) > 1 :
1846
- found = await self ._get_keyword_based_on_search_order (found )
1847
1906
if len (found ) == 1 :
1848
1907
return found [0 ][1 ]
1849
1908
@@ -1856,27 +1915,49 @@ async def _get_keyword_from_resource_files(self, name: str) -> Optional[KeywordD
1856
1915
)
1857
1916
raise CancelSearchError ()
1858
1917
1859
- async def _get_keyword_based_on_search_order (
1860
- self , entries : List [Tuple [LibraryEntry , KeywordDoc ]]
1861
- ) -> List [Tuple [LibraryEntry , KeywordDoc ]]:
1918
+ def _get_keyword_based_on_search_order (
1919
+ self , entries : List [Tuple [Optional [ LibraryEntry ] , KeywordDoc ]]
1920
+ ) -> List [Tuple [Optional [ LibraryEntry ] , KeywordDoc ]]:
1862
1921
1863
1922
for libname in self .namespace .search_order :
1864
1923
for e in entries :
1865
- if eq (libname , e [0 ].alias or e [0 ].name ):
1924
+ if e [ 0 ] is not None and eq (libname , e [0 ].alias or e [0 ].name ):
1866
1925
return [e ]
1867
1926
1868
1927
return entries
1869
1928
1870
- async def _get_keyword_from_libraries (self , name : str ) -> Optional [KeywordDoc ]:
1929
+ def _get_keyword_from_libraries (self , name : str ) -> Optional [KeywordDoc ]:
1871
1930
if self ._library_keywords is None :
1872
1931
self ._library_keywords = [v for v in chain (self .namespace ._libraries .values ())]
1873
- found = [(v , v .library_doc .keywords [name ]) for v in self ._library_keywords if name in v .library_doc .keywords ]
1932
+
1933
+ if get_robot_version () >= (6 , 0 , 0 ):
1934
+ found : List [Tuple [Optional [LibraryEntry ], KeywordDoc ]] = []
1935
+ for v in self ._library_keywords :
1936
+ r = v .library_doc .keywords .get_all (name )
1937
+ if r :
1938
+ found .extend ([(v , k ) for k in r ])
1939
+ else :
1940
+ found = []
1941
+
1942
+ for k in self ._library_keywords :
1943
+ s = k .library_doc .keywords .get (name , None )
1944
+ if s is not None :
1945
+ found .append ((k , s ))
1946
+
1874
1947
if not found :
1875
1948
return None
1876
- if len (found ) > 1 :
1877
- found = await self ._get_keyword_based_on_search_order (found )
1878
- if len (found ) == 2 :
1879
- found = await self ._filter_stdlib_runner (* found )
1949
+
1950
+ if get_robot_version () >= (6 , 0 , 0 ):
1951
+ if len (found ) > 1 :
1952
+ found = self ._select_best_matches (found )
1953
+ if len (found ) > 1 :
1954
+ found = self ._get_keyword_based_on_search_order (found )
1955
+ else :
1956
+ if len (found ) > 1 :
1957
+ found = self ._get_keyword_based_on_search_order (found )
1958
+ if len (found ) == 2 :
1959
+ found = self ._filter_stdlib_runner (* found )
1960
+
1880
1961
if len (found ) == 1 :
1881
1962
return found [0 ][1 ]
1882
1963
@@ -1889,15 +1970,15 @@ async def _get_keyword_from_libraries(self, name: str) -> Optional[KeywordDoc]:
1889
1970
)
1890
1971
raise CancelSearchError ()
1891
1972
1892
- async def _filter_stdlib_runner (
1893
- self , entry1 : Tuple [LibraryEntry , KeywordDoc ], entry2 : Tuple [LibraryEntry , KeywordDoc ]
1894
- ) -> List [Tuple [LibraryEntry , KeywordDoc ]]:
1973
+ def _filter_stdlib_runner (
1974
+ self , entry1 : Tuple [Optional [ LibraryEntry ] , KeywordDoc ], entry2 : Tuple [Optional [ LibraryEntry ] , KeywordDoc ]
1975
+ ) -> List [Tuple [Optional [ LibraryEntry ] , KeywordDoc ]]:
1895
1976
from robot .libraries import STDLIBS
1896
1977
1897
1978
stdlibs_without_remote = STDLIBS - {"Remote" }
1898
- if entry1 [0 ].name in stdlibs_without_remote :
1979
+ if entry1 [0 ] is not None and entry1 [ 0 ] .name in stdlibs_without_remote :
1899
1980
standard , custom = entry1 , entry2
1900
- elif entry2 [0 ].name in stdlibs_without_remote :
1981
+ elif entry2 [0 ] is not None and entry2 [ 0 ] .name in stdlibs_without_remote :
1901
1982
standard , custom = entry2 , entry1
1902
1983
else :
1903
1984
return [entry1 , entry2 ]
@@ -1913,19 +1994,21 @@ async def _filter_stdlib_runner(
1913
1994
return [custom ]
1914
1995
1915
1996
def _create_custom_and_standard_keyword_conflict_warning_message (
1916
- self , custom : Tuple [LibraryEntry , KeywordDoc ], standard : Tuple [LibraryEntry , KeywordDoc ]
1997
+ self , custom : Tuple [Optional [ LibraryEntry ] , KeywordDoc ], standard : Tuple [Optional [ LibraryEntry ] , KeywordDoc ]
1917
1998
) -> str :
1918
1999
custom_with_name = standard_with_name = ""
1919
- if custom [0 ].alias is not None :
2000
+ if custom [0 ] is not None and custom [ 0 ] .alias is not None :
1920
2001
custom_with_name = " imported as '%s'" % custom [0 ].alias
1921
- if standard [0 ].alias is not None :
2002
+ if standard [0 ] is not None and standard [ 0 ] .alias is not None :
1922
2003
standard_with_name = " imported as '%s'" % standard [0 ].alias
1923
2004
return (
1924
2005
f"Keyword '{ standard [1 ].name } ' found both from a custom test library "
1925
- f"'{ custom [0 ].name } '{ custom_with_name } and a standard library '{ standard [1 ].name } '{ standard_with_name } . "
2006
+ f"'{ '' if custom [0 ] is None else custom [0 ].name } '{ custom_with_name } "
2007
+ f"and a standard library '{ standard [1 ].name } '{ standard_with_name } . "
1926
2008
f"The custom keyword is used. To select explicitly, and to get "
1927
- f"rid of this warning, use either '{ custom [0 ].alias or custom [0 ].name } .{ custom [1 ].name } ' "
1928
- f"or '{ standard [0 ].alias or standard [0 ].name } .{ standard [1 ].name } '."
2009
+ f"rid of this warning, use either "
2010
+ f"'{ '' if custom [0 ] is None else custom [0 ].alias or custom [0 ].name } .{ custom [1 ].name } ' "
2011
+ f"or '{ '' if standard [0 ] is None else standard [0 ].alias or standard [0 ].name } .{ standard [1 ].name } '."
1929
2012
)
1930
2013
1931
2014
async def _get_bdd_style_keyword (self , name : str ) -> Optional [KeywordDoc ]:
0 commit comments