flowtask 5.2.12__tar.gz → 5.3.3__tar.gz

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 (328) hide show
  1. {flowtask-5.2.12 → flowtask-5.3.3}/Makefile +4 -3
  2. {flowtask-5.2.12 → flowtask-5.3.3}/PKG-INFO +12 -11
  3. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/__init__.py +6 -1
  4. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/__main__.py +5 -6
  5. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/AddDataset.py +89 -111
  6. flowtask-5.3.3/flowtask/components/AutoTask.py +226 -0
  7. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/Azure.py +12 -17
  8. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/AzureUsers.py +20 -25
  9. flowtask-5.3.3/flowtask/components/BaseAction.py +72 -0
  10. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/Boto3Client.py +26 -43
  11. flowtask-5.3.3/flowtask/components/CopyTo.py +57 -0
  12. flowtask-5.3.3/flowtask/components/CopyToPg.py +369 -0
  13. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/CreateReport/CreateReport.py +43 -77
  14. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/CreateReport/charts/__init__.py +4 -4
  15. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/CreateReport/charts/bar.py +11 -25
  16. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/CreateReport/charts/base.py +11 -16
  17. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/CreateReport/charts/pie.py +11 -18
  18. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/CreateReport/utils.py +1 -0
  19. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/DataInput.py +32 -49
  20. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/DateList.py +53 -64
  21. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/DbClient.py +43 -65
  22. flowtask-5.3.3/flowtask/components/DialPad.py +80 -0
  23. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/DownloadFrom.py +133 -131
  24. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/DownloadFromFTP.py +38 -60
  25. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/DownloadFromIMAP.py +94 -112
  26. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/DownloadFromS3.py +61 -88
  27. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/DownloadFromSFTP.py +60 -95
  28. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/DownloadFromSharepoint.py +16 -30
  29. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/DownloadFromSmartSheet.py +28 -42
  30. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/DropboxClient.py +1 -1
  31. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/Dummy.py +4 -3
  32. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/Excel365.py +2 -0
  33. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/ExecuteSQL.py +65 -122
  34. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/FTPClient.py +42 -52
  35. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/FileBase.py +42 -52
  36. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/FileCopy.py +29 -45
  37. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/FileDelete.py +5 -3
  38. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/FileExists.py +32 -49
  39. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/FileIteratorDelete.py +11 -16
  40. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/FileList.py +20 -26
  41. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/FileOpen.py +11 -13
  42. flowtask-5.3.3/flowtask/components/FileRename.py +68 -0
  43. flowtask-5.3.3/flowtask/components/FilterRows/FilterRows.py +150 -0
  44. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/FilterRows/functions.py +29 -14
  45. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/GoogleA4.py +25 -25
  46. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/GoogleClient.py +1 -1
  47. flowtask-5.3.3/flowtask/components/GoogleGeoCoding.py +137 -0
  48. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/HTTPClient.py +205 -354
  49. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/ICIMS.py +15 -32
  50. flowtask-5.3.3/flowtask/components/IMAPClient.py +145 -0
  51. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/IteratorBase.py +47 -38
  52. flowtask-5.3.3/flowtask/components/MS365Usage.py +87 -0
  53. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/MergeFiles.py +73 -82
  54. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/O365Client.py +24 -36
  55. flowtask-5.3.3/flowtask/components/Odoo.py +117 -0
  56. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/OneDrive.py +2 -0
  57. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/OpenFromXML.py +19 -31
  58. flowtask-5.3.3/flowtask/components/OpenWeather.py +41 -0
  59. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/OpenWithBase.py +188 -207
  60. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/OpenWithPandas.py +157 -189
  61. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/PGPDecrypt.py +31 -50
  62. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/PandasIterator.py +27 -41
  63. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/PandasToFile.py +38 -52
  64. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/ParamIterator.py +7 -11
  65. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/PrintMessage.py +19 -28
  66. flowtask-5.3.3/flowtask/components/QS.py +213 -0
  67. flowtask-5.3.3/flowtask/components/QSBase.py +185 -0
  68. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/QueryIterator.py +56 -105
  69. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/QueryToInsert.py +133 -91
  70. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/QueryToPandas.py +133 -214
  71. flowtask-5.3.3/flowtask/components/RESTClient.py +142 -0
  72. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/Rsync.py +27 -35
  73. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/RunSSH.py +12 -25
  74. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/RunShell.py +12 -13
  75. flowtask-5.3.3/flowtask/components/SalesForce.py +20 -0
  76. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/SendNotify.py +37 -62
  77. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/SetVariables.py +30 -24
  78. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/Sharepoint.py +48 -28
  79. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/SubTask.py +29 -32
  80. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/SuiteCRM.py +7 -13
  81. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/TableBase.py +43 -52
  82. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/TableDelete.py +69 -116
  83. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/TableInput.py +21 -25
  84. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/TableOutput/TableOutput.py +66 -107
  85. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/TableOutput/__init__.py +1 -1
  86. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/TableOutput/mysql.py +33 -48
  87. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/TableOutput/postgres.py +26 -45
  88. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/TableOutput/sa.py +28 -42
  89. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/TableSchema.py +115 -128
  90. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/TransformRows/TransformRows.py +69 -92
  91. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/TransformRows/functions.py +570 -296
  92. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/TransposeRows.py +27 -52
  93. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/UPCDatabase.py +24 -29
  94. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/Uncompress.py +27 -49
  95. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/UniqueRows.py +30 -40
  96. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/UpdateOperationalVars.py +17 -23
  97. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/UploadTo.py +68 -101
  98. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/UploadToS3.py +38 -55
  99. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/UploadToSFTP.py +34 -53
  100. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/UserFunc.py +17 -36
  101. flowtask-5.3.3/flowtask/components/VivaTracker.py +123 -0
  102. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/WSDLClient.py +26 -32
  103. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/Wait.py +1 -1
  104. flowtask-5.3.3/flowtask/components/Workplace.py +134 -0
  105. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/XMLToPandas.py +56 -69
  106. flowtask-5.3.3/flowtask/components/Zammad/__init__.py +22 -0
  107. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/__init__.py +18 -20
  108. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/abstract.py +204 -108
  109. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/azureauth.py +14 -18
  110. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/group.py +44 -74
  111. flowtask-5.3.3/flowtask/components/interfaces/ASPX.py +136 -0
  112. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/interfaces/AzureClient.py +31 -31
  113. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/interfaces/SSHClient.py +109 -170
  114. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/interfaces/__init__.py +4 -1
  115. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/interfaces/client.py +34 -36
  116. flowtask-5.3.3/flowtask/components/interfaces/dataframes/__init__.py +11 -0
  117. flowtask-5.3.3/flowtask/components/interfaces/dataframes/abstract.py +34 -0
  118. flowtask-5.3.3/flowtask/components/interfaces/dataframes/arrow.py +74 -0
  119. flowtask-5.3.3/flowtask/components/interfaces/dataframes/dt.py +72 -0
  120. flowtask-5.3.3/flowtask/components/interfaces/dataframes/pandas.py +109 -0
  121. flowtask-5.3.3/flowtask/components/interfaces/dataframes/polars.py +63 -0
  122. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/interfaces/db.py +52 -59
  123. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/interfaces/http.py +244 -333
  124. flowtask-5.3.3/flowtask/components/interfaces/zammad.py +80 -0
  125. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/support/__init__.py +7 -7
  126. flowtask-5.3.3/flowtask/components/support/db.py +87 -0
  127. flowtask-5.3.3/flowtask/components/support/func.py +113 -0
  128. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/support/locale.py +9 -8
  129. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/support/log.py +25 -30
  130. flowtask-5.3.3/flowtask/components/support/qs.py +232 -0
  131. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/support/result.py +10 -17
  132. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/support/stat.py +4 -8
  133. flowtask-5.3.3/flowtask/components/support/template.py +82 -0
  134. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/tConcat.py +21 -34
  135. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/tExplode.py +24 -41
  136. flowtask-5.3.3/flowtask/components/tFilter.py +154 -0
  137. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/tGroup.py +15 -19
  138. flowtask-5.3.3/flowtask/components/tJoin.py +199 -0
  139. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/tMap/functions.py +9 -6
  140. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/tMap/tMap.py +96 -121
  141. flowtask-5.3.3/flowtask/components/tMelt.py +65 -0
  142. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/tPluckCols.py +10 -15
  143. flowtask-5.3.3/flowtask/components/tUnnest.py +76 -0
  144. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/user.py +83 -142
  145. flowtask-5.3.3/flowtask/conf.py +305 -0
  146. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/download.py +18 -24
  147. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/events/__init__.py +4 -4
  148. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/events/events/__init__.py +13 -13
  149. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/events/events/abstract.py +12 -20
  150. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/events/events/alerts/__init__.py +16 -38
  151. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/events/events/alerts/colfunctions.py +6 -15
  152. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/events/events/alerts/functions.py +6 -8
  153. flowtask-5.3.3/flowtask/events/events/dummy.py +12 -0
  154. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/events/events/exec.py +22 -29
  155. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/events/events/file/__init__.py +2 -2
  156. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/events/events/file/base.py +18 -24
  157. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/events/events/file/copy.py +2 -1
  158. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/events/events/file/delete.py +2 -6
  159. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/events/events/interfaces/__init__.py +3 -3
  160. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/events/events/interfaces/client.py +15 -31
  161. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/events/events/interfaces/credentials.py +9 -18
  162. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/events/events/interfaces/notifications.py +13 -19
  163. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/events/events/log.py +7 -8
  164. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/events/events/logerr.py +10 -16
  165. flowtask-5.3.3/flowtask/events/events/notify.py +59 -0
  166. flowtask-5.3.3/flowtask/events/events/notify_event.py +160 -0
  167. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/events/events/publish.py +9 -11
  168. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/events/events/sendfile.py +21 -42
  169. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/events/events/task.py +18 -26
  170. flowtask-5.3.3/flowtask/events/events/teams.py +66 -0
  171. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/events/events/webhook.py +18 -19
  172. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/events/manager.py +89 -96
  173. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/exceptions.c +30 -41
  174. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/extensions/__init__.py +1 -1
  175. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/extensions/abstract.py +5 -6
  176. flowtask-5.3.3/flowtask/extensions/logging/__init__.py +65 -0
  177. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/hooks/actions/__init__.py +5 -5
  178. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/hooks/actions/abstract.py +9 -9
  179. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/hooks/actions/dummy.py +3 -4
  180. flowtask-5.3.3/flowtask/hooks/actions/jira.py +45 -0
  181. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/hooks/actions/rest.py +80 -101
  182. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/hooks/actions/task.py +1 -0
  183. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/hooks/actions/ticket.py +7 -10
  184. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/hooks/actions/zammad.py +18 -25
  185. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/hooks/interfaces/__init__.py +4 -4
  186. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/hooks/interfaces/cache.py +33 -77
  187. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/hooks/interfaces/client.py +18 -39
  188. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/hooks/interfaces/env.py +2 -5
  189. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/hooks/interfaces/log.py +19 -25
  190. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/hooks/interfaces/mask.py +6 -6
  191. flowtask-5.3.3/flowtask/hooks/interfaces/masks.py +69 -0
  192. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/hooks/interfaces/message.py +47 -84
  193. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/hooks/interfaces/task.py +19 -32
  194. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/hooks/interfaces/templates.py +8 -12
  195. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/hooks/service.py +46 -45
  196. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/hooks/types/__init__.py +7 -7
  197. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/hooks/types/base.py +9 -19
  198. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/hooks/types/fs.py +25 -38
  199. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/hooks/types/http.py +5 -8
  200. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/hooks/types/imap.py +39 -52
  201. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/hooks/types/responses/__init__.py +1 -1
  202. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/hooks/types/responses/base.py +0 -1
  203. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/hooks/types/ssh.py +15 -25
  204. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/hooks/types/tagged.py +17 -22
  205. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/hooks/types/upload.py +4 -3
  206. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/hooks/types/watch.py +13 -18
  207. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/hooks/types/web.py +5 -10
  208. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/models.py +67 -90
  209. flowtask-5.3.3/flowtask/parsers/__init__.py +15 -0
  210. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/parsers/_yaml.c +88 -99
  211. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/parsers/argparser.py +46 -56
  212. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/parsers/base.c +95 -106
  213. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/parsers/json.c +88 -99
  214. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/parsers/maps.py +18 -17
  215. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/parsers/toml.c +88 -99
  216. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/plugins/__init__.py +3 -3
  217. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/plugins/handler/__init__.py +9 -9
  218. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/plugins/importer.py +4 -3
  219. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/runner.py +40 -62
  220. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/scheduler/__init__.py +1 -1
  221. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/scheduler/functions.py +95 -139
  222. flowtask-5.3.3/flowtask/scheduler/handlers/__init__.py +8 -0
  223. flowtask-5.3.3/flowtask/scheduler/handlers/manager.py +497 -0
  224. flowtask-5.3.3/flowtask/scheduler/handlers/models.py +58 -0
  225. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/scheduler/handlers/service.py +15 -24
  226. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/scheduler/notifications.py +21 -23
  227. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/scheduler/scheduler.py +289 -341
  228. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/services/tasks/__init__.py +1 -7
  229. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/services/tasks/launcher.py +54 -97
  230. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/services/tasks/manager.py +34 -28
  231. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/services/tasks/service.py +48 -110
  232. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/services/tasks/task_manager.py +77 -100
  233. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/services/tasks/tasks.py +39 -72
  234. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/tasks/abstract.py +91 -147
  235. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/tasks/command.py +15 -26
  236. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/tasks/files/__init__.py +1 -1
  237. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/tasks/files/abstract.py +6 -9
  238. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/tasks/files/filesystem.py +14 -11
  239. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/tasks/pile.py +97 -58
  240. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/tasks/storages/__init__.py +6 -1
  241. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/tasks/storages/abstract.py +3 -11
  242. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/tasks/storages/database.py +7 -8
  243. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/tasks/storages/filesystem.py +34 -52
  244. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/tasks/storages/github.py +22 -26
  245. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/tasks/storages/row.py +3 -7
  246. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/tasks/task.py +157 -265
  247. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/template/__init__.py +36 -39
  248. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/tests.py +31 -19
  249. flowtask-5.3.3/flowtask/types/__init__.py +8 -0
  250. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/types/typedefs.c +38 -48
  251. flowtask-5.3.3/flowtask/utils/__init__.py +24 -0
  252. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/utils/constants.py +10 -8
  253. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/utils/encoders.py +2 -1
  254. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/utils/executor.py +31 -29
  255. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/utils/functions.cpp +61 -70
  256. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/utils/json.cpp +99 -110
  257. flowtask-5.3.3/flowtask/utils/mail.py +63 -0
  258. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/utils/parseqs.c +125 -135
  259. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/utils/stats.py +27 -41
  260. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/utils/uv.py +3 -1
  261. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/utils/validators.py +11 -3
  262. flowtask-5.3.3/flowtask/version.py +11 -0
  263. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask.egg-info/PKG-INFO +12 -11
  264. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask.egg-info/SOURCES.txt +23 -2
  265. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask.egg-info/entry_points.txt +0 -1
  266. flowtask-5.3.3/flowtask.egg-info/requires.txt +34 -0
  267. {flowtask-5.2.12 → flowtask-5.3.3}/pyproject.toml +1 -1
  268. flowtask-5.3.3/resources/__init__.py +0 -0
  269. flowtask-5.3.3/resources/image.py +269 -0
  270. {flowtask-5.2.12 → flowtask-5.3.3}/setup.py +19 -22
  271. flowtask-5.2.12/flowtask/components/CopyTo.py +0 -8
  272. flowtask-5.2.12/flowtask/components/CopyToPg.py +0 -501
  273. flowtask-5.2.12/flowtask/components/FileRename.py +0 -84
  274. flowtask-5.2.12/flowtask/components/FilterRows/FilterRows.py +0 -139
  275. flowtask-5.2.12/flowtask/components/IMAPClient.py +0 -179
  276. flowtask-5.2.12/flowtask/components/QSBase.py +0 -244
  277. flowtask-5.2.12/flowtask/components/RESTBase.py +0 -63
  278. flowtask-5.2.12/flowtask/components/RESTClient.py +0 -182
  279. flowtask-5.2.12/flowtask/components/SalesForce.py +0 -25
  280. flowtask-5.2.12/flowtask/components/Workplace.py +0 -139
  281. flowtask-5.2.12/flowtask/components/support/db.py +0 -105
  282. flowtask-5.2.12/flowtask/components/support/func.py +0 -106
  283. flowtask-5.2.12/flowtask/components/support/template.py +0 -34
  284. flowtask-5.2.12/flowtask/components/tFilter.py +0 -112
  285. flowtask-5.2.12/flowtask/components/tJoin.py +0 -178
  286. flowtask-5.2.12/flowtask/components/tMelt.py +0 -84
  287. flowtask-5.2.12/flowtask/conf.py +0 -316
  288. flowtask-5.2.12/flowtask/events/events/dummy.py +0 -12
  289. flowtask-5.2.12/flowtask/events/events/notify.py +0 -67
  290. flowtask-5.2.12/flowtask/events/events/notify_event.py +0 -127
  291. flowtask-5.2.12/flowtask/events/events/teams.py +0 -78
  292. flowtask-5.2.12/flowtask/extensions/logging/__init__.py +0 -82
  293. flowtask-5.2.12/flowtask/hooks/actions/jira.py +0 -59
  294. flowtask-5.2.12/flowtask/hooks/interfaces/masks.py +0 -42
  295. flowtask-5.2.12/flowtask/parsers/__init__.py +0 -11
  296. flowtask-5.2.12/flowtask/scheduler/handlers/__init__.py +0 -8
  297. flowtask-5.2.12/flowtask/scheduler/handlers/manager.py +0 -436
  298. flowtask-5.2.12/flowtask/types/__init__.py +0 -9
  299. flowtask-5.2.12/flowtask/utils/__init__.py +0 -30
  300. flowtask-5.2.12/flowtask/utils/_functions.py +0 -552
  301. flowtask-5.2.12/flowtask/utils/mail.py +0 -49
  302. flowtask-5.2.12/flowtask/version.py +0 -9
  303. flowtask-5.2.12/flowtask.egg-info/requires.txt +0 -37
  304. {flowtask-5.2.12 → flowtask-5.3.3}/CONTRIBUTING.md +0 -0
  305. {flowtask-5.2.12 → flowtask-5.3.3}/INSTALL +0 -0
  306. {flowtask-5.2.12 → flowtask-5.3.3}/LICENSE +0 -0
  307. {flowtask-5.2.12 → flowtask-5.3.3}/MANIFEST.in +0 -0
  308. {flowtask-5.2.12 → flowtask-5.3.3}/README.md +0 -0
  309. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/CreateReport/__init__.py +0 -0
  310. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/FilterRows/__init__.py +0 -0
  311. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/TransformRows/__init__.py +0 -0
  312. /flowtask-5.2.12/flowtask/components/py.typed → /flowtask-5.3.3/flowtask/components/Zammad/models.py +0 -0
  313. /flowtask-5.2.12/flowtask/plugins/components/__init__.py → /flowtask-5.3.3/flowtask/components/py.typed +0 -0
  314. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/components/tMap/__init__.py +0 -0
  315. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask/hooks/__init__.py +0 -0
  316. {flowtask-5.2.12/flowtask/plugins/sources → flowtask-5.3.3/flowtask/plugins/components}/__init__.py +0 -0
  317. {flowtask-5.2.12/flowtask/services → flowtask-5.3.3/flowtask/plugins/sources}/__init__.py +0 -0
  318. {flowtask-5.2.12/flowtask/tasks → flowtask-5.3.3/flowtask/services}/__init__.py +0 -0
  319. {flowtask-5.2.12/resources → flowtask-5.3.3/flowtask/tasks}/__init__.py +0 -0
  320. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask.egg-info/dependency_links.txt +0 -0
  321. {flowtask-5.2.12 → flowtask-5.3.3}/flowtask.egg-info/top_level.txt +0 -0
  322. {flowtask-5.2.12 → flowtask-5.3.3}/plugins/__init__.py +0 -0
  323. {flowtask-5.2.12 → flowtask-5.3.3}/resources/auth.py +0 -0
  324. {flowtask-5.2.12 → flowtask-5.3.3}/resources/functions.py +0 -0
  325. {flowtask-5.2.12 → flowtask-5.3.3}/resources/users/__init__.py +0 -0
  326. {flowtask-5.2.12 → flowtask-5.3.3}/resources/users/models.py +0 -0
  327. {flowtask-5.2.12 → flowtask-5.3.3}/resources/version.py +0 -0
  328. {flowtask-5.2.12 → flowtask-5.3.3}/setup.cfg +0 -0
@@ -1,5 +1,5 @@
1
1
  venv:
2
- python3.10 -m venv .venv
2
+ python3.11 -m venv .venv
3
3
  echo 'run `source .venv/bin/activate` to start develop FlowTask'
4
4
 
5
5
  install:
@@ -11,14 +11,15 @@ install:
11
11
  pip install --upgrade navigator-auth
12
12
  pip install --upgrade async-notify[all]
13
13
  pip install --upgrade querysource
14
- # dev
15
- python -m pip install -Ur docs/requirements-dev.txt
16
14
  # Install extra resources
17
15
  pip install --upgrade qworker
18
16
  # install FlowTask
19
17
  pip install -e .
20
18
  echo 'start develop FlowTask'
21
19
 
20
+ develop:
21
+ pip install -Ur docs/requirements-dev.txt
22
+
22
23
  compile:
23
24
  python setup.py build_ext --inplace
24
25
 
@@ -1,27 +1,30 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: flowtask
3
- Version: 5.2.12
3
+ Version: 5.3.3
4
4
  Summary: Framework for running Tasks and from CLI and API for orchestation. Component-based Task builder/Runner for non-programmers.
5
5
  Home-page: https://github.com/phenobarbital/flowtask
6
6
  Author: Jesus Lara
7
- Author-email: jlara@trocglobal.com
8
- License: Apache License 2.0
7
+ Author-email: "Jesus Lara G." <jesuslarag@gmail.com>
8
+ License: Apache-2.0
9
9
  Project-URL: Source, https://github.com/phenobarbital/flowtask
10
10
  Project-URL: Funding, https://paypal.me/phenobarbital
11
11
  Project-URL: Say Thanks!, https://saythanks.io/to/phenobarbital
12
- Keywords: DataIntegration DataIntegration Task Orchestation Framework Task-Runner,Pipelines
12
+ Keywords: DataIntegration,Task,Orchestation,Task-Runner,Pipelines,Data-Pipelines
13
13
  Platform: *nix
14
14
  Classifier: Development Status :: 4 - Beta
15
15
  Classifier: Intended Audience :: Developers
16
+ Classifier: Intended Audience :: System Administrators
17
+ Classifier: Operating System :: OS Independent
18
+ Classifier: Programming Language :: Python :: 3.9
19
+ Classifier: Programming Language :: Python
20
+ Classifier: Typing :: Typed
21
+ Classifier: Development Status :: 4 - Beta
22
+ Classifier: Environment :: Web Environment
23
+ Classifier: Framework :: AsyncIO
16
24
  Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
17
25
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
18
26
  Classifier: Topic :: Software Development :: Build Tools
19
- Classifier: Topic :: Utilities
20
- Classifier: Programming Language :: Python :: 3.9
21
- Classifier: Programming Language :: Python :: 3.10
22
- Classifier: Programming Language :: Python :: 3.11
23
27
  Classifier: License :: OSI Approved :: BSD License
24
- Classifier: Framework :: AsyncIO
25
28
  Requires-Python: >=3.9.16
26
29
  Description-Content-Type: text/markdown
27
30
  License-File: LICENSE
@@ -112,5 +115,3 @@ Please have a look at the Contribution Guide
112
115
  ### License ###
113
116
 
114
117
  Navigator is licensed under Apache 2.0 License. See the LICENSE file for more details.
115
-
116
-
@@ -5,9 +5,14 @@ Navigator Data-Integration.
5
5
  Tool for execution of Tasks.
6
6
  """
7
7
  from .version import (
8
- __title__, __description__, __version__, __author__, __author_email__
8
+ __title__,
9
+ __description__,
10
+ __version__,
11
+ __author__,
12
+ __author_email__,
9
13
  )
10
14
 
15
+
11
16
  def version():
12
17
  """version.
13
18
  Returns:
@@ -24,16 +24,15 @@ def main():
24
24
  loop = asyncio.get_event_loop()
25
25
  loop.slow_callback_duration = 0.5 # Set threshold to 0.5 seconds
26
26
  # try:
27
- result = loop.run_until_complete(
28
- task(loop)
29
- )
27
+ result = loop.run_until_complete(task(loop))
30
28
  if result:
31
- cPrint(' === RESULT === ', level="DEBUG")
29
+ cPrint(" === RESULT === ", level="DEBUG")
32
30
  print(result.result)
33
- cPrint('== Task stats === ', level="INFO")
31
+ cPrint("== Task stats === ", level="INFO")
34
32
  print(result.stats)
35
33
  # finally:
36
34
  # loop.close()
37
35
 
38
- if __name__ == '__main__':
36
+
37
+ if __name__ == "__main__":
39
38
  main()
@@ -2,15 +2,9 @@ import asyncio
2
2
  from collections.abc import Callable
3
3
  import numpy as np
4
4
  import pandas as pd
5
- from asyncdb.exceptions import (
6
- NoDataFound
7
- )
8
- from flowtask.exceptions import (
9
- ComponentError,
10
- DataNotFound,
11
- TaskError
12
- )
13
- from flowtask.utils import cPrint
5
+ from asyncdb.exceptions import NoDataFound
6
+ from ..exceptions import ComponentError, DataNotFound, TaskError
7
+ from ..utils import cPrint
14
8
  from .abstract import DtComponent
15
9
 
16
10
 
@@ -19,25 +13,24 @@ class AddDataset(DtComponent):
19
13
 
20
14
  Join two Datasets based on some criteria.
21
15
  """
16
+
22
17
  df1 = None
23
18
  df2 = None
24
19
 
25
20
  def __init__(
26
- self,
27
- loop: asyncio.AbstractEventLoop = None,
28
- job: Callable = None,
29
- stat: Callable = None,
30
- **kwargs
21
+ self,
22
+ loop: asyncio.AbstractEventLoop = None,
23
+ job: Callable = None,
24
+ stat: Callable = None,
25
+ **kwargs,
31
26
  ) -> None:
32
27
  """Init Method."""
33
- self.type: str = 'left'
28
+ self.type: str = "left"
34
29
  self._dtypes: dict = {}
35
30
  self.infer_types: bool = False
36
31
  self.to_string: bool = True
37
32
  self.as_objects: bool = False
38
- super(AddDataset, self).__init__(
39
- loop=loop, job=job, stat=stat, **kwargs
40
- )
33
+ super(AddDataset, self).__init__(loop=loop, job=job, stat=stat, **kwargs)
41
34
 
42
35
  async def start(self, **kwargs):
43
36
  """Obtain Pandas Dataframe."""
@@ -49,22 +42,18 @@ class AddDataset(DtComponent):
49
42
  else:
50
43
  self.df1 = self.previous.output()
51
44
  except IndexError as ex:
52
- raise ComponentError(
53
- "Missing LEFT Dataframe"
54
- ) from ex
45
+ raise ComponentError("Missing LEFT Dataframe") from ex
55
46
  ### check info for creating the second dataset:
56
47
  self.df2 = None
57
- if not hasattr(self, 'fields'):
58
- raise TaskError(
59
- "Wrong Task configuration: need *fields* declaration."
60
- )
61
- if not hasattr(self, 'dataset'):
48
+ if not hasattr(self, "fields"):
49
+ raise TaskError("Wrong Task configuration: need *fields* declaration.")
50
+ if not hasattr(self, "dataset"):
62
51
  raise TaskError(
63
52
  "Wrong Task configuration: need *dataset* name declaration."
64
53
  )
65
- if not hasattr(self, 'datasource'):
66
- self.datasource = 'datasets'
67
- if self.datasource in ('datasets', 'vision'):
54
+ if not hasattr(self, "datasource"):
55
+ self.datasource = "datasets"
56
+ if self.datasource in ("datasets", "vision"):
68
57
  # using current datasets on pg database
69
58
  self.connection = self.pg_connection()
70
59
  else:
@@ -75,25 +64,21 @@ class AddDataset(DtComponent):
75
64
  async def run(self):
76
65
  args = {}
77
66
  if self.df1.empty:
78
- raise DataNotFound(
79
- "Data Was Not Found on Dataframe 1"
80
- )
67
+ raise DataNotFound("Data Was Not Found on Dataframe 1")
81
68
  ## getting second dataset:
82
69
  try:
83
70
  ### TODO: instrumentation for getting dataset from different sources
84
71
  async with await self.connection.connection() as conn:
85
- fields = ', '.join(self.fields)
86
- if hasattr(self, 'distinct'):
87
- join = ', '.join(self.join)
72
+ fields = ", ".join(self.fields)
73
+ if hasattr(self, "distinct"):
74
+ join = ", ".join(self.join)
88
75
  query = f"SELECT DISTINCT ON ({join}) {fields} FROM {self.datasource}.{self.dataset}"
89
76
  else:
90
77
  query = f"SELECT {fields} FROM {self.datasource}.{self.dataset}"
91
- self._logger.info(f'DATASET QUERY: {query}')
78
+ self._logger.info(f"DATASET QUERY: {query}")
92
79
  result, error = await conn.query(query)
93
80
  if error or not result:
94
- raise DataNotFound(
95
- "Empty Dataset"
96
- )
81
+ raise DataNotFound("Empty Dataset")
97
82
  ## converting on Dataframe:
98
83
  self.df2 = await self.get_dataframe(result, infer_types=True)
99
84
  except (DataNotFound, NoDataFound) as exc:
@@ -101,44 +86,42 @@ class AddDataset(DtComponent):
101
86
  raise DataNotFound(str(exc)) from exc
102
87
  finally:
103
88
  self.connection = None
104
- if self.type == 'left' and (self.df2 is None or self.df2.empty):
89
+ if self.type == "left" and (self.df2 is None or self.df2.empty):
105
90
  self._result = self.df1
106
91
  return True
107
92
  elif self.df2 is None or self.df2.empty:
108
- raise DataNotFound(
109
- "Data Was Not Found on Dataframe 2"
110
- )
111
- if hasattr(self, 'no_copy'):
112
- args['copy'] = self.no_copy
93
+ raise DataNotFound("Data Was Not Found on Dataframe 2")
94
+ if hasattr(self, "no_copy"):
95
+ args["copy"] = self.no_copy
113
96
  if not self.type:
114
- self.type = 'left'
115
- elif self.type == 'inner':
116
- args['left_index'] = True
117
- if hasattr(self, 'args') and isinstance(self.args, dict):
97
+ self.type = "left"
98
+ elif self.type == "inner":
99
+ args["left_index"] = True
100
+ if hasattr(self, "args") and isinstance(self.args, dict):
118
101
  args = {**args, **self.args}
119
- if hasattr(self, 'operator'):
102
+ if hasattr(self, "operator"):
120
103
  operator = self.operator
121
104
  else:
122
- operator = 'and'
123
- if hasattr(self, 'join'):
124
- args['on'] = self.join
105
+ operator = "and"
106
+ if hasattr(self, "join"):
107
+ args["on"] = self.join
125
108
  else:
126
- args['left_index'] = True
109
+ args["left_index"] = True
127
110
  # making a Join between 2 dataframes
128
111
  try:
129
- if operator == 'and':
112
+ if operator == "and":
130
113
  df = pd.merge(
131
114
  self.df1,
132
115
  self.df2,
133
116
  how=self.type,
134
- suffixes=('_left', '_right'),
135
- **args
117
+ suffixes=("_left", "_right"),
118
+ **args,
136
119
  )
137
120
  else:
138
- if hasattr(self, 'join'):
139
- args['left_on'] = self.join
121
+ if hasattr(self, "join"):
122
+ args["left_on"] = self.join
140
123
  else:
141
- args['left_index'] = True
124
+ args["left_index"] = True
142
125
  ndf = self.df1
143
126
  sdf = self.df2.copy()
144
127
  merge = []
@@ -148,15 +131,21 @@ class AddDataset(DtComponent):
148
131
  sdf,
149
132
  right_on=key,
150
133
  how=self.type,
151
- suffixes=('_left', None),
152
- **args
134
+ suffixes=("_left", None),
135
+ **args,
153
136
  )
154
137
  ndf = d[d[key].isnull()]
155
- ndf.drop(ndf.columns[ndf.columns.str.contains(
156
- '_left')], axis=1, inplace=True)
138
+ ndf.drop(
139
+ ndf.columns[ndf.columns.str.contains("_left")],
140
+ axis=1,
141
+ inplace=True,
142
+ )
157
143
  ddf = d[d[key].notnull()]
158
- ddf.drop(ddf.columns[ddf.columns.str.contains(
159
- '_left')], axis=1, inplace=True)
144
+ ddf.drop(
145
+ ddf.columns[ddf.columns.str.contains("_left")],
146
+ axis=1,
147
+ inplace=True,
148
+ )
160
149
  merge.append(ddf)
161
150
  # merge the last (not matched) rows
162
151
  merge.append(ndf)
@@ -164,25 +153,19 @@ class AddDataset(DtComponent):
164
153
  df.reset_index(drop=True)
165
154
  df.is_copy = None
166
155
  except (ValueError, KeyError) as err:
167
- raise ComponentError(
168
- f'Cannot Join with missing Column: {err!s}'
169
- ) from err
156
+ raise ComponentError(f"Cannot Join with missing Column: {err!s}") from err
170
157
  except Exception as err:
171
- raise ComponentError(
172
- f"Unknown JOIN error {err!s}"
173
- ) from err
158
+ raise ComponentError(f"Unknown JOIN error {err!s}") from err
174
159
  numrows = len(df.index)
175
160
  if numrows == 0:
176
- raise DataNotFound(
177
- "Cannot make any JOIN, returns zero coincidences"
178
- )
179
- self._variables[f'{self.TaskName}_NUMROWS'] = numrows
180
- print('ON END> ', numrows)
181
- self.add_metric('JOINED_ROWS', numrows)
161
+ raise DataNotFound("Cannot make any JOIN, returns zero coincidences")
162
+ self._variables[f"{self.TaskName}_NUMROWS"] = numrows
163
+ print("ON END> ", numrows)
164
+ self.add_metric("JOINED_ROWS", numrows)
182
165
  if self._debug is True:
183
- print('::: Printing Column Information === ')
166
+ print("::: Printing Column Information === ")
184
167
  for column, t in df.dtypes.items():
185
- print(column, '->', t, '->', df[column].iloc[0])
168
+ print(column, "->", t, "->", df[column].iloc[0])
186
169
  # helping some transformations
187
170
  df.is_copy = None
188
171
  self._result = df
@@ -198,63 +181,58 @@ class AddDataset(DtComponent):
198
181
  result = [dict(row) for row in result]
199
182
  try:
200
183
  if self.as_objects is True:
201
- df = pd.DataFrame(
202
- result,
203
- dtype=object
204
- )
184
+ df = pd.DataFrame(result, dtype=object)
205
185
  else:
206
- df = pd.DataFrame(
207
- result,
208
- **self._dtypes
209
- )
186
+ df = pd.DataFrame(result, **self._dtypes)
210
187
  except Exception as err: # pylint: disable=W0718
211
188
  self._logger.exception(err, stack_info=True)
212
189
  # Attempt to infer better dtypes for object columns.
213
190
  if hasattr(self, "infer_types") or infer_types is True:
214
191
  df.infer_objects()
215
- df = df.convert_dtypes(
216
- convert_string=self.to_string
217
- )
192
+ df = df.convert_dtypes(convert_string=self.to_string)
218
193
  if self._debug is True:
219
- cPrint('Data Types:')
194
+ cPrint("Data Types:")
220
195
  print(df.dtypes)
221
196
  if hasattr(self, "drop_empty"):
222
- df.dropna(axis=1, how='all', inplace=True)
223
- df.dropna(axis=0, how='all', inplace=True)
224
- if hasattr(self, 'dropna'):
225
- df.dropna(subset=self.dropna, how='all', inplace=True)
226
- if hasattr(self, 'clean_strings') and getattr(self, 'clean_strings', False) is True:
227
- u = df.select_dtypes(include=['object', 'string'])
228
- df[u.columns] = u.fillna('')
197
+ df.dropna(axis=1, how="all", inplace=True)
198
+ df.dropna(axis=0, how="all", inplace=True)
199
+ if hasattr(self, "dropna"):
200
+ df.dropna(subset=self.dropna, how="all", inplace=True)
201
+ if (
202
+ hasattr(self, "clean_strings")
203
+ and getattr(self, "clean_strings", False) is True
204
+ ):
205
+ u = df.select_dtypes(include=["object", "string"])
206
+ df[u.columns] = u.fillna("")
229
207
  return df
230
208
 
231
209
  def set_datatypes(self):
232
- if hasattr(self, 'datatypes'):
210
+ if hasattr(self, "datatypes"):
233
211
  dtypes = {}
234
212
  for field, dtype in self.datatypes.items():
235
- if dtype == 'uint8':
213
+ if dtype == "uint8":
236
214
  dtypes[field] = np.uint8
237
- elif dtype == 'uint16':
215
+ elif dtype == "uint16":
238
216
  dtypes[field] = np.uint16
239
- elif dtype == 'uint32':
217
+ elif dtype == "uint32":
240
218
  dtypes[field] = np.uint32
241
- elif dtype == 'int8':
219
+ elif dtype == "int8":
242
220
  dtypes[field] = np.int8
243
- elif dtype == 'int16':
221
+ elif dtype == "int16":
244
222
  dtypes[field] = np.int16
245
- elif dtype == 'int32':
223
+ elif dtype == "int32":
246
224
  dtypes[field] = np.int32
247
- elif dtype == 'float':
225
+ elif dtype == "float":
248
226
  dtypes[field] = float
249
- elif dtype == 'float32':
227
+ elif dtype == "float32":
250
228
  dtypes[field] = float
251
- elif dtype in ('string', 'varchar', 'str'):
229
+ elif dtype in ("string", "varchar", "str"):
252
230
  dtypes[field] = str
253
231
  else:
254
232
  # invalid datatype
255
233
  self._logger.warning(
256
- f'Invalid DataType value: {field} for field {dtype}'
234
+ f"Invalid DataType value: {field} for field {dtype}"
257
235
  )
258
236
  continue
259
237
  if dtypes:
260
- self._dtypes['dtype'] = dtypes
238
+ self._dtypes["dtype"] = dtypes
@@ -0,0 +1,226 @@
1
+ import math
2
+ import re
3
+ from urllib.parse import urljoin
4
+ import numpy as np
5
+ import orjson
6
+ import pandas as pd
7
+ from flowtask.components.abstract import DtComponent
8
+ from flowtask.components.interfaces.http import HTTPService
9
+ from flowtask.exceptions import ComponentError
10
+
11
+
12
+ def to_snake_case(s):
13
+ """Converts a string to snake_case format.
14
+
15
+ Args:
16
+ name: The string to convert.
17
+
18
+ Returns:
19
+ The converted string in snake_case format.
20
+ """
21
+ # Remove unwanted characters
22
+ s = re.sub(r"[^a-zA-Z0-9_\s]", "", s)
23
+
24
+ # Insert underscores before uppercase letters
25
+ s1 = re.sub("(.)([A-Z][a-z]+)", r"\1_\2", s)
26
+
27
+ # Replace remaining uppercase letters with underscores
28
+ return re.sub("([a-z0-9])([A-Z])", r"\1_\2", s1).lower()
29
+
30
+
31
+ class AutoTask(DtComponent, HTTPService):
32
+ _credentials: dict = {"API_INTEGRATION_CODE": str, "USERNAME": str, "SECRET": str}
33
+
34
+ async def start(self, **kwargs):
35
+ self.headers = None
36
+ self._proxies = None
37
+ self.auth = ""
38
+ self.auth_type = ""
39
+ self.download = None
40
+ self.timeout = 180
41
+ self.accept = "application/json"
42
+ self.query_json = self.mask_replacement_recursively(self.query_json)
43
+ self.processing_credentials()
44
+
45
+ self._base_url = (
46
+ f"https://{self.zone}.autotask.net/atservicesrest/v1.0/{self.entity}/"
47
+ )
48
+
49
+ self.headers = {
50
+ "Content-Type": "application/json",
51
+ "ApiIntegrationCode": self.credentials["API_INTEGRATION_CODE"],
52
+ "UserName": self.credentials["USERNAME"],
53
+ "Secret": self.credentials["SECRET"],
54
+ }
55
+
56
+ self.ids_chunks = []
57
+ if self.previous:
58
+ self.data = self.input
59
+
60
+ self.ids_chunks = self.filter_ids(
61
+ id_field=self.id_column_name,
62
+ items=self.data,
63
+ chunk_size=500,
64
+ )
65
+ elif getattr(self, "ids", None):
66
+ self._logger.info("Dropping specified Filters. Using ids instead.")
67
+ self.ids_chunks = [self.ids]
68
+
69
+ return True
70
+
71
+ async def run(self):
72
+ if not self.ids_chunks:
73
+ # Use the Filter specified in the task
74
+ df_items = await self.get_dataframe_from_entity(
75
+ payload=orjson.dumps(self.query_json),
76
+ id_column_name=self.id_column_name,
77
+ )
78
+ else:
79
+ # Use the ids from the previous component or from the ids argument
80
+ df_items = pd.DataFrame()
81
+ for ids_chunk in self.ids_chunks:
82
+ self.query_json.update(
83
+ {
84
+ "Filter": [
85
+ {"op": "in", "field": "id", "value": ids_chunk.tolist()}
86
+ ]
87
+ }
88
+ )
89
+
90
+ items = await self.get_dataframe_from_entity(
91
+ payload=orjson.dumps(self.query_json),
92
+ id_column_name=self.id_column_name,
93
+ )
94
+
95
+ df_items = pd.concat([df_items, items], ignore_index=True)
96
+
97
+ if not df_items.empty:
98
+ for field in self.picklist_fields:
99
+ df_picklist_values = await self.get_picklist_values(field)
100
+
101
+ snake_case_field_name = to_snake_case(field)
102
+
103
+ df_items = df_items.astype({snake_case_field_name: "str"})
104
+
105
+ df_items = df_items.merge(
106
+ df_picklist_values,
107
+ how="left",
108
+ on=snake_case_field_name,
109
+ )
110
+
111
+ self._result = df_items
112
+ return self._result
113
+
114
+ async def close(self):
115
+ pass
116
+
117
+ def processing_credentials(self):
118
+ if self.credentials:
119
+ for value, dtype in self._credentials.items():
120
+ try:
121
+ if type(self.credentials[value]) == dtype:
122
+ default = getattr(self, value, self.credentials[value])
123
+ val = self.get_env_value(
124
+ self.credentials[value], default=default
125
+ )
126
+ self.credentials[value] = val
127
+ except (TypeError, KeyError) as ex:
128
+ self._logger.error(f"{__name__}: Wrong or missing Credentials")
129
+ raise ComponentError(
130
+ f"{__name__}: Wrong or missing Credentials"
131
+ ) from ex
132
+
133
+ def filter_ids(self, id_field: str, items: pd.DataFrame, chunk_size):
134
+ data = items[id_field].dropna().unique().astype(int)
135
+
136
+ if data.size > 0:
137
+ split_n = math.ceil(data.size / chunk_size)
138
+
139
+ # Split into chunks of n items
140
+ return np.array_split(data, split_n) # Convert to NumPy array and split
141
+
142
+ return [data]
143
+
144
+ def get_autotask_url(self, resource):
145
+ return urljoin(self._base_url, resource)
146
+
147
+ async def get_dataframe_from_entity(self, payload, id_column_name):
148
+ args = {
149
+ "url": self.get_autotask_url("query"),
150
+ "method": "post",
151
+ "data": payload,
152
+ }
153
+
154
+ results = []
155
+ while True:
156
+ result, error = await self.session(**args)
157
+
158
+ if error:
159
+ self._logger.error(f"{__name__}: Error getting {self.entity}")
160
+ raise ComponentError(f"{__name__}: Error getting {self.entity}") from error
161
+
162
+ results.extend(result.get("items", []))
163
+
164
+ args.update({"url": result["pageDetails"].get("nextPageUrl", None)})
165
+
166
+ if not args["url"]:
167
+ break
168
+
169
+ df_results = await self.create_dataframe(results)
170
+
171
+ if not df_results.empty:
172
+ for field in self.user_defined_fields:
173
+ df_results[field] = df_results["userDefinedFields"].apply(
174
+ self.get_udf_value, args=[field]
175
+ )
176
+
177
+ df_results = (
178
+ df_results.drop("userDefinedFields", axis=1, errors="ignore")
179
+ .fillna(value=self.fillna_values)
180
+ .astype(self.map_field_type)
181
+ .rename(columns=lambda x: to_snake_case(x))
182
+ .rename(columns={"id": id_column_name})
183
+ )
184
+
185
+ return df_results
186
+
187
+ @staticmethod
188
+ def get_udf_value(udfs, field_name):
189
+ """
190
+ Extracts the value of a specific user-defined field from a item dictionary.
191
+
192
+ Args:
193
+ item (dict): A dictionary representing a item.
194
+ field_name (str): The name of the user-defined field to extract.
195
+
196
+ Returns:
197
+ str: The value of the specified user-defined field, or None if not found.
198
+ """
199
+ for udf in udfs:
200
+ if udf["name"] == field_name:
201
+ return udf["value"]
202
+
203
+ return None
204
+
205
+ async def get_picklist_values(self, field_name: str) -> pd.DataFrame:
206
+ result, error = await self.session(
207
+ url=self.get_autotask_url("entityInformation/fields"),
208
+ method="get",
209
+ )
210
+
211
+ if error:
212
+ self._logger.error(f"{__name__}: Error getting {self.entity}")
213
+ raise ComponentError(f"{__name__}: Error getting {self.entity}") from error
214
+
215
+ for field in result["fields"]:
216
+ if field["name"] == field_name:
217
+ df = await self.create_dataframe(field["picklistValues"])
218
+ df = df[["label", "value"]]
219
+ snake_case_field_name = to_snake_case(field_name)
220
+
221
+ return df.rename(
222
+ columns={
223
+ "label": f"{snake_case_field_name}_label",
224
+ "value": snake_case_field_name,
225
+ }
226
+ )