flowtask 5.8.4__cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (470) hide show
  1. flowtask/__init__.py +93 -0
  2. flowtask/__main__.py +38 -0
  3. flowtask/bots/__init__.py +6 -0
  4. flowtask/bots/check.py +93 -0
  5. flowtask/bots/codebot.py +51 -0
  6. flowtask/components/ASPX.py +148 -0
  7. flowtask/components/AddDataset.py +352 -0
  8. flowtask/components/Amazon.py +523 -0
  9. flowtask/components/AutoTask.py +314 -0
  10. flowtask/components/Azure.py +80 -0
  11. flowtask/components/AzureUsers.py +106 -0
  12. flowtask/components/BaseAction.py +91 -0
  13. flowtask/components/BaseLoop.py +198 -0
  14. flowtask/components/BestBuy.py +800 -0
  15. flowtask/components/CSVToGCS.py +120 -0
  16. flowtask/components/CompanyScraper/__init__.py +1 -0
  17. flowtask/components/CompanyScraper/parsers/__init__.py +6 -0
  18. flowtask/components/CompanyScraper/parsers/base.py +102 -0
  19. flowtask/components/CompanyScraper/parsers/explorium.py +192 -0
  20. flowtask/components/CompanyScraper/parsers/leadiq.py +206 -0
  21. flowtask/components/CompanyScraper/parsers/rocket.py +133 -0
  22. flowtask/components/CompanyScraper/parsers/siccode.py +109 -0
  23. flowtask/components/CompanyScraper/parsers/visualvisitor.py +130 -0
  24. flowtask/components/CompanyScraper/parsers/zoominfo.py +118 -0
  25. flowtask/components/CompanyScraper/scrapper.py +1054 -0
  26. flowtask/components/CopyTo.py +177 -0
  27. flowtask/components/CopyToBigQuery.py +243 -0
  28. flowtask/components/CopyToMongoDB.py +291 -0
  29. flowtask/components/CopyToPg.py +609 -0
  30. flowtask/components/CopyToRethink.py +207 -0
  31. flowtask/components/CreateGCSBucket.py +102 -0
  32. flowtask/components/CreateReport/CreateReport.py +228 -0
  33. flowtask/components/CreateReport/__init__.py +9 -0
  34. flowtask/components/CreateReport/charts/__init__.py +15 -0
  35. flowtask/components/CreateReport/charts/bar.py +51 -0
  36. flowtask/components/CreateReport/charts/base.py +66 -0
  37. flowtask/components/CreateReport/charts/pie.py +64 -0
  38. flowtask/components/CreateReport/utils.py +9 -0
  39. flowtask/components/CustomerSatisfaction.py +196 -0
  40. flowtask/components/DataInput.py +200 -0
  41. flowtask/components/DateList.py +255 -0
  42. flowtask/components/DbClient.py +163 -0
  43. flowtask/components/DialPad.py +146 -0
  44. flowtask/components/DocumentDBQuery.py +200 -0
  45. flowtask/components/DownloadFrom.py +371 -0
  46. flowtask/components/DownloadFromD2L.py +113 -0
  47. flowtask/components/DownloadFromFTP.py +181 -0
  48. flowtask/components/DownloadFromIMAP.py +315 -0
  49. flowtask/components/DownloadFromS3.py +198 -0
  50. flowtask/components/DownloadFromSFTP.py +265 -0
  51. flowtask/components/DownloadFromSharepoint.py +110 -0
  52. flowtask/components/DownloadFromSmartSheet.py +114 -0
  53. flowtask/components/DownloadS3File.py +229 -0
  54. flowtask/components/Dummy.py +59 -0
  55. flowtask/components/DuplicatePhoto.py +411 -0
  56. flowtask/components/EmployeeEvaluation.py +237 -0
  57. flowtask/components/ExecuteSQL.py +323 -0
  58. flowtask/components/ExtractHTML.py +178 -0
  59. flowtask/components/FileBase.py +178 -0
  60. flowtask/components/FileCopy.py +181 -0
  61. flowtask/components/FileDelete.py +82 -0
  62. flowtask/components/FileExists.py +146 -0
  63. flowtask/components/FileIteratorDelete.py +112 -0
  64. flowtask/components/FileList.py +194 -0
  65. flowtask/components/FileOpen.py +75 -0
  66. flowtask/components/FileRead.py +120 -0
  67. flowtask/components/FileRename.py +106 -0
  68. flowtask/components/FilterIf.py +284 -0
  69. flowtask/components/FilterRows/FilterRows.py +200 -0
  70. flowtask/components/FilterRows/__init__.py +10 -0
  71. flowtask/components/FilterRows/functions.py +4 -0
  72. flowtask/components/GCSToBigQuery.py +103 -0
  73. flowtask/components/GoogleA4.py +150 -0
  74. flowtask/components/GoogleGeoCoding.py +344 -0
  75. flowtask/components/GooglePlaces.py +315 -0
  76. flowtask/components/GoogleSearch.py +539 -0
  77. flowtask/components/HTTPClient.py +268 -0
  78. flowtask/components/ICIMS.py +146 -0
  79. flowtask/components/IF.py +179 -0
  80. flowtask/components/IcimsFolderCopy.py +173 -0
  81. flowtask/components/ImageFeatures/__init__.py +5 -0
  82. flowtask/components/ImageFeatures/process.py +233 -0
  83. flowtask/components/IteratorBase.py +251 -0
  84. flowtask/components/LangchainLoader/__init__.py +5 -0
  85. flowtask/components/LangchainLoader/loader.py +194 -0
  86. flowtask/components/LangchainLoader/loaders/__init__.py +22 -0
  87. flowtask/components/LangchainLoader/loaders/abstract.py +362 -0
  88. flowtask/components/LangchainLoader/loaders/basepdf.py +50 -0
  89. flowtask/components/LangchainLoader/loaders/docx.py +91 -0
  90. flowtask/components/LangchainLoader/loaders/html.py +119 -0
  91. flowtask/components/LangchainLoader/loaders/pdfblocks.py +146 -0
  92. flowtask/components/LangchainLoader/loaders/pdfmark.py +79 -0
  93. flowtask/components/LangchainLoader/loaders/pdftables.py +135 -0
  94. flowtask/components/LangchainLoader/loaders/qa.py +67 -0
  95. flowtask/components/LangchainLoader/loaders/txt.py +55 -0
  96. flowtask/components/LeadIQ.py +650 -0
  97. flowtask/components/Loop.py +253 -0
  98. flowtask/components/Lowes.py +334 -0
  99. flowtask/components/MS365Usage.py +156 -0
  100. flowtask/components/MSTeamsMessages.py +320 -0
  101. flowtask/components/MarketClustering.py +1051 -0
  102. flowtask/components/MergeFiles.py +362 -0
  103. flowtask/components/MilvusOutput.py +87 -0
  104. flowtask/components/NearByStores.py +175 -0
  105. flowtask/components/NetworkNinja/__init__.py +6 -0
  106. flowtask/components/NetworkNinja/models/__init__.py +52 -0
  107. flowtask/components/NetworkNinja/models/abstract.py +177 -0
  108. flowtask/components/NetworkNinja/models/account.py +39 -0
  109. flowtask/components/NetworkNinja/models/client.py +19 -0
  110. flowtask/components/NetworkNinja/models/district.py +14 -0
  111. flowtask/components/NetworkNinja/models/events.py +101 -0
  112. flowtask/components/NetworkNinja/models/forms.py +499 -0
  113. flowtask/components/NetworkNinja/models/market.py +16 -0
  114. flowtask/components/NetworkNinja/models/organization.py +34 -0
  115. flowtask/components/NetworkNinja/models/photos.py +125 -0
  116. flowtask/components/NetworkNinja/models/project.py +44 -0
  117. flowtask/components/NetworkNinja/models/region.py +28 -0
  118. flowtask/components/NetworkNinja/models/store.py +203 -0
  119. flowtask/components/NetworkNinja/models/user.py +151 -0
  120. flowtask/components/NetworkNinja/router.py +854 -0
  121. flowtask/components/Odoo.py +175 -0
  122. flowtask/components/OdooInjector.py +192 -0
  123. flowtask/components/OpenFromXML.py +126 -0
  124. flowtask/components/OpenWeather.py +41 -0
  125. flowtask/components/OpenWithBase.py +616 -0
  126. flowtask/components/OpenWithPandas.py +715 -0
  127. flowtask/components/PGPDecrypt.py +199 -0
  128. flowtask/components/PandasIterator.py +187 -0
  129. flowtask/components/PandasToFile.py +189 -0
  130. flowtask/components/Paradox.py +339 -0
  131. flowtask/components/ParamIterator.py +117 -0
  132. flowtask/components/ParseHTML.py +84 -0
  133. flowtask/components/PlacerStores.py +249 -0
  134. flowtask/components/Pokemon.py +507 -0
  135. flowtask/components/PositiveBot.py +62 -0
  136. flowtask/components/PowerPointSlide.py +400 -0
  137. flowtask/components/PrintMessage.py +127 -0
  138. flowtask/components/ProductCompetitors/__init__.py +5 -0
  139. flowtask/components/ProductCompetitors/parsers/__init__.py +7 -0
  140. flowtask/components/ProductCompetitors/parsers/base.py +72 -0
  141. flowtask/components/ProductCompetitors/parsers/bestbuy.py +86 -0
  142. flowtask/components/ProductCompetitors/parsers/lowes.py +103 -0
  143. flowtask/components/ProductCompetitors/scrapper.py +155 -0
  144. flowtask/components/ProductCompliant.py +169 -0
  145. flowtask/components/ProductInfo/__init__.py +1 -0
  146. flowtask/components/ProductInfo/parsers/__init__.py +5 -0
  147. flowtask/components/ProductInfo/parsers/base.py +83 -0
  148. flowtask/components/ProductInfo/parsers/brother.py +97 -0
  149. flowtask/components/ProductInfo/parsers/canon.py +167 -0
  150. flowtask/components/ProductInfo/parsers/epson.py +118 -0
  151. flowtask/components/ProductInfo/parsers/hp.py +131 -0
  152. flowtask/components/ProductInfo/parsers/samsung.py +97 -0
  153. flowtask/components/ProductInfo/scraper.py +319 -0
  154. flowtask/components/ProductPricing.py +118 -0
  155. flowtask/components/QS.py +261 -0
  156. flowtask/components/QSBase.py +201 -0
  157. flowtask/components/QueryIterator.py +273 -0
  158. flowtask/components/QueryToInsert.py +327 -0
  159. flowtask/components/QueryToPandas.py +432 -0
  160. flowtask/components/RESTClient.py +195 -0
  161. flowtask/components/RethinkDBQuery.py +189 -0
  162. flowtask/components/Rsync.py +74 -0
  163. flowtask/components/RunSSH.py +59 -0
  164. flowtask/components/RunShell.py +71 -0
  165. flowtask/components/SalesForce.py +20 -0
  166. flowtask/components/SaveImageBank/__init__.py +257 -0
  167. flowtask/components/SchedulingVisits.py +592 -0
  168. flowtask/components/ScrapPage.py +216 -0
  169. flowtask/components/ScrapSearch.py +79 -0
  170. flowtask/components/SendNotify.py +257 -0
  171. flowtask/components/SentimentAnalysis.py +694 -0
  172. flowtask/components/ServiceScrapper/__init__.py +5 -0
  173. flowtask/components/ServiceScrapper/parsers/__init__.py +1 -0
  174. flowtask/components/ServiceScrapper/parsers/base.py +94 -0
  175. flowtask/components/ServiceScrapper/parsers/costco.py +93 -0
  176. flowtask/components/ServiceScrapper/scrapper.py +199 -0
  177. flowtask/components/SetVariables.py +156 -0
  178. flowtask/components/SubTask.py +182 -0
  179. flowtask/components/SuiteCRM.py +48 -0
  180. flowtask/components/Switch.py +175 -0
  181. flowtask/components/TableBase.py +148 -0
  182. flowtask/components/TableDelete.py +312 -0
  183. flowtask/components/TableInput.py +143 -0
  184. flowtask/components/TableOutput/TableOutput.py +384 -0
  185. flowtask/components/TableOutput/__init__.py +3 -0
  186. flowtask/components/TableSchema.py +534 -0
  187. flowtask/components/Target.py +223 -0
  188. flowtask/components/ThumbnailGenerator.py +156 -0
  189. flowtask/components/ToPandas.py +67 -0
  190. flowtask/components/TransformRows/TransformRows.py +507 -0
  191. flowtask/components/TransformRows/__init__.py +9 -0
  192. flowtask/components/TransformRows/functions.py +559 -0
  193. flowtask/components/TransposeRows.py +176 -0
  194. flowtask/components/UPCDatabase.py +86 -0
  195. flowtask/components/UnGzip.py +171 -0
  196. flowtask/components/Uncompress.py +172 -0
  197. flowtask/components/UniqueRows.py +126 -0
  198. flowtask/components/Unzip.py +107 -0
  199. flowtask/components/UpdateOperationalVars.py +147 -0
  200. flowtask/components/UploadTo.py +299 -0
  201. flowtask/components/UploadToS3.py +136 -0
  202. flowtask/components/UploadToSFTP.py +160 -0
  203. flowtask/components/UploadToSharepoint.py +205 -0
  204. flowtask/components/UserFunc.py +122 -0
  205. flowtask/components/VivaTracker.py +140 -0
  206. flowtask/components/WSDLClient.py +123 -0
  207. flowtask/components/Wait.py +18 -0
  208. flowtask/components/Walmart.py +199 -0
  209. flowtask/components/Workplace.py +134 -0
  210. flowtask/components/XMLToPandas.py +267 -0
  211. flowtask/components/Zammad/__init__.py +41 -0
  212. flowtask/components/Zammad/models.py +0 -0
  213. flowtask/components/ZoomInfoScraper.py +409 -0
  214. flowtask/components/__init__.py +104 -0
  215. flowtask/components/abstract.py +18 -0
  216. flowtask/components/flow.py +530 -0
  217. flowtask/components/google.py +335 -0
  218. flowtask/components/group.py +221 -0
  219. flowtask/components/py.typed +0 -0
  220. flowtask/components/reviewscrap.py +132 -0
  221. flowtask/components/tAutoincrement.py +117 -0
  222. flowtask/components/tConcat.py +109 -0
  223. flowtask/components/tExplode.py +119 -0
  224. flowtask/components/tFilter.py +184 -0
  225. flowtask/components/tGroup.py +236 -0
  226. flowtask/components/tJoin.py +270 -0
  227. flowtask/components/tMap/__init__.py +9 -0
  228. flowtask/components/tMap/functions.py +54 -0
  229. flowtask/components/tMap/tMap.py +450 -0
  230. flowtask/components/tMelt.py +112 -0
  231. flowtask/components/tMerge.py +114 -0
  232. flowtask/components/tOrder.py +93 -0
  233. flowtask/components/tPandas.py +94 -0
  234. flowtask/components/tPivot.py +71 -0
  235. flowtask/components/tPluckCols.py +76 -0
  236. flowtask/components/tUnnest.py +82 -0
  237. flowtask/components/user.py +401 -0
  238. flowtask/conf.py +457 -0
  239. flowtask/download.py +102 -0
  240. flowtask/events/__init__.py +11 -0
  241. flowtask/events/events/__init__.py +20 -0
  242. flowtask/events/events/abstract.py +95 -0
  243. flowtask/events/events/alerts/__init__.py +362 -0
  244. flowtask/events/events/alerts/colfunctions.py +131 -0
  245. flowtask/events/events/alerts/functions.py +158 -0
  246. flowtask/events/events/dummy.py +12 -0
  247. flowtask/events/events/exec.py +124 -0
  248. flowtask/events/events/file/__init__.py +7 -0
  249. flowtask/events/events/file/base.py +51 -0
  250. flowtask/events/events/file/copy.py +23 -0
  251. flowtask/events/events/file/delete.py +16 -0
  252. flowtask/events/events/interfaces/__init__.py +9 -0
  253. flowtask/events/events/interfaces/client.py +67 -0
  254. flowtask/events/events/interfaces/credentials.py +28 -0
  255. flowtask/events/events/interfaces/notifications.py +58 -0
  256. flowtask/events/events/jira.py +122 -0
  257. flowtask/events/events/log.py +26 -0
  258. flowtask/events/events/logerr.py +52 -0
  259. flowtask/events/events/notify.py +59 -0
  260. flowtask/events/events/notify_event.py +160 -0
  261. flowtask/events/events/publish.py +54 -0
  262. flowtask/events/events/sendfile.py +104 -0
  263. flowtask/events/events/task.py +97 -0
  264. flowtask/events/events/teams.py +98 -0
  265. flowtask/events/events/webhook.py +58 -0
  266. flowtask/events/manager.py +287 -0
  267. flowtask/exceptions.c +39393 -0
  268. flowtask/exceptions.cpython-310-x86_64-linux-gnu.so +0 -0
  269. flowtask/extensions/__init__.py +3 -0
  270. flowtask/extensions/abstract.py +82 -0
  271. flowtask/extensions/logging/__init__.py +65 -0
  272. flowtask/hooks/__init__.py +9 -0
  273. flowtask/hooks/actions/__init__.py +22 -0
  274. flowtask/hooks/actions/abstract.py +66 -0
  275. flowtask/hooks/actions/dummy.py +23 -0
  276. flowtask/hooks/actions/jira.py +74 -0
  277. flowtask/hooks/actions/rest.py +320 -0
  278. flowtask/hooks/actions/sampledata.py +37 -0
  279. flowtask/hooks/actions/sensor.py +23 -0
  280. flowtask/hooks/actions/task.py +9 -0
  281. flowtask/hooks/actions/ticket.py +37 -0
  282. flowtask/hooks/actions/zammad.py +55 -0
  283. flowtask/hooks/hook.py +62 -0
  284. flowtask/hooks/models.py +17 -0
  285. flowtask/hooks/service.py +187 -0
  286. flowtask/hooks/step.py +91 -0
  287. flowtask/hooks/types/__init__.py +23 -0
  288. flowtask/hooks/types/base.py +129 -0
  289. flowtask/hooks/types/brokers/__init__.py +11 -0
  290. flowtask/hooks/types/brokers/base.py +54 -0
  291. flowtask/hooks/types/brokers/mqtt.py +35 -0
  292. flowtask/hooks/types/brokers/rabbitmq.py +82 -0
  293. flowtask/hooks/types/brokers/redis.py +83 -0
  294. flowtask/hooks/types/brokers/sqs.py +44 -0
  295. flowtask/hooks/types/fs.py +232 -0
  296. flowtask/hooks/types/http.py +49 -0
  297. flowtask/hooks/types/imap.py +200 -0
  298. flowtask/hooks/types/jira.py +279 -0
  299. flowtask/hooks/types/mail.py +205 -0
  300. flowtask/hooks/types/postgres.py +98 -0
  301. flowtask/hooks/types/responses/__init__.py +8 -0
  302. flowtask/hooks/types/responses/base.py +5 -0
  303. flowtask/hooks/types/sharepoint.py +288 -0
  304. flowtask/hooks/types/ssh.py +141 -0
  305. flowtask/hooks/types/tagged.py +59 -0
  306. flowtask/hooks/types/upload.py +85 -0
  307. flowtask/hooks/types/watch.py +71 -0
  308. flowtask/hooks/types/web.py +36 -0
  309. flowtask/interfaces/AzureClient.py +137 -0
  310. flowtask/interfaces/AzureGraph.py +839 -0
  311. flowtask/interfaces/Boto3Client.py +326 -0
  312. flowtask/interfaces/DropboxClient.py +173 -0
  313. flowtask/interfaces/ExcelHandler.py +94 -0
  314. flowtask/interfaces/FTPClient.py +131 -0
  315. flowtask/interfaces/GoogleCalendar.py +201 -0
  316. flowtask/interfaces/GoogleClient.py +133 -0
  317. flowtask/interfaces/GoogleDrive.py +127 -0
  318. flowtask/interfaces/GoogleGCS.py +89 -0
  319. flowtask/interfaces/GoogleGeocoding.py +93 -0
  320. flowtask/interfaces/GoogleLang.py +114 -0
  321. flowtask/interfaces/GooglePub.py +61 -0
  322. flowtask/interfaces/GoogleSheet.py +68 -0
  323. flowtask/interfaces/IMAPClient.py +137 -0
  324. flowtask/interfaces/O365Calendar.py +113 -0
  325. flowtask/interfaces/O365Client.py +220 -0
  326. flowtask/interfaces/OneDrive.py +284 -0
  327. flowtask/interfaces/Outlook.py +155 -0
  328. flowtask/interfaces/ParrotBot.py +130 -0
  329. flowtask/interfaces/SSHClient.py +378 -0
  330. flowtask/interfaces/Sharepoint.py +496 -0
  331. flowtask/interfaces/__init__.py +36 -0
  332. flowtask/interfaces/azureauth.py +119 -0
  333. flowtask/interfaces/cache.py +201 -0
  334. flowtask/interfaces/client.py +82 -0
  335. flowtask/interfaces/compress.py +525 -0
  336. flowtask/interfaces/credentials.py +124 -0
  337. flowtask/interfaces/d2l.py +239 -0
  338. flowtask/interfaces/databases/__init__.py +5 -0
  339. flowtask/interfaces/databases/db.py +223 -0
  340. flowtask/interfaces/databases/documentdb.py +55 -0
  341. flowtask/interfaces/databases/rethink.py +39 -0
  342. flowtask/interfaces/dataframes/__init__.py +11 -0
  343. flowtask/interfaces/dataframes/abstract.py +21 -0
  344. flowtask/interfaces/dataframes/arrow.py +71 -0
  345. flowtask/interfaces/dataframes/dt.py +69 -0
  346. flowtask/interfaces/dataframes/pandas.py +167 -0
  347. flowtask/interfaces/dataframes/polars.py +60 -0
  348. flowtask/interfaces/db.py +263 -0
  349. flowtask/interfaces/env.py +46 -0
  350. flowtask/interfaces/func.py +137 -0
  351. flowtask/interfaces/http.py +1780 -0
  352. flowtask/interfaces/locale.py +40 -0
  353. flowtask/interfaces/log.py +75 -0
  354. flowtask/interfaces/mask.py +143 -0
  355. flowtask/interfaces/notification.py +154 -0
  356. flowtask/interfaces/playwright.py +339 -0
  357. flowtask/interfaces/powerpoint.py +368 -0
  358. flowtask/interfaces/py.typed +0 -0
  359. flowtask/interfaces/qs.py +376 -0
  360. flowtask/interfaces/result.py +87 -0
  361. flowtask/interfaces/selenium_service.py +779 -0
  362. flowtask/interfaces/smartsheet.py +154 -0
  363. flowtask/interfaces/stat.py +39 -0
  364. flowtask/interfaces/task.py +96 -0
  365. flowtask/interfaces/template.py +118 -0
  366. flowtask/interfaces/vectorstores/__init__.py +1 -0
  367. flowtask/interfaces/vectorstores/abstract.py +133 -0
  368. flowtask/interfaces/vectorstores/milvus.py +669 -0
  369. flowtask/interfaces/zammad.py +107 -0
  370. flowtask/models.py +193 -0
  371. flowtask/parsers/__init__.py +15 -0
  372. flowtask/parsers/_yaml.c +11978 -0
  373. flowtask/parsers/_yaml.cpython-310-x86_64-linux-gnu.so +0 -0
  374. flowtask/parsers/argparser.py +235 -0
  375. flowtask/parsers/base.c +15155 -0
  376. flowtask/parsers/base.cpython-310-x86_64-linux-gnu.so +0 -0
  377. flowtask/parsers/json.c +11968 -0
  378. flowtask/parsers/json.cpython-310-x86_64-linux-gnu.so +0 -0
  379. flowtask/parsers/maps.py +49 -0
  380. flowtask/parsers/toml.c +11968 -0
  381. flowtask/parsers/toml.cpython-310-x86_64-linux-gnu.so +0 -0
  382. flowtask/plugins/__init__.py +16 -0
  383. flowtask/plugins/components/__init__.py +0 -0
  384. flowtask/plugins/handler/__init__.py +45 -0
  385. flowtask/plugins/importer.py +31 -0
  386. flowtask/plugins/sources/__init__.py +0 -0
  387. flowtask/runner.py +283 -0
  388. flowtask/scheduler/__init__.py +9 -0
  389. flowtask/scheduler/functions.py +493 -0
  390. flowtask/scheduler/handlers/__init__.py +8 -0
  391. flowtask/scheduler/handlers/manager.py +504 -0
  392. flowtask/scheduler/handlers/models.py +58 -0
  393. flowtask/scheduler/handlers/service.py +72 -0
  394. flowtask/scheduler/notifications.py +65 -0
  395. flowtask/scheduler/scheduler.py +993 -0
  396. flowtask/services/__init__.py +0 -0
  397. flowtask/services/bots/__init__.py +0 -0
  398. flowtask/services/bots/telegram.py +264 -0
  399. flowtask/services/files/__init__.py +11 -0
  400. flowtask/services/files/manager.py +522 -0
  401. flowtask/services/files/model.py +37 -0
  402. flowtask/services/files/service.py +767 -0
  403. flowtask/services/jira/__init__.py +3 -0
  404. flowtask/services/jira/jira_actions.py +191 -0
  405. flowtask/services/tasks/__init__.py +13 -0
  406. flowtask/services/tasks/launcher.py +213 -0
  407. flowtask/services/tasks/manager.py +323 -0
  408. flowtask/services/tasks/service.py +275 -0
  409. flowtask/services/tasks/task_manager.py +376 -0
  410. flowtask/services/tasks/tasks.py +155 -0
  411. flowtask/storages/__init__.py +16 -0
  412. flowtask/storages/exceptions.py +12 -0
  413. flowtask/storages/files/__init__.py +8 -0
  414. flowtask/storages/files/abstract.py +29 -0
  415. flowtask/storages/files/filesystem.py +66 -0
  416. flowtask/storages/tasks/__init__.py +19 -0
  417. flowtask/storages/tasks/abstract.py +26 -0
  418. flowtask/storages/tasks/database.py +33 -0
  419. flowtask/storages/tasks/filesystem.py +108 -0
  420. flowtask/storages/tasks/github.py +119 -0
  421. flowtask/storages/tasks/memory.py +45 -0
  422. flowtask/storages/tasks/row.py +25 -0
  423. flowtask/tasks/__init__.py +0 -0
  424. flowtask/tasks/abstract.py +526 -0
  425. flowtask/tasks/command.py +118 -0
  426. flowtask/tasks/pile.py +486 -0
  427. flowtask/tasks/py.typed +0 -0
  428. flowtask/tasks/task.py +778 -0
  429. flowtask/template/__init__.py +161 -0
  430. flowtask/tests.py +257 -0
  431. flowtask/types/__init__.py +8 -0
  432. flowtask/types/typedefs.c +11347 -0
  433. flowtask/types/typedefs.cpython-310-x86_64-linux-gnu.so +0 -0
  434. flowtask/utils/__init__.py +24 -0
  435. flowtask/utils/constants.py +117 -0
  436. flowtask/utils/encoders.py +21 -0
  437. flowtask/utils/executor.py +112 -0
  438. flowtask/utils/functions.cpp +14280 -0
  439. flowtask/utils/functions.cpython-310-x86_64-linux-gnu.so +0 -0
  440. flowtask/utils/json.cpp +13349 -0
  441. flowtask/utils/json.cpython-310-x86_64-linux-gnu.so +0 -0
  442. flowtask/utils/mail.py +63 -0
  443. flowtask/utils/parseqs.c +13324 -0
  444. flowtask/utils/parserqs.cpython-310-x86_64-linux-gnu.so +0 -0
  445. flowtask/utils/stats.py +308 -0
  446. flowtask/utils/transformations.py +74 -0
  447. flowtask/utils/uv.py +12 -0
  448. flowtask/utils/validators.py +97 -0
  449. flowtask/version.py +11 -0
  450. flowtask-5.8.4.dist-info/LICENSE +201 -0
  451. flowtask-5.8.4.dist-info/METADATA +209 -0
  452. flowtask-5.8.4.dist-info/RECORD +470 -0
  453. flowtask-5.8.4.dist-info/WHEEL +6 -0
  454. flowtask-5.8.4.dist-info/entry_points.txt +3 -0
  455. flowtask-5.8.4.dist-info/top_level.txt +2 -0
  456. plugins/components/CreateQR.py +39 -0
  457. plugins/components/TestComponent.py +28 -0
  458. plugins/components/Use1.py +13 -0
  459. plugins/components/Workplace.py +117 -0
  460. plugins/components/__init__.py +3 -0
  461. plugins/sources/__init__.py +0 -0
  462. plugins/sources/get_populartimes.py +78 -0
  463. plugins/sources/google.py +150 -0
  464. plugins/sources/hubspot.py +679 -0
  465. plugins/sources/icims.py +679 -0
  466. plugins/sources/mobileinsight.py +501 -0
  467. plugins/sources/newrelic.py +262 -0
  468. plugins/sources/uap.py +268 -0
  469. plugins/sources/venu.py +244 -0
  470. plugins/sources/vocinity.py +314 -0
@@ -0,0 +1,54 @@
1
+ import asyncio
2
+ from typing import Optional, Any
3
+ from aiohttp import web
4
+ from abc import abstractmethod
5
+ from ..base import BaseTrigger
6
+
7
+ class BaseMQTrigger(BaseTrigger):
8
+ def __init__(self, *args, actions: list = None, **kwargs):
9
+ super().__init__(*args, actions=actions, **kwargs)
10
+ self.consumer_task: Optional[asyncio.Task] = None
11
+ self._connection = None # To be set in subclass
12
+ self._queue_name = kwargs.get('queue_name', 'default_queue')
13
+
14
+ @abstractmethod
15
+ async def connect(self):
16
+ """Establish the connection."""
17
+ pass
18
+
19
+ @abstractmethod
20
+ async def disconnect(self):
21
+ """Disconnect the connection."""
22
+ pass
23
+
24
+ async def on_startup(self, app):
25
+ self._logger.info(
26
+ f"Starting MQ Broker {self.__class__.__name__}"
27
+ )
28
+ await self.connect()
29
+ self.consumer_task = asyncio.create_task(self.start_consuming())
30
+
31
+ async def on_shutdown(self, app):
32
+ self._logger.info(
33
+ f"Shutting down MQ Broker {self.__class__.__name__}"
34
+ )
35
+ if self.consumer_task:
36
+ self.consumer_task.cancel()
37
+ try:
38
+ await self.consumer_task
39
+ except asyncio.CancelledError:
40
+ self._logger.info("Consumer task cancelled.")
41
+ self.consumer_task = None
42
+ await self.disconnect()
43
+
44
+ @abstractmethod
45
+ async def start_consuming(self):
46
+ """Start consuming messages."""
47
+ pass
48
+
49
+ def setup(self, app: web.Application):
50
+ super().setup(app)
51
+
52
+ @abstractmethod
53
+ async def _consumer_callback(self, *args, **kwargs) -> None:
54
+ pass
@@ -0,0 +1,35 @@
1
+ import asyncio
2
+ from gmqtt import Client as MQTTClient
3
+ from ..base import BaseTrigger
4
+
5
+ class MQTTTrigger(BaseTrigger):
6
+ def __init__(self, *args, broker_url: str, topics: list, **kwargs):
7
+ super().__init__(*args, **kwargs)
8
+ self.broker_url = broker_url
9
+ self.topics = topics
10
+ self.client = MQTTClient(client_id='')
11
+ self.client.on_message = self.on_message
12
+ self.client.on_connect = self.on_connect
13
+ self.client.on_disconnect = self.on_disconnect
14
+
15
+ async def on_startup(self, app):
16
+ self._logger.info(f"Connecting to MQTT broker at {self.broker_url}")
17
+ await self.client.connect(self.broker_url)
18
+
19
+ async def on_shutdown(self, app):
20
+ self._logger.info("Disconnecting from MQTT broker")
21
+ await self.client.disconnect()
22
+
23
+ def on_connect(self, client, flags, rc, properties):
24
+ self._logger.info("Connected to MQTT broker")
25
+ for topic in self.topics:
26
+ client.subscribe(topic)
27
+ self._logger.info(f"Subscribed to topic: {topic}")
28
+
29
+ def on_disconnect(self, client, packet, exc=None):
30
+ self._logger.warning("Disconnected from MQTT broker")
31
+ # Implement reconnection logic if needed
32
+
33
+ def on_message(self, client, topic, payload, qos, properties):
34
+ self._logger.info(f"Received message on topic {topic}: {payload}")
35
+ asyncio.create_task(self.run_actions(topic=topic, payload=payload))
@@ -0,0 +1,82 @@
1
+ from typing import Optional, Any
2
+ import aiormq
3
+ from navigator.brokers.rabbitmq import RabbitMQConnection
4
+ from .base import BaseMQTrigger
5
+
6
+
7
+ class RabbitMQTrigger(BaseMQTrigger):
8
+ def __init__(
9
+ self,
10
+ *args,
11
+ queue_name: str,
12
+ routing_key: str = '',
13
+ exchange_name: str = '',
14
+ exchange_type: str = 'topic',
15
+ credentials: Optional[str] = None,
16
+ actions: list = None,
17
+ **kwargs
18
+ ):
19
+ super().__init__(
20
+ *args,
21
+ actions=actions,
22
+ queue_name=queue_name,
23
+ **kwargs
24
+ )
25
+ self._queue_name = queue_name
26
+ self._routing_key = routing_key
27
+ self._exchange_name = exchange_name
28
+ self._exchange_type = exchange_type
29
+ self._connection = RabbitMQConnection(
30
+ credentials=credentials
31
+ )
32
+ self.prefetch_count = kwargs.get('prefetch_count', 1)
33
+
34
+ async def connect(self):
35
+ await self._connection.connect()
36
+ self._logger.info("RabbitMQ connection established.")
37
+ # Ensure the exchange exists
38
+ await self._connection.ensure_exchange(
39
+ exchange_name=self._exchange_name or self._queue_name,
40
+ exchange_type=self._exchange_type
41
+ )
42
+ # Ensure the queue exists and bind it to the exchange
43
+ await self._connection.ensure_queue(
44
+ queue_name=self._queue_name,
45
+ exchange_name=self._exchange_name or self._queue_name,
46
+ routing_key=self._routing_key
47
+ )
48
+
49
+ async def disconnect(self):
50
+ await self._connection.disconnect()
51
+ self._logger.info("RabbitMQ connection closed.")
52
+
53
+ async def start_consuming(self):
54
+ await self._connection.consume_messages(
55
+ queue_name=self._queue_name,
56
+ callback=self._consumer_callback,
57
+ prefetch_count=self.prefetch_count
58
+ )
59
+
60
+ async def _consumer_callback(
61
+ self,
62
+ message: aiormq.abc.DeliveredMessage,
63
+ body: Any
64
+ ) -> None:
65
+ """
66
+ Callback from Consumer.
67
+
68
+ Used to call actions based on consumer messages received.
69
+ """
70
+ try:
71
+ message_id = message.delivery_tag
72
+ self._logger.info(f"Received Message ID: {message_id} Body: {body}")
73
+ # Call run_actions with the received message
74
+ await self.run_actions(
75
+ message_id=message_id,
76
+ payload=message,
77
+ message=body
78
+ )
79
+ except Exception as e:
80
+ self._logger.error(f"Error in _consumer_callback: {e}")
81
+ # Handle message rejection or requeueing if necessary
82
+ await self._connection.reject_message(message, requeue=False)
@@ -0,0 +1,83 @@
1
+ from typing import Optional, Any
2
+ from navigator.brokers.redis import RedisConnection
3
+ from .base import BaseMQTrigger
4
+
5
+
6
+ class RedisTrigger(BaseMQTrigger):
7
+ """Redis Trigger.
8
+
9
+ Trigger that listens to a Redis Stream and calls actions based on the received messages.
10
+ """
11
+ def __init__(
12
+ self,
13
+ *args,
14
+ stream_name: str,
15
+ group_name: str = 'default_group',
16
+ consumer_name: str = 'default_consumer',
17
+ credentials: Optional[dict] = None,
18
+ actions: list = None,
19
+ **kwargs
20
+ ):
21
+ super().__init__(
22
+ *args,
23
+ actions=actions,
24
+ queue_name=stream_name,
25
+ **kwargs
26
+ )
27
+ self._stream_name = stream_name
28
+ self._group_name = group_name
29
+ self._consumer_name = consumer_name
30
+ self._connection = RedisConnection(
31
+ credentials=credentials,
32
+ group_name=group_name,
33
+ consumer_name=consumer_name,
34
+ queue_name=stream_name
35
+ )
36
+ self.count = kwargs.get('count', 1)
37
+ self.block = kwargs.get('block', 1000)
38
+
39
+ async def connect(self):
40
+ await self._connection.connect()
41
+ self._logger.info(
42
+ "Redis connection established."
43
+ )
44
+
45
+ async def disconnect(self):
46
+ await self._connection.disconnect()
47
+ self._logger.info(
48
+ "Redis connection closed."
49
+ )
50
+
51
+ async def start_consuming(self):
52
+ await self._connection.consume_messages(
53
+ queue_name=self._stream_name,
54
+ callback=self._consumer_callback,
55
+ count=self.count,
56
+ block=self.block,
57
+ consumer_name=self._consumer_name
58
+ )
59
+
60
+ async def _consumer_callback(
61
+ self,
62
+ data: dict,
63
+ processed_message: Any
64
+ ) -> None:
65
+ """
66
+ Callback from Consumer.
67
+
68
+ Used to call actions based on consumer messages received.
69
+ """
70
+ try:
71
+ message_id = data.get('message_id')
72
+ self._logger.info(
73
+ f"Received Message ID: {message_id} Body: {processed_message}"
74
+ )
75
+ # Call run_actions with the received message
76
+ await self.run_actions(
77
+ payload=data,
78
+ message_id=message_id,
79
+ message=processed_message
80
+ )
81
+ except Exception as e:
82
+ self._logger.error(f"Error in _consumer_callback: {e}")
83
+ raise
@@ -0,0 +1,44 @@
1
+ from typing import Optional, Any
2
+ from navigator.brokers.sqs import SQSConnection
3
+ from .base import BaseMQTrigger
4
+
5
+ class SQSTrigger(BaseMQTrigger):
6
+ def __init__(
7
+ self,
8
+ *args,
9
+ queue_name: str,
10
+ credentials: Optional[dict] = None,
11
+ actions: list = None,
12
+ **kwargs
13
+ ):
14
+ super().__init__(
15
+ *args,
16
+ actions=actions,
17
+ queue_name=queue_name,
18
+ **kwargs
19
+ )
20
+ self._connection = SQSConnection(credentials=credentials)
21
+ self.max_messages = kwargs.get('max_messages', 10)
22
+ self.wait_time = kwargs.get('wait_time', 10)
23
+ self.idle_sleep = kwargs.get('idle_sleep', 5)
24
+
25
+ async def connect(self):
26
+ await self._connection.connect()
27
+ self._logger.info(
28
+ "AWS SQS connection established."
29
+ )
30
+
31
+ async def disconnect(self):
32
+ await self._connection.disconnect()
33
+ self._logger.info(
34
+ "AWS SQS connection closed."
35
+ )
36
+
37
+ async def start_consuming(self):
38
+ await self._connection.consume_messages(
39
+ queue_name=self._queue_name,
40
+ callback=self._consumer_callback,
41
+ max_messages=self.max_messages,
42
+ wait_time=self.wait_time,
43
+ idle_sleep=self.idle_sleep
44
+ )
@@ -0,0 +1,232 @@
1
+ import time
2
+ import os
3
+ from collections import defaultdict
4
+ from navconfig.logging import logging
5
+ from watchdog.observers import Observer
6
+ from watchdog.events import PatternMatchingEventHandler
7
+ from navigator.types import WebApp
8
+ from ...exceptions import ComponentError
9
+ from .watch import BaseWatcher, BaseWatchdog
10
+
11
+
12
+ # TODO> PatternMatchingEventHandler
13
+
14
+ fslog = logging.getLogger("watchdog.observers").setLevel(logging.WARNING)
15
+
16
+
17
+ class FsHandler(PatternMatchingEventHandler):
18
+ def __init__(self, parent: BaseWatchdog, patterns=None, *args, **kwargs):
19
+ self.not_empty = kwargs.pop("not_empty", False)
20
+ super().__init__(patterns=patterns, *args, **kwargs)
21
+ self.debounced_events = defaultdict(lambda: 0)
22
+ self.parent = parent
23
+ self.recently_created = set()
24
+ self._logger = logging.getLogger("Watcher.FS")
25
+
26
+ def zero_size(self, filepath: str):
27
+ """Check if the file is of zero size."""
28
+ try:
29
+ return os.path.getsize(filepath) == 0
30
+ except (OSError, FileNotFoundError):
31
+ # Handle cases where the file no longer exists
32
+ return True
33
+
34
+ def process(self, event):
35
+ """Process the event if it matches the patterns and isn't a directory."""
36
+ if event.is_directory:
37
+ return None
38
+
39
+ # Check if an event for this path has been triggered recently
40
+ last_event_time = self.debounced_events[event.src_path]
41
+ current_time = time.time()
42
+ if current_time - last_event_time < 0.5: # 0.5 seconds debounce time
43
+ return
44
+
45
+ self.debounced_events[event.src_path] = current_time
46
+
47
+ def on_created(self, event):
48
+ if event.is_directory:
49
+ return
50
+ if "created" not in self.parent.events:
51
+ return
52
+ if self.not_empty and self.zero_size(event.src_path):
53
+ self._logger.warning(
54
+ f"File {event.src_path} has zero size and 'not_empty' is True. Skipping."
55
+ )
56
+ return # Skip triggering actions
57
+ print(f"Watchdog received created event - {event.src_path} s.")
58
+ self.recently_created.add(event.src_path) # recently created
59
+ self.process(event)
60
+ # after, running actions:
61
+ args = {
62
+ "directory": self.parent.directory,
63
+ "event": event,
64
+ "on": "created",
65
+ "filename": event.src_path,
66
+ }
67
+ self.parent.call_actions(**args)
68
+
69
+ def on_modified(self, event):
70
+ """
71
+ Handle file modification events.
72
+
73
+ This method is called when a file modification event is detected. It processes
74
+ the event and calls the appropriate actions if the event meets certain criteria.
75
+
76
+ Parameters:
77
+ event (FileSystemEvent): The event object containing information about the
78
+ file modification.
79
+
80
+ Returns:
81
+ None
82
+
83
+ Note:
84
+ - The method returns early if the event is for a directory or if 'modified'
85
+ is not in the parent's events list.
86
+ - It also returns early if the file was recently created to avoid duplicate processing.
87
+ - If the file has zero size, a warning is logged.
88
+ - The event is processed and actions are called twice with the same arguments.
89
+ """
90
+ if event.is_directory:
91
+ return
92
+ if "modified" not in self.parent.events:
93
+ return
94
+ if event.src_path in self.recently_created:
95
+ self.recently_created.remove(event.src_path)
96
+ return
97
+ if self.not_empty and self.zero_size(event.src_path):
98
+ self._logger.warning(
99
+ f"File {event.src_path} has zero size and 'not_empty' is True. Skipping."
100
+ )
101
+ return # Skip triggering actions
102
+ print(f"Watchdog received modified event - {event.src_path} s.")
103
+ self.process(event)
104
+ args = {
105
+ "directory": self.parent.directory,
106
+ "event": event,
107
+ "on": "modified",
108
+ "filename": event.src_path,
109
+ }
110
+ self.parent.call_actions(**args)
111
+ args = {
112
+ "directory": self.parent.directory,
113
+ "event": event,
114
+ "on": "created",
115
+ "filename": event.src_path,
116
+ }
117
+ self.parent.call_actions(**args)
118
+
119
+ def on_moved(self, event):
120
+ if event.is_directory:
121
+ return
122
+ if "moved" not in self.parent.events:
123
+ return
124
+ # For moved events, check the destination path
125
+ if self.not_empty and self.zero_size(event.dest_path):
126
+ self._logger.warning(f"File {event.dest_path} has zero size and 'not_empty' is True. Skipping.")
127
+ return # Skip triggering actions
128
+ print(f"Watchdog received moved event - from {event.src_path} to {event.dest_path}.")
129
+ self.process(event)
130
+ args = {
131
+ "directory": self.parent.directory,
132
+ "event": event,
133
+ "on": "moved",
134
+ "filename": event.dest_path,
135
+ }
136
+ self.parent.call_actions(**args)
137
+
138
+ def on_deleted(self, event):
139
+ if "deleted" not in self.parent.events:
140
+ return
141
+ print(f"Watchdog received deleted event - {event.src_path} s.")
142
+ self.process(event)
143
+ args = {
144
+ "directory": self.parent.directory,
145
+ "event": event,
146
+ "on": "deleted",
147
+ "filename": event.src_path,
148
+ }
149
+ self.parent.call_actions(**args)
150
+
151
+
152
+ class FsWatcher(BaseWatcher):
153
+ def __init__(self, pattern, *args, **kwargs):
154
+ super(FsWatcher, self).__init__(*args, **kwargs)
155
+ self.directory = kwargs.pop("directory", None)
156
+ self.filename = kwargs.pop("filename", [])
157
+ self.recursive = kwargs.pop("recursive", True)
158
+ self.not_empty = kwargs.pop("not_empty", False)
159
+ self.observer = Observer()
160
+ self._patterns = pattern
161
+
162
+ def run(self):
163
+ event_handler = FsHandler(
164
+ parent=self.parent,
165
+ patterns=self._patterns,
166
+ not_empty=self.not_empty
167
+ )
168
+ self.observer.schedule(
169
+ event_handler,
170
+ self.directory,
171
+ recursive=self.recursive
172
+ )
173
+ self.observer.start()
174
+ try:
175
+ while not self.stop_event.is_set():
176
+ time.sleep(self.timeout)
177
+ except KeyboardInterrupt:
178
+ self.stop()
179
+ print("Watchdog FS Observer was stopped")
180
+ except Exception as e:
181
+ self.stop()
182
+ raise e
183
+
184
+ def stop(self):
185
+ try:
186
+ self.observer.stop()
187
+ except Exception:
188
+ pass
189
+ self.observer.join()
190
+
191
+
192
+ class FSWatchdog(BaseWatchdog):
193
+ """FSWatchdog.
194
+ Checking for changes in the filesystem and dispatch events.
195
+ """
196
+
197
+ timeout: int = 5
198
+ recursive: bool = True
199
+
200
+ def create_watcher(self, *args, **kwargs) -> BaseWatcher:
201
+ self.recursive = kwargs.pop("recursive", False)
202
+ self.events = kwargs.pop("on", ["created", "modified", "deleted", "moved"])
203
+ self.filename = kwargs.pop("filename", [])
204
+ self.not_empty = kwargs.pop("not_empty", False)
205
+ if not self.filename:
206
+ self.filename = ["*"]
207
+ else:
208
+ self.filename = [f"*{filename}" for filename in self.filename]
209
+ try:
210
+ self.directory = kwargs["directory"]
211
+ except KeyError as exc:
212
+ raise ComponentError("Unable to load Directory on FSWatchdog") from exc
213
+ return FsWatcher(
214
+ pattern=self.filename,
215
+ directory=self.directory,
216
+ timeout=self.timeout,
217
+ recursive=self.recursive,
218
+ not_empty=self.not_empty,
219
+ )
220
+
221
+ async def on_startup(self, app: WebApp = None) -> None:
222
+ # Perform permissions check
223
+ if not os.access(self.directory, os.R_OK | os.X_OK):
224
+ raise PermissionError(
225
+ f"Insufficient permissions to access directory '{self.directory}'. "
226
+ "Read and execute permissions are required."
227
+ )
228
+ # Start the watcher
229
+ self.watcher.start()
230
+
231
+ async def on_shutdown(self, app: WebApp = None) -> None:
232
+ self.watcher.stop()
@@ -0,0 +1,49 @@
1
+ from navigator.views import BaseHandler
2
+ from navigator.libs.json import JSONContent
3
+ from navigator.types import WebApp
4
+ from .base import BaseTrigger
5
+
6
+
7
+ class HTTPHook(BaseTrigger, BaseHandler):
8
+ """HTTPHook.
9
+
10
+ Base Hook for all HTTP-based hooks.
11
+
12
+ """
13
+ methods: list = ["GET", "POST"]
14
+ default_status: int = 202
15
+
16
+ def __init__(self, *args, **kwargs):
17
+ self.method: str = kwargs.pop('method', None)
18
+ if self.method:
19
+ self.methods = [self.method]
20
+ super(HTTPHook, self).__init__(*args, **kwargs)
21
+ trigger_url = kwargs.get('url', None)
22
+ if trigger_url:
23
+ self.url = trigger_url
24
+ else:
25
+ self._base_url = kwargs.get('base_url', '/api/v1/webhook/')
26
+ self.url = f"{self._base_url}{self.trigger_id}"
27
+ self._json = JSONContent()
28
+
29
+ def setup(self, app: WebApp) -> None:
30
+ super().setup(app)
31
+ self._logger.notice(
32
+ f"Set the unique URL Trigger to: {self.url}"
33
+ )
34
+ if hasattr(self, 'handle'):
35
+ self.app.router.add_route(
36
+ 'POST',
37
+ self.url,
38
+ self.handle
39
+ )
40
+ else:
41
+ # Class-based Views
42
+ for method in self.methods:
43
+ handler = getattr(self, method.lower(), None)
44
+ if handler:
45
+ self.app.router.add_route(
46
+ method,
47
+ self.url,
48
+ handler
49
+ )