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,200 @@
1
+ from typing import Union
2
+ from collections.abc import Callable
3
+ from pathlib import PurePath
4
+ import asyncio
5
+ import aiofiles
6
+ from navconfig.logging import logging
7
+ from ..interfaces import TemplateSupport
8
+ from ..interfaces.databases.documentdb import DocumentDBSupport
9
+ from .flow import FlowComponent
10
+ from ..utils.functions import is_empty
11
+ from ..exceptions import FileError, ComponentError, DataNotFound
12
+ from ..utils.json import json_decoder, json_encoder
13
+
14
+
15
+ # Disable Mongo Logging
16
+ logging.getLogger("pymongo").setLevel(logging.INFO)
17
+
18
+
19
+ class DocumentDBQuery(DocumentDBSupport, TemplateSupport, FlowComponent):
20
+ """DocumentDBQuery.
21
+
22
+ DocumentDBQuery is a component that interacts with a DocumentDB database using pymongo.
23
+
24
+ Returns json-object representation of the query result.
25
+
26
+
27
+ Example:
28
+
29
+ ```yaml
30
+ DocumentDBQuery:
31
+ schema: networkninja
32
+ tablename: batches
33
+ query:
34
+ data.metadata.type: form_data
35
+ data.metadata.timestamp:
36
+ $gte: 1743670800.0
37
+ $lte: 1743681600.999999
38
+ ```
39
+
40
+ """
41
+ driver: str = 'mongo'
42
+
43
+ def __init__(
44
+ self,
45
+ loop: asyncio.AbstractEventLoop = None,
46
+ job: Callable = None,
47
+ stat: Callable = None,
48
+ **kwargs,
49
+ ):
50
+ self._query: dict = {}
51
+ # Collection:
52
+ self._collection: str = kwargs.pop("collection_name", None)
53
+ if not self._collection:
54
+ self._collection = kwargs.pop("tablename", None)
55
+ if not self._collection:
56
+ raise ValueError(
57
+ f"{__name__}: Missing Collection Name or Table Name"
58
+ )
59
+ self._database: str = kwargs.pop("database", None)
60
+ if not self._database:
61
+ self._database = kwargs.pop("schema", kwargs.get('program', None))
62
+ if not self._database:
63
+ raise ValueError(
64
+ f"{__name__}: Missing Database Name or Schema Name"
65
+ )
66
+ self.query: Union[str, dict] = kwargs.get('query', None)
67
+ super().__init__(
68
+ loop=loop,
69
+ job=job,
70
+ stat=stat,
71
+ **kwargs
72
+ )
73
+ if self.as_string is True:
74
+ self.infer_types = True
75
+
76
+ async def open_queryfile(self, file: PurePath, **kwargs) -> str:
77
+ if file.exists() and file.is_file():
78
+ content = None
79
+ # open SQL File:
80
+ async with aiofiles.open(file, "r+") as afp:
81
+ content = await afp.read()
82
+ # check if we need to replace masks
83
+ if hasattr(self, "masks"):
84
+ content = self.mask_replacement(content)
85
+ if self.use_template is True:
86
+ content = self._templateparser.from_string(content, kwargs)
87
+ return content
88
+ else:
89
+ raise FileError(
90
+ f"{__name__}: Missing Query File: {file}"
91
+ )
92
+
93
+ async def start(self, **kwargs) -> bool:
94
+ """start.
95
+
96
+ Start the DocumentDBQuery component.
97
+ """
98
+ await super(DocumentDBQuery, self).start(**kwargs)
99
+ if hasattr(self, "conditions"):
100
+ self.set_conditions("conditions")
101
+ if hasattr(self, "query_file") or hasattr(self, "query_file"):
102
+ query = self.query_file
103
+ qry = await self.open_queryfile(query)
104
+ elif isinstance(self.query, PurePath):
105
+ qry = await self.open_queryfile(self.query)
106
+ else:
107
+ if isinstance(self.query, str):
108
+ if hasattr(self, "masks"):
109
+ qry = self.mask_replacement(self.query)
110
+ if "{" in self.query and hasattr(self, "conditions"):
111
+ qry = self.query.format(**self.conditions)
112
+ else:
113
+ qry = self.query
114
+ elif isinstance(self.query, dict):
115
+ # Doing condition replacement for every element in the query
116
+ qry = {}
117
+ for key, value in self.query.items():
118
+ if isinstance(value, str):
119
+ if hasattr(self, "masks"):
120
+ value = self.mask_replacement(value)
121
+ if "{" in value and hasattr(self, "conditions"):
122
+ value = value.format(**self.conditions)
123
+ qry[key] = value
124
+ else:
125
+ raise ValueError(
126
+ f"{__name__}: Missing or Invalid Query or Query File"
127
+ )
128
+ try:
129
+ if isinstance(qry, str):
130
+ self._query = json_decoder(qry)
131
+ else:
132
+ self._query = qry
133
+ except Exception as err:
134
+ raise ComponentError(
135
+ f"{__name__}: Error decoding Query: {err}"
136
+ )
137
+ return True
138
+
139
+ async def close(self):
140
+ pass
141
+
142
+ async def run(self):
143
+ try:
144
+ db = self.default_connection(
145
+ driver=self.driver, credentials=self.credentials
146
+ )
147
+ except Exception as e:
148
+ self._logger.error(
149
+ f"Error getting Default DocumentDB Connection: {e!s}"
150
+ )
151
+ raise
152
+ try:
153
+ async with await db.connection() as conn:
154
+ if conn.is_connected() is not True:
155
+ raise ComponentError(
156
+ f"DB Error: driver {self.driver} is not connected."
157
+ )
158
+ await conn.use(self._database)
159
+ # print(
160
+ # ':: Count > ',
161
+ # await conn.count_documents(collection_name=self._collection)
162
+ # )
163
+ result, error = await conn.query(
164
+ collection_name=self._collection,
165
+ query=self._query,
166
+ )
167
+ if error:
168
+ raise ComponentError(
169
+ f"Error executing Query: {error}"
170
+ )
171
+ if is_empty(result):
172
+ raise DataNotFound(
173
+ f"Data not found for Query: {self._query}"
174
+ )
175
+
176
+ if self.as_dataframe is True:
177
+ self._result = await self.get_dataframe(result)
178
+ else:
179
+ self._result = result
180
+ # self.add_metric(
181
+ # "Query", json_encoder(self._query)
182
+ # )
183
+ self.add_metric(
184
+ "Database", str(self._database)
185
+ )
186
+ self.add_metric(
187
+ "Collection", str(self._collection)
188
+ )
189
+ self.add_metric(
190
+ "NUM_RESULTS", len(self._result)
191
+ )
192
+ return self._result
193
+ except DataNotFound:
194
+ raise
195
+ except ComponentError:
196
+ raise
197
+ except Exception as e:
198
+ raise ComponentError(
199
+ f"Error connecting to DocumentDB: {e}"
200
+ )
@@ -0,0 +1,371 @@
1
+ import asyncio
2
+ import random
3
+ import ssl
4
+ from abc import abstractmethod
5
+ from functools import partial
6
+ from typing import Dict, List
7
+ from collections.abc import Callable
8
+ from pathlib import Path, PurePath, PosixPath
9
+ from tqdm import tqdm
10
+ import aiohttp
11
+ from ..exceptions import ComponentError, FileNotFound
12
+ from ..utils.encoders import DefaultEncoder
13
+ from ..utils import SafeDict
14
+ from .flow import FlowComponent
15
+ from ..interfaces.dataframes import PandasDataframe
16
+ from ..interfaces.http import ua
17
+
18
+
19
+ class DownloadFromBase(PandasDataframe, FlowComponent):
20
+ """
21
+ DownloadFromBase
22
+
23
+ Abstract base class for downloading files from various sources.
24
+
25
+ Inherits from `FlowComponent` and `PandasDataframe` to provide common functionalities
26
+ for component management and data handling.
27
+
28
+ This class utilizes `aiohttp` for asynchronous HTTP requests and offers support
29
+ for authentication, SSL connections, and basic file management.
30
+
31
+ .. note::
32
+ This class is intended to be subclassed for specific download implementations.
33
+
34
+ .. table:: Properties
35
+ :widths: auto
36
+
37
+ +----------------------+----------+-----------+-------------------------------------------------------------------------+
38
+ | Name | Required | Summary |
39
+ +----------------------+----------+-----------+-------------------------------------------------------------------------+
40
+ | credentials | Yes | Dictionary containing expected username and password for authentication |
41
+ | | | (default: {"username": str, "password": str}). |
42
+ +----------------------+----------+-------------------------------------------------------------------------------------+
43
+ | no_host | No | Boolean flag indicating whether to skip defining host and port (default: False). |
44
+ +----------------------+----------+-----------+-------------------------------------------------------------------------+
45
+ | overwrite | No | Boolean flag indicating whether to overwrite existing files (default: True). |
46
+ +----------------------+----------+-----------+-------------------------------------------------------------------------+
47
+ | overwrite | No | Boolean flag indicating whether to overwrite existing files (default: True). |
48
+ +----------------------+----------+-----------+-------------------------------------------------------------------------+
49
+ | create_destination | No | Boolean flag indicating whether to create the destination directory |
50
+ | | | if it doesn't exist (default: True). |
51
+ +----------------------+----------+-----------+-------------------------------------------------------------------------+
52
+ | rename | No | String defining a new filename for the downloaded file. |
53
+ +----------------------+----------+-----------+-------------------------------------------------------------------------+
54
+ | file | Yes | Access the file download through a url, with the required user credentials and |
55
+ | | | password |
56
+ +----------------------+----------+-----------+-------------------------------------------------------------------------+
57
+ | download | Yes | File destination and directory |
58
+ +----------------------+----------+-----------+-------------------------------------------------------------------------+
59
+ | source | Yes | Origin of the file to download and location where the file is located. |
60
+ +----------------------+----------+-----------+-------------------------------------------------------------------------+
61
+ | destination | Yes | Destination where the file will be save. |
62
+ +----------------------+----------+-----------+-------------------------------------------------------------------------+
63
+ | ssl | No | Boolean flag indicating whether to use SSL connection (default: False). |
64
+ +----------------------+----------+-----------+-------------------------------------------------------------------------+
65
+ | ssl_cafile | No | Path to the CA certificate file for SSL verification. |
66
+ +----------------------+----------+-----------+-------------------------------------------------------------------------+
67
+ | ssl_certs | No | List of certificate chains for SSL verification. |
68
+ +----------------------+----------+-----------+-------------------------------------------------------------------------+
69
+ | host | No | Hostname for the download source (default: "localhost"). |
70
+ +----------------------+----------+-----------+-------------------------------------------------------------------------+
71
+ | port | No | Port number for the download source (default: 22). |
72
+ +----------------------+----------+-----------+-------------------------------------------------------------------------+
73
+ | timeout | No | Timeout value in seconds for HTTP requests (default: 30). |
74
+ +----------------------+----------+-----------+-------------------------------------------------------------------------+
75
+ | url | No | URL of the download source (populated within the class). |
76
+ +----------------------+----------+-----------+-------------------------------------------------------------------------+
77
+ | headers | Yes | Dictionary containing HTTP headers for the request. |
78
+ +----------------------+----------+-----------+-------------------------------------------------------------------------+
79
+ """ # noqa
80
+ _credentials: dict = {"username": str, "password": str}
81
+
82
+ def __init__(
83
+ self,
84
+ loop: asyncio.AbstractEventLoop = None,
85
+ job: Callable = None,
86
+ stat: Callable = None,
87
+ **kwargs,
88
+ ):
89
+ self.no_host: bool = kwargs.pop("no_host", False)
90
+ self.accept: str = "text/plain"
91
+ self.overwrite: bool = True
92
+ self.create_destination: bool = kwargs.pop("create_destination", False)
93
+ self.rename: str = None
94
+ # source:
95
+ self.source_file: str = None
96
+ self.source_dir: str = None
97
+ # destination:
98
+ self.filename: str = None
99
+ self._srcfiles: List = []
100
+ self._filenames: Dict = {}
101
+ self._connection: Callable = None
102
+ self.ssl: bool = False
103
+ self.ssl_cafile: str = None
104
+ self.ssl_certs: list = []
105
+ self.timeout: int = kwargs.pop("timeout", 30)
106
+ super().__init__(
107
+ loop=loop, job=job, stat=stat, **kwargs
108
+ )
109
+ if not hasattr(self, "url"):
110
+ self.url: str = None
111
+ if not hasattr(self, "headers"):
112
+ self.headers = {}
113
+ self._encoder = DefaultEncoder()
114
+ self._valid_response_status: tuple = (200, 201, 202)
115
+ # SSL Context:
116
+ if self.ssl:
117
+ # TODO: add CAFile and cert-chain
118
+ self.ssl_ctx = ssl.SSLContext(ssl.PROTOCOL_TLS, cafile=self.ssl_cafile)
119
+ self.ssl_ctx.minimum_version = ssl.TLSVersion.TLSv1_2
120
+ self.ssl_ctx.options &= ~ssl.OP_NO_SSLv3
121
+ self.ssl_ctx.verify_mode = ssl.CERT_NONE
122
+ if self.ssl_certs:
123
+ self.ssl_ctx.load_cert_chain(*self.ssl_certs)
124
+ else:
125
+ self.ssl_ctx = None
126
+
127
+ def build_headers(self):
128
+ self.headers = {
129
+ "Accept": self.accept,
130
+ "Accept-Encoding": "gzip, deflate",
131
+ "DNT": "1",
132
+ "Connection": "keep-alive",
133
+ "Upgrade-Insecure-Requests": "1",
134
+ "User-Agent": random.choice(ua),
135
+ **self.headers,
136
+ }
137
+
138
+ async def start(self, **kwargs):
139
+ """Start.
140
+
141
+ Processing variables and credentials.
142
+ """
143
+ try:
144
+ if getattr(self, 'define_host', None) is not None:
145
+ self.define_host()
146
+ self.processing_credentials()
147
+ except Exception as err:
148
+ self._logger.error(err)
149
+ raise
150
+ if hasattr(self, "directory"):
151
+ self.directory = Path(self.directory)
152
+ try:
153
+ if hasattr(self, "masks"):
154
+ p = self.mask_replacement(self.directory)
155
+ else:
156
+ p = self.directory
157
+ if not p.exists():
158
+ if self.create_destination is True:
159
+ try:
160
+ PosixPath(p).mkdir(parents=True, exist_ok=True)
161
+ except (Exception, OSError) as err:
162
+ raise ComponentError(
163
+ f"Error creating directory {self.directory}: {err}"
164
+ ) from err
165
+ else:
166
+ self._logger.error(
167
+ f"DownloadFrom: Path doesn't exists: {p}"
168
+ )
169
+ raise FileNotFound(
170
+ f"DownloadFrom: Path doesn't exists: {p}"
171
+ )
172
+ except Exception as err:
173
+ self._logger.error(err)
174
+ raise ComponentError(f"{err!s}") from err
175
+ self._logger.debug(f"Destination Directory: {self.directory}")
176
+ if hasattr(self, "file"):
177
+ if isinstance(self.file, list):
178
+ # is a list of files:
179
+ for file in self.file:
180
+ filename = file
181
+ if hasattr(self, "masks"):
182
+ filename = self.mask_replacement(file)
183
+ self._logger.debug(f"Filename > {filename}")
184
+ self._srcfiles.append(filename)
185
+ else:
186
+ try:
187
+ filename = self.process_pattern("file")
188
+ directory = self.file.get('directory', None)
189
+ if hasattr(self, "masks"):
190
+ if isinstance(filename, dict):
191
+ for key, value in filename.items():
192
+ filename[key] = self.mask_replacement(value)
193
+ elif isinstance(filename, str):
194
+ filename = self.mask_replacement(filename)
195
+ # path for file
196
+ self._logger.debug(
197
+ f"Filename > {filename}"
198
+ )
199
+ self.filename = filename
200
+ # for some exception, directory is on file:
201
+ if directory:
202
+ self.source_dir = directory
203
+ if hasattr(self, "masks"):
204
+ self.source_dir = self.mask_replacement(directory)
205
+ self._srcfiles.append(filename)
206
+ except Exception as err:
207
+ raise ComponentError(f"{err!s}") from err
208
+ elif hasattr(self, "source"): # using the destination filosophy
209
+ source_dir = self.source.get('directory', '/')
210
+ if hasattr(self, "masks"):
211
+ self.source_dir = self.mask_replacement(source_dir)
212
+ else:
213
+ self.source_dir = source_dir
214
+ # filename:
215
+ if "file" in self.source:
216
+ self.source_file = self.process_pattern(
217
+ "file",
218
+ parent=self.source
219
+ )
220
+ self._srcfiles.append(self.source_file)
221
+ else:
222
+ filenames = self.source.get('filename')
223
+ try:
224
+ if isinstance(filenames, list):
225
+ for file in filenames:
226
+ filename = self.mask_replacement(file)
227
+ self._srcfiles.append(
228
+ {
229
+ "filename": file,
230
+ "directory": self.source_dir
231
+ }
232
+ )
233
+ elif isinstance(filenames, dict):
234
+ self._srcfiles.append(filenames)
235
+ else:
236
+ self.source_file = {
237
+ "filename": self.mask_replacement(
238
+ filenames
239
+ ),
240
+ "directory": self.source_dir
241
+ }
242
+ self._srcfiles.append(self.source_file)
243
+ except KeyError:
244
+ self.source_file = None
245
+ if hasattr(self, "destination"):
246
+ if "filename" in self.destination:
247
+ # Rename the file to be downloaded
248
+ self.filename = self.destination.get('filename', None)
249
+ elif isinstance(self.filename, dict) and 'filename' in self.filename:
250
+ self.filename = self.filename["filename"]
251
+ else:
252
+ # Preserving Filename from Source
253
+ self.filename = None
254
+ if self.filename:
255
+ self._logger.debug(
256
+ f"Raw Destination Filename: {self.filename}\n"
257
+ )
258
+ if hasattr(self, "masks") or "{" in self.filename:
259
+ self.filename = self.mask_replacement(self.filename)
260
+ try:
261
+ _dir = self.destination.get('directory')
262
+ _direc = _dir.format_map(SafeDict(**self._variables))
263
+ _dir = self.mask_replacement(_direc)
264
+ self.directory = Path(_dir)
265
+ except KeyError:
266
+ # Maybe Filename contains directory?
267
+ if self.destination["filename"]:
268
+ self.directory = Path(self.destination["filename"]).parent
269
+ self.filename = Path(self.destination["filename"]).name
270
+ try:
271
+ if self.create_destination is True:
272
+ self.directory.mkdir(parents=True, exist_ok=True)
273
+ except OSError as err:
274
+ raise ComponentError(
275
+ f"DownloadFrom: Error creating directory {self.directory}: {err}"
276
+ ) from err
277
+ except Exception as err:
278
+ self._logger.error(f"Error creating directory {self.directory}: {err}")
279
+ raise ComponentError(
280
+ f"Error creating directory {self.directory}: {err}"
281
+ ) from err
282
+ if "filename" in self.destination:
283
+ if not isinstance(self.filename, PurePath):
284
+ self.filename = self.directory.joinpath(self.filename)
285
+ self._logger.debug(
286
+ f":: Destination File: {self.filename}"
287
+ )
288
+ await super(DownloadFromBase, self).start(**kwargs)
289
+ if self.url:
290
+ self.build_headers()
291
+ return True
292
+
293
+ async def http_response(self, response):
294
+ return response
295
+
296
+ async def http_session(
297
+ self,
298
+ url: str = None,
299
+ method: str = "get",
300
+ data: dict = None,
301
+ data_format: str = "json",
302
+ ):
303
+ """
304
+ session.
305
+ connect to an http source using aiohttp
306
+ """
307
+ timeout = aiohttp.ClientTimeout(total=self.timeout)
308
+ if url is not None:
309
+ self.url = url
310
+ # TODO: Auth, Data, etc
311
+ auth = {}
312
+ params = {}
313
+ _data = {"data": None}
314
+ if self.credentials:
315
+ if "username" in self.credentials: # basic Authentication
316
+ auth = aiohttp.BasicAuth(
317
+ self.credentials["username"], self.credentials["password"]
318
+ )
319
+ params = {"auth": auth}
320
+ elif "token" in self.credentials:
321
+ self.headers["Authorization"] = "{scheme} {token}".format(
322
+ scheme=self.credentials["scheme"], token=self.credentials["token"]
323
+ )
324
+ if data_format == "json":
325
+ params["json_serialize"] = self._encoder.dumps
326
+ _data["json"] = data
327
+ else:
328
+ _data["data"] = data
329
+ async with aiohttp.ClientSession(**params) as session:
330
+ meth = getattr(session, method)
331
+ if self.ssl:
332
+ ssl = {"ssl": self.ssl_ctx, "verify_ssl": True}
333
+ else:
334
+ ssl = {}
335
+ fn = partial(
336
+ meth,
337
+ self.url,
338
+ headers=self.headers,
339
+ timeout=timeout,
340
+ allow_redirects=True,
341
+ **ssl,
342
+ **_data,
343
+ )
344
+ try:
345
+ async with fn() as response:
346
+ if response.status in self._valid_response_status:
347
+ return await self.http_response(response)
348
+ else:
349
+ print("ERROR RESPONSE >> ", response)
350
+ raise ComponentError(
351
+ f"DownloadFrom: Error getting data from URL {response}"
352
+ )
353
+ except Exception as err:
354
+ raise ComponentError(
355
+ f"DownloadFrom: Error Making an SSL Connection to ({self.url}): {err}"
356
+ ) from err
357
+ except aiohttp.exceptions.HTTPError as err:
358
+ raise ComponentError(
359
+ f"DownloadFrom: SSL Certificate Error: {err}"
360
+ ) from err
361
+
362
+ @abstractmethod
363
+ async def close(self):
364
+ pass
365
+
366
+ @abstractmethod
367
+ async def run(self):
368
+ pass
369
+
370
+ def start_pbar(self, total: int = 1):
371
+ return tqdm(total=total)
@@ -0,0 +1,113 @@
1
+ import asyncio
2
+ import pandas as pd
3
+ from collections.abc import Callable
4
+ from ..utils import is_empty
5
+ from ..exceptions import ComponentError, DataNotFound
6
+ from .DownloadFrom import DownloadFromBase
7
+ from ..interfaces.d2l import D2LClient
8
+
9
+ class DownloadFromD2L(D2LClient, DownloadFromBase):
10
+ """
11
+ DownloadFromD2L
12
+
13
+ Overview
14
+
15
+ Download Data from D2L.
16
+
17
+ Properties (inherited from D2LClient and DownloadFromBase)
18
+
19
+ .. table:: Properties
20
+ :widths: auto
21
+
22
+ +--------------------+----------+-----------+----------------------------------------------------------------------+
23
+ | Name | Required | Summary |
24
+ +--------------------+----------+-----------+----------------------------------------------------------------------+
25
+ | credentials | Yes | Credentials to establish connection with Polestar site (user and password) |
26
+ | | | get credentials from environment if null. |
27
+ +--------------------+----------+-----------+----------------------------------------------------------------------+
28
+ | filename | Yes | The filename to use for the downloaded file. |
29
+ +--------------------+----------+-----------+----------------------------------------------------------------------+
30
+ | Action | No | Select 'download' or 'awards'. (Default: download) |
31
+ +--------------------+----------+-----------+----------------------------------------------------------------------+
32
+ | schema | No | The ID of the Schema to download. Required if action is 'download' |
33
+ +--------------------+----------+-----------+----------------------------------------------------------------------+
34
+ | org_units | No | A list of ID of Organization Units. Required if action is 'awards' |
35
+ +--------------------+----------+-----------+----------------------------------------------------------------------+
36
+ | column | No | A column name to extract the list of Organization Units. Required if action is |
37
+ | | | 'awards' and depends of a Pandas DataFrame. |
38
+ +--------------------+----------+-----------+----------------------------------------------------------------------+
39
+ | create_destination | No | Boolean flag indicating whether to create the destination directory if it |
40
+ | | | doesn't exist (default: True). |
41
+ +--------------------+----------+-----------+----------------------------------------------------------------------+
42
+
43
+ Save the downloaded files on the new destination.
44
+
45
+
46
+
47
+ Example:
48
+
49
+ ```yaml
50
+ DownloadFromD2L:
51
+ domain: POLESTAR_DOMAIN
52
+ schema: c0b0740f-896e-4afa-bfd9-81d8e43006d9
53
+ credentials:
54
+ username: POLESTAR_USERNAME
55
+ password: POLESTAR_PASSWORD
56
+ destination:
57
+ directory: /home/ubuntu/symbits/polestar/files/organizational_unit_ancestors/
58
+ filename: organizational_unit_ancestors_{yesterday}.zip
59
+ overwrite: true
60
+ masks:
61
+ yesterday:
62
+ - yesterday
63
+ - mask: '%Y-%m-%d'
64
+ ```
65
+
66
+ """ # noqa
67
+ def __init__(
68
+ self,
69
+ loop: asyncio.AbstractEventLoop = None,
70
+ job: Callable = None,
71
+ stat: Callable = None,
72
+ **kwargs,
73
+ ):
74
+ super().__init__(loop=loop, job=job, stat=stat, **kwargs)
75
+
76
+ async def start(self, **kwargs):
77
+ self.action = kwargs.get('action', 'download')
78
+ if self.action == 'awards':
79
+ if hasattr(self, 'org_units'):
80
+ self.data = self.org_units
81
+ elif self.previous:
82
+ if not isinstance(self.input, pd.DataFrame):
83
+ raise ComponentError(
84
+ "DownloadFromD2L: Incompatible Pandas Dataframe", status=404
85
+ )
86
+ else:
87
+ if not hasattr(self, 'column'):
88
+ raise ComponentError(
89
+ 'DownloadFromD2L: requires a "column" Attribute'
90
+ )
91
+ self.data = self.input[self.column].to_numpy()
92
+ await self.get_bearer_token()
93
+ await super(DownloadFromD2L, self).start(**kwargs)
94
+ return True
95
+
96
+ async def close(self):
97
+ pass
98
+
99
+ async def run(self):
100
+ if self.action == 'download':
101
+ await self.download_file()
102
+ self._result = self.filename
103
+ self.add_metric("D2L_FILE", self.filename)
104
+ return self._result
105
+ elif self.action == 'awards':
106
+ self._result = await self.create_dataframe(await self.awards(org_units=self.data))
107
+ if is_empty(self._result):
108
+ raise DataNotFound(f"{self.__name__}: Data Not Found")
109
+ return self._result
110
+ else:
111
+ raise ComponentError(
112
+ 'DownloadFromD2L: Action not defined'
113
+ )