flowtask 5.8.4__cp39-cp39-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-39-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-39-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-39-x86_64-linux-gnu.so +0 -0
  377. flowtask/parsers/json.c +11968 -0
  378. flowtask/parsers/json.cpython-39-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-39-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-39-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-39-x86_64-linux-gnu.so +0 -0
  440. flowtask/utils/json.cpp +13349 -0
  441. flowtask/utils/json.cpython-39-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-39-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,450 @@
1
+ import asyncio
2
+ import copy
3
+ import re
4
+ from typing import Dict, List, Union
5
+ from collections.abc import Callable
6
+ import pandas as pd
7
+ import numpy as np
8
+ from navconfig.logging import logging
9
+ from asyncdb import AsyncDB
10
+ from asyncdb.exceptions import NoDataFound
11
+ from querysource.conf import asyncpg_url
12
+ from querysource.types.dt import transforms as qsdfunctions
13
+ from ...exceptions import ComponentError
14
+ from ...parsers.maps import open_map, open_model
15
+ from ..TransformRows import functions as tfunctions
16
+ from ...utils.executor import getFunction
17
+ from ..flow import FlowComponent
18
+ from . import functions as tmapfn
19
+
20
+
21
+ def is_snakecase(value):
22
+ ## already in snake case:
23
+ return re.match(r"^[a-zA-Z][a-zA-Z0-9_]+_[a-zA-Z0-9]*$", value.strip()) is not None
24
+
25
+
26
+ def is_camelcase(value):
27
+ return re.match(r"^[A-Za-z][a-z0-9]*([A-Z][a-z0-9]*)*$", value.strip()) is not None
28
+
29
+
30
+ def is_titlecase(value):
31
+ return re.match(r"^([A-Z][a-z]*\s?)*$", value.strip()) is not None
32
+
33
+
34
+ def camelCase_split(value):
35
+ if bool(re.match(r"[A-Z]+$", value)):
36
+ return re.findall(r"[A-Z]+$", value)
37
+ elif bool(re.search(r"\d", value)):
38
+ return re.findall(r"[A-Z](?:[a-z]+[1-9]?|[A-Z]*(?=[A-Z])|$)", value)
39
+ elif value[0].isupper():
40
+ return re.findall(r"[A-Z](?:[a-z]+|[A-Z]*(?=[A-Z]|$))", value)
41
+ else:
42
+ # value = value.capitalize()
43
+ return re.findall(r"^[a-z]+|[A-Z][^A-Z]*", value)
44
+
45
+
46
+ class tMap(FlowComponent):
47
+ """
48
+ tMap
49
+
50
+ Overview
51
+
52
+ The tMap class is a component for transforming and mapping data in a Pandas DataFrame. It supports various column name
53
+ transformations, data type conversions, and function applications to columns. It extends the FlowComponent class and
54
+ provides methods for column information retrieval, data transformation, and function execution.
55
+
56
+ .. table:: Properties
57
+ :widths: auto
58
+
59
+ +------------------+----------+-----------+--------------------------------------------------------------------------------------+
60
+ | Name | Required | Description |
61
+ +------------------+----------+-----------+--------------------------------------------------------------------------------------+
62
+ | tablename | No | The name of the table to retrieve column information from. |
63
+ +------------------+----------+-----------+--------------------------------------------------------------------------------------+
64
+ | schema | No | The schema of the table to retrieve column information from. |
65
+ +------------------+----------+-----------+--------------------------------------------------------------------------------------+
66
+ | model | No | The model to use for data transformation. |
67
+ +------------------+----------+-----------+--------------------------------------------------------------------------------------+
68
+ | _modelinfo | No | A dictionary containing the model information. |
69
+ +------------------+----------+-----------+--------------------------------------------------------------------------------------+
70
+ | map | No | The map file to use for column transformations. |
71
+ +------------------+----------+-----------+--------------------------------------------------------------------------------------+
72
+ | _mapping | No | A dictionary containing the column mappings. |
73
+ +------------------+----------+-----------+--------------------------------------------------------------------------------------+
74
+ | force_map | No | A flag indicating if the map file should be forced, defaults to False. |
75
+ +------------------+----------+-----------+--------------------------------------------------------------------------------------+
76
+ | replace_columns | No | A flag indicating if columns should be replaced, defaults to True. |
77
+ +------------------+----------+-----------+--------------------------------------------------------------------------------------+
78
+ | drop_missing | No | A flag indicating if missing columns should be dropped, defaults to False. |
79
+ +------------------+----------+-----------+--------------------------------------------------------------------------------------+
80
+ | column_info | Yes | I access the information of the column through a statement in sql to extract the data |
81
+ +------------------+----------+-----------+--------------------------------------------------------------------------------------+
82
+ | clean_names | Yes | Remove duplicate names from data |
83
+ +------------------+----------+-----------+--------------------------------------------------------------------------------------+
84
+
85
+ Return
86
+
87
+ The methods in this class manage the transformation and mapping of data in a Pandas DataFrame, including initialization,
88
+ column information retrieval, data transformation, and function execution.
89
+
90
+
91
+
92
+ Example:
93
+
94
+ ```yaml
95
+ tMap:
96
+ schema: bose
97
+ map: products_by_store
98
+ drop_missing: false
99
+ ```
100
+
101
+ """ # noqa
102
+ def __init__(
103
+ self,
104
+ loop: asyncio.AbstractEventLoop = None,
105
+ job: Callable = None,
106
+ stat: Callable = None,
107
+ **kwargs,
108
+ ):
109
+ self.tablename: str = None
110
+ self.schema: str = None
111
+ self.model: str = None
112
+ self._modelinfo: dict = None
113
+ self.map: str = None
114
+ self._mapping: dict = None
115
+ self.force_map: bool = False
116
+ self.replace_columns: bool = True
117
+ self.drop_missing: bool = False
118
+ # use it for getting column information
119
+ self._flavor = kwargs.pop('flavor', 'postgres')
120
+ super(tMap, self).__init__(loop=loop, job=job, stat=stat, **kwargs)
121
+ if not self.schema:
122
+ self.schema = self._program
123
+
124
+ def _get_df_function(self, fn: str) -> Union[Callable, None]:
125
+ func = getattr(tfunctions, fn, None)
126
+ if func is None:
127
+ func = getattr(qsdfunctions, fn, None)
128
+ return func
129
+
130
+ async def column_info(
131
+ self, table: str, schema: str = "public", flavor: str = "postgres"
132
+ ) -> list:
133
+ if not self.force_map:
134
+ result = None
135
+ if flavor == "postgres":
136
+ tablename = f"{schema}.{table}"
137
+ discover = f"""SELECT attname AS column_name, atttypid::regtype
138
+ AS data_type, attnotnull::boolean as notnull
139
+ FROM pg_attribute WHERE attrelid = '{tablename}'::regclass
140
+ AND attnum > 0 AND NOT attisdropped ORDER BY attnum;
141
+ """
142
+ try:
143
+ try:
144
+ event_loop = asyncio.get_running_loop()
145
+ except RuntimeError:
146
+ event_loop = asyncio.get_event_loop()
147
+ db = AsyncDB("pg", dsn=asyncpg_url, loop=event_loop)
148
+ async with await db.connection() as conn:
149
+ result, error = await conn.query(discover)
150
+ if error:
151
+ raise ComponentError(f"Column Info Error {error}")
152
+ except NoDataFound:
153
+ pass
154
+ finally:
155
+ db = None
156
+ else:
157
+ raise ValueError(f"Column Info: Flavor not supported yet: {flavor}")
158
+ if result:
159
+ return {item["column_name"]: item["data_type"] for item in result}
160
+ # getting model from file:
161
+ model = await open_model(table, schema)
162
+ if model:
163
+ fields = model["fields"]
164
+ return {field: fields[field]["data_type"] for field in fields}
165
+ else:
166
+ if self.force_map:
167
+ self._logger.debug(
168
+ f"Open Map: Forcing using of Map File {schema}.{table}"
169
+ )
170
+ else:
171
+ self._logger.error(f"Open Map: Table {schema}.{table} doesn't exist")
172
+ return None
173
+
174
+ async def start(self, **kwargs):
175
+ if self.previous:
176
+ self.data = self.input
177
+ # getting model from model or from tablename
178
+ if self.tablename:
179
+ try:
180
+ self._modelinfo = await self.column_info(
181
+ table=self.tablename, schema=self.schema, flavor=self._flavor
182
+ )
183
+ except Exception as exc:
184
+ self._logger.warning(
185
+ f"Error getting Table Model for {self.tablename}.{self.schema} : {exc}"
186
+ )
187
+ if hasattr(self, "automap"):
188
+ # Create a Mapping converting columns:
189
+ mapping = {}
190
+ columns = self.data.columns.tolist()
191
+ for col in columns:
192
+ if is_snakecase(col):
193
+ new_name = col.strip().lower()
194
+ elif is_camelcase(col):
195
+ new_name = "_".join(
196
+ [x.lower().strip() for x in camelCase_split(col)]
197
+ )
198
+ else:
199
+ new_col = col.replace("(", "").replace(')', '').replace('-', '_').strip()
200
+ if is_camelcase(new_col):
201
+ new_name = "_".join(
202
+ [x.lower().strip() for x in camelCase_split(new_col)]
203
+ )
204
+ elif is_titlecase(new_col):
205
+ new_name = "_".join(
206
+ [x.lower().strip() for x in new_col.split(" ")]
207
+ )
208
+ else:
209
+ new_name = col.strip()
210
+ mapping[new_name] = col
211
+ self._mapping = mapping
212
+ else:
213
+ try:
214
+ # open a map file:
215
+ self._mapping = await open_map(
216
+ filename=str(self.map), program=self._program
217
+ )
218
+ except Exception as err:
219
+ raise ComponentError(f"TableMap: Error open Map File: {err}") from err
220
+
221
+ async def close(self):
222
+ """
223
+ close.
224
+
225
+ close method
226
+ """
227
+
228
+ def is_dataframe(self, df) -> bool:
229
+ return isinstance(df, pd.DataFrame)
230
+
231
+ async def run(self):
232
+ """
233
+ run.
234
+
235
+ Iteration over all dataframes.
236
+ """
237
+ if isinstance(self.data, list): # a list of dataframes
238
+ pass
239
+ elif isinstance(self.data, dict): # named queries
240
+ pass
241
+ else:
242
+ # one single dataframe
243
+ if not self.is_dataframe(self.data):
244
+ raise ComponentError(
245
+ "tMap Error: we're expecting a Pandas Dataframe as source."
246
+ )
247
+ # adding first metrics:
248
+ self.add_metric("started_rows", self.data.shape[0])
249
+ self.add_metric("started_columns", self.data.shape[1])
250
+ df = await self.transform(self.data, copy.deepcopy(self._mapping))
251
+ # check if a column is missing:
252
+ if self.drop_missing is True:
253
+ for column in df.columns:
254
+ if column not in self._mapping: # Dropping unused columns
255
+ df.drop(column, axis="columns", inplace=True)
256
+ self._result = df
257
+ # avoid threat the Dataframe as a Copy
258
+ self._result.is_copy = None
259
+ return self._result
260
+
261
+ async def transform(self, df: pd.DataFrame, mapping: dict) -> pd.DataFrame:
262
+ it = {}
263
+ for column, field in mapping.items():
264
+ logging.debug(f"tMap: CALLING {column} for {field}:{type(field)}")
265
+ if isinstance(field, str): # making a column replacement
266
+ try:
267
+ if column != field:
268
+ it[column] = pd.Series(df[field])
269
+ df.drop(field, axis="columns", inplace=True)
270
+ else:
271
+ it[column] = pd.Series(df[column])
272
+ df.drop(field, axis="columns", inplace=True)
273
+ continue
274
+ except KeyError:
275
+ self._logger.error(f"Column doesn't exists: {field}")
276
+ continue
277
+ elif isinstance(field, list):
278
+ col = field.pop(0)
279
+ if isinstance(col, list):
280
+ ### combine several columns into one
281
+ df[column] = df[col].apply("|".join, axis=1)
282
+ # is a list of columns:
283
+ try:
284
+ fname = field.pop(0)
285
+ try:
286
+ kwargs = field[0]
287
+ except IndexError:
288
+ kwargs = {}
289
+ try:
290
+ result = await self.call_function(
291
+ fname, df, df, column, args=kwargs
292
+ )
293
+ it[column] = df[column]
294
+ if self.replace_columns is True:
295
+ df.drop(column, axis="columns", inplace=True)
296
+ continue
297
+ except Exception:
298
+ pass
299
+ except IndexError:
300
+ # No other changes to made:
301
+ it[column] = df[column]
302
+ if self.replace_columns is True:
303
+ for c in col:
304
+ df.drop(c, axis="columns", inplace=True)
305
+ df.drop(column, axis="columns", inplace=True)
306
+ continue
307
+ if len(field) == 0:
308
+ if col in df.columns:
309
+ # there is no change to made:
310
+ # simple field replacement
311
+ it[column] = it[col]
312
+ else:
313
+ # calling an scalar function:
314
+ it[column] = await self.call_function(col, None, df, col)
315
+ continue
316
+ if len(field) > 0:
317
+ ### Calling a Function with(out) parameters
318
+ fname = field.pop(0)
319
+ try:
320
+ kwargs = field[0]
321
+ except IndexError:
322
+ kwargs = {}
323
+ # Call a Transformation Function on Dataframe:
324
+ self._logger.debug(
325
+ f"Calling {fname} with parameters: {kwargs}"
326
+ )
327
+ if col in df:
328
+ result = await self.call_function(fname, df, df, col, args=kwargs)
329
+ if col in result:
330
+ it[column] = result[col]
331
+ if self.replace_columns is True:
332
+ df.drop(col, axis="columns", inplace=True)
333
+ elif isinstance(field, dict):
334
+ # direct calling of Transform Function
335
+ val = list(field.keys())[0]
336
+ operation = field[val]
337
+ if val != "value":
338
+ fname = val
339
+ args = {}
340
+ if isinstance(operation[0], dict):
341
+ ## Operation doesn't have a column involved:
342
+ ## Or columns comes in arguments:
343
+ args = operation[0]
344
+ result = await self.call_function(
345
+ fname, df, df, column, args=args
346
+ )
347
+ it[column] = result[column]
348
+ df.drop(column, axis="columns", inplace=True)
349
+ continue
350
+ elif isinstance(operation[-1], dict):
351
+ args = operation.pop()
352
+ # all operation are arguments to fname:
353
+ # print('CALLING > ', fname, operation, args)
354
+ it[column] = await self.call_function(
355
+ fname, operation, df, column, args=args
356
+ )
357
+ else:
358
+ col = operation.pop(0) # name of column
359
+ try:
360
+ fname = operation.pop(0)
361
+ except IndexError:
362
+ ### there is not function to apply:
363
+ it[column] = result[col]
364
+ continue
365
+ try:
366
+ kwargs = operation[0]
367
+ except IndexError:
368
+ kwargs = {}
369
+ result = await self.call_function(fname, df, df, col, args=kwargs)
370
+ it[column] = result[col]
371
+ if self.replace_columns is True:
372
+ df.drop(col, axis="columns", inplace=True)
373
+ # Join the original DataFrame with the new columns
374
+ df = pd.concat([df, pd.DataFrame(it)], axis=1)
375
+ # Set the index of the new DataFrame
376
+ df.set_index(df.index, inplace=True)
377
+ if self._debug is True:
378
+ columns = list(df.columns)
379
+ print("=== tMap Columns ===")
380
+ for column in columns:
381
+ try:
382
+ t = df[column].dtype
383
+ except AttributeError:
384
+ raise ComponentError(f"Error Parsing Column {column}")
385
+ print(column, "->", t, "->", df[column].iloc[0])
386
+ print("===")
387
+ print(df)
388
+ # avoid threat the Dataframe as a Copy
389
+ df.is_copy = None
390
+ try:
391
+ self.add_metric("mapped_rows", df.shape[0])
392
+ self.add_metric("mapped_columns", df.shape[1])
393
+ except Exception as err: # pylint: disable=W0703
394
+ logging.error(f"TransformRows: Error setting Metrics: {err}")
395
+ return df
396
+
397
+ async def call_function(
398
+ self,
399
+ fname: str,
400
+ df: Union[pd.DataFrame, pd.Series, List[str]],
401
+ old_df: pd.DataFrame,
402
+ column: str,
403
+ args: Dict = None,
404
+ **kwargs,
405
+ ) -> Union[pd.DataFrame, pd.Series, None]:
406
+ logging.debug(
407
+ f"tMap: Calling {fname!s} for {column} with args: {args}/{kwargs}"
408
+ )
409
+ if isinstance(df, pd.Series):
410
+ try:
411
+ func = getattr(tmapfn, fname)
412
+ except AttributeError:
413
+ func = getFunction(fname)
414
+ elif isinstance(df, pd.DataFrame):
415
+ try:
416
+ func = self._get_df_function(fname)
417
+ except TypeError as exc:
418
+ raise ComponentError(f"Error on Function name: {fname}, {exc}") from exc
419
+ except AttributeError:
420
+ func = getFunction(fname)
421
+ elif isinstance(df, list):
422
+ try:
423
+ func = getattr(tmapfn, fname)
424
+ except AttributeError:
425
+ func = getFunction(fname)
426
+ else:
427
+ func = getFunction(fname)
428
+ if fname == "fill_column":
429
+ args["variables"] = self._variables
430
+ elif args is None:
431
+ args = {}
432
+ new_args = {**args, **kwargs}
433
+ if callable(func):
434
+ try:
435
+ if isinstance(df, pd.Series):
436
+ it = func(series=df, field=column, **new_args)
437
+ elif isinstance(df, pd.DataFrame):
438
+ it = func(df=df, field=column, **new_args)
439
+ elif isinstance(df, list):
440
+ it = func(old_df, df, **new_args)
441
+ else:
442
+ it = func(**new_args)
443
+ if np.isscalar(it):
444
+ it = pd.Series(it, index=old_df.index)
445
+ return it
446
+ except (ValueError, TypeError) as exc:
447
+ logging.warning(f"tMap: Error Calling function {func}: {exc}")
448
+ else:
449
+ logging.warning(f"tMap: Function {func} is not callable.")
450
+ return df
@@ -0,0 +1,112 @@
1
+ import asyncio
2
+ from typing import Any
3
+ from collections.abc import Callable
4
+ import pandas as pd
5
+ from querysource.exceptions import DriverError, QueryException
6
+ from ..exceptions import ComponentError
7
+ from .flow import FlowComponent
8
+
9
+
10
+ class tMelt(FlowComponent):
11
+ """
12
+ tMelt
13
+
14
+ Overview
15
+
16
+ The tMelt class is a component for transforming a DataFrame from a wide format to a long format using the
17
+ Pandas `melt` function. It reshapes data by unpivoting columns, making it easier to analyze or process data
18
+ with a simpler, long-form structure.
19
+
20
+ .. table:: Properties
21
+ :widths: auto
22
+
23
+ +----------------+----------+-----------+---------------------------------------------------------------+
24
+ | Name | Required | Summary |
25
+ +----------------+----------+-----------+---------------------------------------------------------------+
26
+ | index | Yes | Column(s) to use as identifier variables for melting. |
27
+ +----------------+----------+-----------+---------------------------------------------------------------+
28
+ | name | No | Name to use for the "variable" column in the result DataFrame. |
29
+ | | | Defaults to "name". |
30
+ +----------------+----------+-----------+---------------------------------------------------------------+
31
+ | value | No | Name to use for the "value" column in the result DataFrame. |
32
+ | | | Defaults to "value". |
33
+ +----------------+----------+-----------+---------------------------------------------------------------+
34
+ | values | No | List of columns to unpivot. If None, all remaining columns are used. |
35
+ +----------------+----------+-----------+---------------------------------------------------------------+
36
+
37
+ Returns
38
+
39
+ This component returns a DataFrame in long format where specified columns are unpivoted to create two
40
+ new columns: one for variable names (`name`) and one for values (`value`). Metrics on the row and column
41
+ counts of the transformed DataFrame are recorded. Any errors during transformation are logged and raised
42
+ with descriptive error messages.
43
+
44
+
45
+ Example:
46
+
47
+ ```yaml
48
+ tMelt:
49
+ index:
50
+ - AL No.
51
+ - Store Format
52
+ name: product_name
53
+ value: displays_quantity
54
+ ```
55
+
56
+ """ #noqa
57
+
58
+ def __init__(
59
+ self,
60
+ loop: asyncio.AbstractEventLoop = None,
61
+ job: Callable = None,
62
+ stat: Callable = None,
63
+ **kwargs,
64
+ ):
65
+ """Init Method."""
66
+ self.df1: Any = None
67
+ self.df2: Any = None
68
+ self.type = None
69
+ super(tMelt, self).__init__(loop=loop, job=job, stat=stat, **kwargs)
70
+
71
+ async def start(self, **kwargs):
72
+ if self.previous:
73
+ self.data = self.input
74
+ else:
75
+ raise ComponentError("Data Not Found", status=404)
76
+ if not isinstance(self.data, pd.DataFrame):
77
+ raise ComponentError("Incompatible Pandas Dataframe", status=404)
78
+ if not hasattr(self, "index"):
79
+ raise DriverError("Crosstab Transform: Missing Index on definition")
80
+ if not hasattr(self, "name"):
81
+ self.name = "name"
82
+ if not hasattr(self, "value"):
83
+ self.name = "value"
84
+
85
+ if not hasattr(self, "values"):
86
+ self.values = None
87
+
88
+ return True
89
+
90
+ async def close(self):
91
+ pass
92
+
93
+ async def run(self):
94
+ try:
95
+ df = pd.melt(
96
+ self.data, id_vars=self.index, var_name=self.name, value_name=self.value
97
+ )
98
+ self._result = df
99
+ self.add_metric("NUM_ROWS", self._result.shape[0])
100
+ self.add_metric("NUM_COLUMNS", self._result.shape[1])
101
+ if self._debug:
102
+ print("Debugging: tCrosstab ===")
103
+ print(self._result)
104
+ columns = list(self._result.columns)
105
+ for column in columns:
106
+ t = self._result[column].dtype
107
+ print(column, "->", t, "->", self._result[column].iloc[0])
108
+ return self._result
109
+ except (ValueError, KeyError) as err:
110
+ raise QueryException(f"Crosstab Error: {err!s}") from err
111
+ except Exception as err:
112
+ raise QueryException(f"Unknown error {err!s}") from err
@@ -0,0 +1,114 @@
1
+ import asyncio
2
+ import pandas as pd
3
+ from typing import Any
4
+ from collections.abc import Callable
5
+ from querysource.exceptions import QueryException
6
+ from ..exceptions import ComponentError
7
+ from .flow import FlowComponent
8
+
9
+
10
+ class tMerge(FlowComponent):
11
+ """
12
+ tMerge
13
+
14
+ Overview
15
+
16
+ The tMerge class is a component for merging two DataFrames (or named Series objects) using a database-style join.
17
+ It supports different join types such as 'inner', 'outer', 'left', 'right', and 'cross', allowing flexible merging
18
+ configurations for complex data workflows.
19
+
20
+ .. table:: Properties
21
+ :widths: auto
22
+
23
+ +------------------+----------+-----------+---------------------------------------------------------------+
24
+ | Name | Required | Summary |
25
+ +------------------+----------+-----------+---------------------------------------------------------------+
26
+ | df1 | Yes | The left DataFrame to join. |
27
+ +------------------+----------+-----------+---------------------------------------------------------------+
28
+ | df2 | Yes | The right DataFrame to join. |
29
+ +------------------+----------+-----------+---------------------------------------------------------------+
30
+ | type | No | The type of join to perform (e.g., 'inner', 'outer'). Defaults to 'cross'.|
31
+ +------------------+----------+-----------+---------------------------------------------------------------+
32
+ | pd_args | No | Additional arguments for the Pandas merge function, if any. |
33
+ +------------------+----------+-----------+---------------------------------------------------------------+
34
+
35
+ Returns
36
+
37
+ This component returns a DataFrame created by merging `df1` and `df2` based on the specified join type and arguments.
38
+ It records metrics for the resulting DataFrame’s row and column counts. Any errors during merging are raised
39
+ with detailed error messages, and additional debug information is available if debugging mode is enabled.
40
+
41
+
42
+ Example:
43
+
44
+ ```yaml
45
+ tMerge:
46
+ depends:
47
+ - QueryToPandas_1
48
+ - QueryToPandas_2
49
+ type: cross
50
+ ```
51
+
52
+ """ #noqa
53
+
54
+ def __init__(
55
+ self,
56
+ loop: asyncio.AbstractEventLoop = None,
57
+ job: Callable = None,
58
+ stat: Callable = None,
59
+ **kwargs,
60
+ ):
61
+ """Init Method."""
62
+ self.df1: Any = None
63
+ self.df2: Any = None
64
+ self.type = kwargs.pop('type', 'cross')
65
+ super(tMerge, self).__init__(loop=loop, job=job, stat=stat, **kwargs)
66
+
67
+ async def start(self, **kwargs):
68
+ if self.previous:
69
+ self.data = self.input
70
+ else:
71
+ raise ComponentError("Data Not Found")
72
+ try:
73
+ self.df1 = self.previous[0].output()
74
+ except IndexError as ex:
75
+ name = self.depends[0]
76
+ raise ComponentError(
77
+ f"Missing LEFT Dataframe: {name}"
78
+ ) from ex
79
+ try:
80
+ self.df2 = self.previous[1].output()
81
+ except IndexError as ex:
82
+ name = self.depends[1]
83
+ raise ComponentError(
84
+ "Missing RIGHT Dataframe"
85
+ ) from ex
86
+ return True
87
+
88
+ async def close(self):
89
+ pass
90
+
91
+ async def run(self):
92
+ try:
93
+ if hasattr(self, "pd_args"):
94
+ args = self.pd_args
95
+ else:
96
+ args = {}
97
+ df = pd.merge(self.df1, self.df2, how=self.type, **args)
98
+ self._result = df
99
+ self.add_metric("NUM_ROWS", self._result.shape[0])
100
+ self.add_metric("NUM_COLUMNS", self._result.shape[1])
101
+ if self._debug:
102
+ print("Debugging: tMerge ===")
103
+ print(self._result)
104
+ columns = list(self._result.columns)
105
+ for column in columns:
106
+ t = self._result[column].dtype
107
+ print(
108
+ column, "->", t, "->", self._result[column].iloc[0]
109
+ )
110
+ return self._result
111
+ except (ValueError, KeyError) as err:
112
+ raise ComponentError(f"tMerge Error: {err!s}") from err
113
+ except Exception as err:
114
+ raise ComponentError(f"tMerge error {err!s}") from err