Coverage for flogin/query.py: 100%

46 statements  

« prev     ^ index     » next       coverage.py v7.9.2, created at 2025-07-03 22:51 +0000

1from __future__ import annotations 

2 

3from typing import TYPE_CHECKING, Any, Generic, TypedDict, TypeVar 

4 

5from .utils import MISSING 

6 

7if TYPE_CHECKING: 

8 from typing_extensions import TypeVar # noqa: TC004 

9 

10 from ._types.search_handlers import PluginT 

11 from .jsonrpc.results import Result 

12 

13 ConditionDataT = TypeVar("ConditionDataT", default=Any) 

14 

15else: 

16 ConditionDataT = TypeVar("ConditionDataT") 

17 

18__all__ = ("Query",) 

19 

20 

21class RawQuery(TypedDict): 

22 search: str 

23 rawQuery: str 

24 isReQuery: bool 

25 actionKeyword: str 

26 

27 

28class Query(Generic[ConditionDataT]): 

29 r"""This class represents the query data sent from flow launcher 

30 

31 .. container:: operations 

32 

33 .. describe:: x == y 

34 

35 Compare the keywords, text, and is_query values of two query objects. 

36 

37 .. describe:: hash(x) 

38 

39 Gets the hash of the query's raw text 

40 

41 Attributes 

42 ---------- 

43 raw_text: :class:`str`: 

44 The raw and complete query, which includes the keyword 

45 is_requery: :class:`bool` 

46 Whether the query is a requery or not 

47 text: :class:`str` 

48 The actual query, excluding any keywords 

49 keyword: :class:`str` 

50 The keyword used to initiate the query 

51 """ 

52 

53 def __init__(self, data: RawQuery, plugin: PluginT) -> None: 

54 self.__search_condition_data: ConditionDataT | None = None 

55 self._data = data 

56 self.plugin = plugin 

57 

58 @property 

59 def condition_data(self) -> ConditionDataT | None: 

60 """:class:`Any` | ``None``: If used in a :class:`~flogin.search_handler.SearchHandler`, this attribute will return any extra data that the condition gave.""" 

61 return self.__search_condition_data 

62 

63 @condition_data.setter 

64 def condition_data(self, value: ConditionDataT) -> None: 

65 self.__search_condition_data = value 

66 

67 @property 

68 def is_requery(self) -> bool: 

69 return self._data["isReQuery"] 

70 

71 @property 

72 def keyword(self) -> str: 

73 return self._data["actionKeyword"] or "*" 

74 

75 @property 

76 def raw_text(self) -> str: 

77 return self._data["rawQuery"] 

78 

79 @property 

80 def text(self) -> str: 

81 return self._data["search"] 

82 

83 def __eq__(self, other: Any) -> bool: 

84 return ( 

85 isinstance(other, Query) 

86 and other.raw_text == self.raw_text 

87 and other.is_requery == self.is_requery 

88 ) 

89 

90 def __hash__(self) -> int: 

91 return hash(self.raw_text) 

92 

93 def __repr__(self) -> str: 

94 return f"<Query {self.raw_text=} {self.text=} {self.keyword=} {self.is_requery=} {self.condition_data=}>" 

95 

96 async def update_results(self, results: list[Result]) -> None: 

97 r"""|coro| 

98 

99 Tells flow to change the results shown to the user, using the query from this query object. 

100 

101 This method provides quick acess to :func:`flogin.flow.api.FlowLauncherAPI.update_results`. Because of that, this method will only take affect if the user has not changed the query. 

102 

103 Parameters 

104 ---------- 

105 results: list[:class:`~flogin.jsonrpc.results.Result`] 

106 The new results 

107 

108 Raises 

109 ------- 

110 :class:`~flogin.jsonrpc.errors.JsonRPCException` 

111 This is raised when an error happens with the JsonRPC pipe while attempting to call this API method. 

112 

113 Returns 

114 ------- 

115 ``None`` 

116 """ 

117 

118 return await self.plugin.api.update_results(self.raw_text, results) 

119 

120 async def update( 

121 self, 

122 *, 

123 text: str | None = MISSING, 

124 keyword: str | None = MISSING, 

125 requery: bool = False, 

126 ) -> None: 

127 r"""|coro| 

128 

129 Applies updates to the query with flow, and to this object. 

130 

131 This method provides quick acess to :func:`flogin.flow.api.FlowLauncherAPI.change_query` 

132 

133 Parameters 

134 ---------- 

135 text: Optional[:class:`str` | ``None``] 

136 The text that will be used with the query. 

137 

138 .. versionchanged:: 2.0.0 

139 ``text`` can now be ``None``, and is now optional 

140 keyword: Optional[:class:`str` | ``None``] 

141 The keyword that will be used with the query. Defaults to the pre-existing value of :attr:`Query.keyword`. Set this to ``None`` or ``*`` for no keyword to be used. 

142 requery: Optional[:class:`bool`] 

143 Whether or not to re-send a query request in the event that the new query is the same as the current query. Defaults to ``False`` 

144 

145 Raises 

146 ------- 

147 :class:`~flogin.jsonrpc.errors.JsonRPCException` 

148 This is raised when an error happens with the JsonRPC pipe while attempting to call this API method. 

149 

150 Returns 

151 -------- 

152 ``None`` 

153 """ 

154 

155 if keyword is not MISSING: 

156 self._data["actionKeyword"] = "*" if keyword is None else keyword 

157 

158 if text is not MISSING: 

159 self._data["search"] = text or "" 

160 

161 self._data["rawQuery"] = ( 

162 f"{'' if self.keyword == '*' else self.keyword} {self.text}".strip() 

163 ) 

164 

165 return await self.plugin.api.change_query(self.raw_text, requery=requery)