Coverage for flogin/flow/api.py: 49%

59 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, ParamSpec 

4 

5from .fuzzy_search import FuzzySearchResult 

6from .plugin_metadata import PluginMetadata 

7 

8ATS = ParamSpec("ATS") 

9 

10if TYPE_CHECKING: 

11 from ..jsonrpc import ExecuteResponse, JsonRPCClient, Result 

12 

13__all__ = ("FlowLauncherAPI",) 

14 

15 

16class FlowLauncherAPI: 

17 r"""This class is a wrapper around Flow's API to make it easy to make requests and receive results. 

18 

19 .. NOTE:: 

20 Do not initialize this class yourself, instead use :class:`~flogin.plugin.Plugin`'s :attr:`~flogin.plugin.Plugin.api` attribute to get an instance. 

21 """ 

22 

23 def __init__(self, jsonrpc: JsonRPCClient) -> None: 

24 self.jsonrpc = jsonrpc 

25 

26 async def __call__(self, method: str, *args: Any, **kwargs: Any) -> ExecuteResponse: 

27 from ..jsonrpc import ExecuteResponse 

28 

29 await getattr(self, method)(*args, **kwargs) 

30 return ExecuteResponse() 

31 

32 async def fuzzy_search( 

33 self, text: str, text_to_compare_it_to: str 

34 ) -> FuzzySearchResult: 

35 r"""|coro| 

36 

37 Asks flow how similiar two strings are. 

38 

39 Parameters 

40 -------- 

41 text: :class:`str` 

42 The text 

43 text_to_compare_it_to: :class:`str` 

44 The text you want to compare the other text to 

45 

46 Raises 

47 ------- 

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

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

50 

51 Returns 

52 -------- 

53 :class:`~flogin.flow.fuzzy_search.FuzzySearchResult` 

54 """ 

55 

56 res = await self.jsonrpc.request("FuzzySearch", [text, text_to_compare_it_to]) 

57 

58 return FuzzySearchResult(res["result"]) 

59 

60 async def change_query(self, new_query: str, requery: bool = False) -> None: 

61 r"""|coro| 

62 

63 Change the query in flow launcher's menu. 

64 

65 Parameters 

66 -------- 

67 new_query: :class:`str` 

68 The new query to change it to 

69 requery: :class:`bool` 

70 Whether or not to re-send a query request in the event that the `new_query` is the same as the current query 

71 

72 Raises 

73 ------- 

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

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

76 

77 Returns 

78 -------- 

79 None 

80 """ 

81 

82 await self.jsonrpc.request("ChangeQuery", [new_query, requery]) 

83 

84 async def show_error_message(self, title: str, text: str) -> None: 

85 r"""|coro| 

86 

87 Triggers an error message in the form of a windows notification 

88 

89 Parameters 

90 -------- 

91 title: :class:`str` 

92 The title of the notification 

93 text: :class:`str` 

94 The content of the notification 

95 

96 Raises 

97 ------- 

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

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

100 

101 Returns 

102 -------- 

103 None 

104 """ 

105 

106 await self.jsonrpc.request("ShowMsgError", [title, text]) 

107 

108 async def show_notification( 

109 self, 

110 title: str, 

111 content: str, 

112 icon: str = "", 

113 use_main_window_as_owner: bool = True, 

114 ) -> None: 

115 r"""|coro| 

116 

117 Creates a notification window in the bottom right hand of the user's screen 

118 

119 Parameters 

120 -------- 

121 title: :class:`str` 

122 The notification's title 

123 content: :class:`str` 

124 The notification's content 

125 icon: :class:`str` 

126 The icon to be shown with the notification, defaults to `""` 

127 use_main_window_as_owner: :class:`bool` 

128 Whether or not to use the main flow window as the notification's owner. Defaults to `True` 

129 

130 Raises 

131 ------- 

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

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

134 

135 Returns 

136 -------- 

137 None 

138 """ 

139 

140 await self.jsonrpc.request( 

141 "ShowMsg", [title, content, icon, use_main_window_as_owner] 

142 ) 

143 

144 async def open_settings_menu(self) -> None: 

145 r"""|coro| 

146 

147 This method tells flow to open up the settings menu. 

148 

149 Raises 

150 ------- 

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

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

153 

154 Returns 

155 -------- 

156 None 

157 """ 

158 

159 await self.jsonrpc.request("OpenSettingDialog") 

160 

161 async def open_url(self, url: str, in_private: bool = False) -> None: 

162 r"""|coro| 

163 

164 Open up a url in the user's preferred browser, which was set in their Flow Launcher settings. 

165 

166 Parameters 

167 -------- 

168 url: :class:`str` 

169 The url to be opened in the webbrowser 

170 in_private: :class:`bool` 

171 Whether or not to open up the url in a private window 

172 

173 Raises 

174 ------- 

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

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

177 

178 Returns 

179 -------- 

180 None 

181 """ 

182 

183 await self.jsonrpc.request("OpenUrl", [url, in_private]) 

184 

185 async def run_shell_cmd(self, cmd: str, filename: str = "cmd.exe") -> None: 

186 r"""|coro| 

187 

188 Tell flow to run a shell command 

189 

190 Parameters 

191 -------- 

192 cmd: :class:`str` 

193 The command to be run 

194 filename: :class:`str` 

195 The name of the command prompt instance, defaults to `cmd.exe` 

196 

197 Raises 

198 ------- 

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

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

201 

202 Returns 

203 -------- 

204 None 

205 """ 

206 

207 await self.jsonrpc.request("ShellRun", [cmd, filename]) 

208 

209 async def restart_flow_launcher(self) -> None: 

210 r"""|coro| 

211 

212 This method tells flow launcher to initiate a restart of flow launcher. 

213 

214 .. WARNING:: 

215 Expect this method to never finish, so clean up and prepare for the plugin to be shut down before calling this. 

216 

217 Raises 

218 ------- 

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

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

221 """ 

222 

223 await self.jsonrpc.request("RestartApp") 

224 

225 async def save_all_app_settings(self) -> None: 

226 r"""|coro| 

227 

228 This method tells flow to save all app settings. 

229 

230 Raises 

231 ------- 

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

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

234 

235 Returns 

236 -------- 

237 None 

238 """ 

239 

240 await self.jsonrpc.request("SaveAppAllSettings") 

241 

242 async def save_plugin_settings(self) -> Any: 

243 r"""|coro| 

244 

245 This method tells flow to save plugin settings 

246 

247 Raises 

248 ------- 

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

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

251 

252 Returns 

253 -------- 

254 None 

255 """ 

256 

257 res = await self.jsonrpc.request("SavePluginSettings") 

258 

259 return res["result"] 

260 

261 async def reload_all_plugin_data(self) -> None: 

262 r"""|coro| 

263 

264 This method tells flow to trigger a reload of all plugins. 

265 

266 Raises 

267 ------- 

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

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

270 

271 Returns 

272 -------- 

273 None 

274 """ 

275 

276 await self.jsonrpc.request("ReloadAllPluginDataAsync") 

277 

278 async def show_main_window(self) -> None: 

279 """|coro| 

280 

281 This method tells flow to show the main window 

282 

283 Raises 

284 ------- 

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

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

287 

288 Returns 

289 -------- 

290 None 

291 """ 

292 

293 await self.jsonrpc.request("ShowMainWindow") 

294 

295 async def hide_main_window(self) -> None: 

296 r"""|coro| 

297 

298 This method tells flow to hide the main window 

299 

300 Raises 

301 ------- 

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

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

304 

305 Returns 

306 -------- 

307 None 

308 """ 

309 

310 await self.jsonrpc.request("HideMainWindow") 

311 

312 async def is_main_window_visible(self) -> bool: 

313 r"""|coro| 

314 

315 This method asks flow if the main window is visible or not 

316 

317 Raises 

318 ------- 

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

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

321 

322 Returns 

323 -------- 

324 :class:`bool` 

325 """ 

326 

327 res = await self.jsonrpc.request("IsMainWindowVisible") 

328 

329 return res["result"] 

330 

331 async def check_for_updates(self) -> None: 

332 r"""|coro| 

333 

334 This tells flow launcher to check for updates to flow launcher 

335 

336 .. NOTE:: 

337 This tells flow launcher to check for updates to flow launcher, not your plugin 

338 

339 Raises 

340 ------- 

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

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

343 

344 Returns 

345 -------- 

346 None 

347 """ 

348 

349 await self.jsonrpc.request("CheckForNewUpdate") 

350 

351 async def get_all_plugins(self) -> list[PluginMetadata]: 

352 r"""|coro| 

353 

354 Get the metadata of all plugins that the user has installed 

355 

356 Raises 

357 ------- 

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

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

360 

361 Returns 

362 -------- 

363 list[:class:`~flogin.flow.plugin_metadata.PluginMetadata`] 

364 """ 

365 

366 res = await self.jsonrpc.request("GetAllPlugins") 

367 

368 return [PluginMetadata(plugin["metadata"], self) for plugin in res["result"]] 

369 

370 async def add_keyword(self, plugin_id: str, keyword: str) -> None: 

371 r"""|coro| 

372 

373 Registers a new keyword for a plugin with flow launcher. 

374 

375 Parameters 

376 -------- 

377 plugin_id: :class:`str` 

378 The id of the plugin that you want the keyword added to 

379 keyword: :class:`str` 

380 The keyword to add 

381 

382 Raises 

383 ------- 

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

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

386 

387 Returns 

388 -------- 

389 None 

390 """ 

391 

392 await self.jsonrpc.request("AddActionKeyword", [plugin_id, keyword]) 

393 

394 async def remove_keyword(self, plugin_id: str, keyword: str) -> None: 

395 r"""|coro| 

396 

397 Unregisters a keyword for a plugin with flow launcher. 

398 

399 Parameters 

400 -------- 

401 plugin_id: :class:`str` 

402 The ID of the plugin that you want to remove the keyword from 

403 keyword: :class:`str` 

404 The keyword that you want to remove 

405 

406 Raises 

407 ------- 

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

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

410 

411 Returns 

412 -------- 

413 None 

414 """ 

415 

416 await self.jsonrpc.request("RemoveActionKeyword", [plugin_id, keyword]) 

417 

418 async def open_directory(self, directory: str, file: str | None = None) -> None: 

419 r"""|coro| 

420 

421 Opens up a folder in file explorer. If a file is provided, the file will be pre-selected. 

422 

423 Parameters 

424 -------- 

425 directory: :class:`str` 

426 The directory you want to open 

427 file: Optional[:class:`str`] 

428 The file in the directory that you want to highlight, defaults to `None` 

429 

430 Raises 

431 ------- 

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

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

434 

435 Returns 

436 -------- 

437 None 

438 """ 

439 

440 await self.jsonrpc.request("OpenDirectory", [directory, file]) 

441 

442 async def update_results(self, raw_query: str, results: list[Result[Any]]) -> None: 

443 r"""|coro| 

444 

445 Tells flow to change the results shown to the user 

446 

447 .. NOTE:: 

448 The ``raw_query`` parameter is required by flow launcher, and must be the same as the current raw query in flow launcher for the results to successfully update. 

449 

450 Parameters 

451 ---------- 

452 raw_query: :class:`str` 

453 Only change the results if the current raw query is the same as this 

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

455 The new results 

456 

457 Raises 

458 ------- 

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

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

461 

462 Returns 

463 ------- 

464 None 

465 """ 

466 

467 from ..jsonrpc import QueryResponse # circular import 

468 

469 self.jsonrpc.plugin._results.update({res.slug: res for res in results}) 

470 

471 await self.jsonrpc.request( 

472 "UpdateResults", [raw_query, QueryResponse(results).to_dict()["result"]] 

473 )