flowtask 5.8.4__cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (470) hide show
  1. flowtask/__init__.py +93 -0
  2. flowtask/__main__.py +38 -0
  3. flowtask/bots/__init__.py +6 -0
  4. flowtask/bots/check.py +93 -0
  5. flowtask/bots/codebot.py +51 -0
  6. flowtask/components/ASPX.py +148 -0
  7. flowtask/components/AddDataset.py +352 -0
  8. flowtask/components/Amazon.py +523 -0
  9. flowtask/components/AutoTask.py +314 -0
  10. flowtask/components/Azure.py +80 -0
  11. flowtask/components/AzureUsers.py +106 -0
  12. flowtask/components/BaseAction.py +91 -0
  13. flowtask/components/BaseLoop.py +198 -0
  14. flowtask/components/BestBuy.py +800 -0
  15. flowtask/components/CSVToGCS.py +120 -0
  16. flowtask/components/CompanyScraper/__init__.py +1 -0
  17. flowtask/components/CompanyScraper/parsers/__init__.py +6 -0
  18. flowtask/components/CompanyScraper/parsers/base.py +102 -0
  19. flowtask/components/CompanyScraper/parsers/explorium.py +192 -0
  20. flowtask/components/CompanyScraper/parsers/leadiq.py +206 -0
  21. flowtask/components/CompanyScraper/parsers/rocket.py +133 -0
  22. flowtask/components/CompanyScraper/parsers/siccode.py +109 -0
  23. flowtask/components/CompanyScraper/parsers/visualvisitor.py +130 -0
  24. flowtask/components/CompanyScraper/parsers/zoominfo.py +118 -0
  25. flowtask/components/CompanyScraper/scrapper.py +1054 -0
  26. flowtask/components/CopyTo.py +177 -0
  27. flowtask/components/CopyToBigQuery.py +243 -0
  28. flowtask/components/CopyToMongoDB.py +291 -0
  29. flowtask/components/CopyToPg.py +609 -0
  30. flowtask/components/CopyToRethink.py +207 -0
  31. flowtask/components/CreateGCSBucket.py +102 -0
  32. flowtask/components/CreateReport/CreateReport.py +228 -0
  33. flowtask/components/CreateReport/__init__.py +9 -0
  34. flowtask/components/CreateReport/charts/__init__.py +15 -0
  35. flowtask/components/CreateReport/charts/bar.py +51 -0
  36. flowtask/components/CreateReport/charts/base.py +66 -0
  37. flowtask/components/CreateReport/charts/pie.py +64 -0
  38. flowtask/components/CreateReport/utils.py +9 -0
  39. flowtask/components/CustomerSatisfaction.py +196 -0
  40. flowtask/components/DataInput.py +200 -0
  41. flowtask/components/DateList.py +255 -0
  42. flowtask/components/DbClient.py +163 -0
  43. flowtask/components/DialPad.py +146 -0
  44. flowtask/components/DocumentDBQuery.py +200 -0
  45. flowtask/components/DownloadFrom.py +371 -0
  46. flowtask/components/DownloadFromD2L.py +113 -0
  47. flowtask/components/DownloadFromFTP.py +181 -0
  48. flowtask/components/DownloadFromIMAP.py +315 -0
  49. flowtask/components/DownloadFromS3.py +198 -0
  50. flowtask/components/DownloadFromSFTP.py +265 -0
  51. flowtask/components/DownloadFromSharepoint.py +110 -0
  52. flowtask/components/DownloadFromSmartSheet.py +114 -0
  53. flowtask/components/DownloadS3File.py +229 -0
  54. flowtask/components/Dummy.py +59 -0
  55. flowtask/components/DuplicatePhoto.py +411 -0
  56. flowtask/components/EmployeeEvaluation.py +237 -0
  57. flowtask/components/ExecuteSQL.py +323 -0
  58. flowtask/components/ExtractHTML.py +178 -0
  59. flowtask/components/FileBase.py +178 -0
  60. flowtask/components/FileCopy.py +181 -0
  61. flowtask/components/FileDelete.py +82 -0
  62. flowtask/components/FileExists.py +146 -0
  63. flowtask/components/FileIteratorDelete.py +112 -0
  64. flowtask/components/FileList.py +194 -0
  65. flowtask/components/FileOpen.py +75 -0
  66. flowtask/components/FileRead.py +120 -0
  67. flowtask/components/FileRename.py +106 -0
  68. flowtask/components/FilterIf.py +284 -0
  69. flowtask/components/FilterRows/FilterRows.py +200 -0
  70. flowtask/components/FilterRows/__init__.py +10 -0
  71. flowtask/components/FilterRows/functions.py +4 -0
  72. flowtask/components/GCSToBigQuery.py +103 -0
  73. flowtask/components/GoogleA4.py +150 -0
  74. flowtask/components/GoogleGeoCoding.py +344 -0
  75. flowtask/components/GooglePlaces.py +315 -0
  76. flowtask/components/GoogleSearch.py +539 -0
  77. flowtask/components/HTTPClient.py +268 -0
  78. flowtask/components/ICIMS.py +146 -0
  79. flowtask/components/IF.py +179 -0
  80. flowtask/components/IcimsFolderCopy.py +173 -0
  81. flowtask/components/ImageFeatures/__init__.py +5 -0
  82. flowtask/components/ImageFeatures/process.py +233 -0
  83. flowtask/components/IteratorBase.py +251 -0
  84. flowtask/components/LangchainLoader/__init__.py +5 -0
  85. flowtask/components/LangchainLoader/loader.py +194 -0
  86. flowtask/components/LangchainLoader/loaders/__init__.py +22 -0
  87. flowtask/components/LangchainLoader/loaders/abstract.py +362 -0
  88. flowtask/components/LangchainLoader/loaders/basepdf.py +50 -0
  89. flowtask/components/LangchainLoader/loaders/docx.py +91 -0
  90. flowtask/components/LangchainLoader/loaders/html.py +119 -0
  91. flowtask/components/LangchainLoader/loaders/pdfblocks.py +146 -0
  92. flowtask/components/LangchainLoader/loaders/pdfmark.py +79 -0
  93. flowtask/components/LangchainLoader/loaders/pdftables.py +135 -0
  94. flowtask/components/LangchainLoader/loaders/qa.py +67 -0
  95. flowtask/components/LangchainLoader/loaders/txt.py +55 -0
  96. flowtask/components/LeadIQ.py +650 -0
  97. flowtask/components/Loop.py +253 -0
  98. flowtask/components/Lowes.py +334 -0
  99. flowtask/components/MS365Usage.py +156 -0
  100. flowtask/components/MSTeamsMessages.py +320 -0
  101. flowtask/components/MarketClustering.py +1051 -0
  102. flowtask/components/MergeFiles.py +362 -0
  103. flowtask/components/MilvusOutput.py +87 -0
  104. flowtask/components/NearByStores.py +175 -0
  105. flowtask/components/NetworkNinja/__init__.py +6 -0
  106. flowtask/components/NetworkNinja/models/__init__.py +52 -0
  107. flowtask/components/NetworkNinja/models/abstract.py +177 -0
  108. flowtask/components/NetworkNinja/models/account.py +39 -0
  109. flowtask/components/NetworkNinja/models/client.py +19 -0
  110. flowtask/components/NetworkNinja/models/district.py +14 -0
  111. flowtask/components/NetworkNinja/models/events.py +101 -0
  112. flowtask/components/NetworkNinja/models/forms.py +499 -0
  113. flowtask/components/NetworkNinja/models/market.py +16 -0
  114. flowtask/components/NetworkNinja/models/organization.py +34 -0
  115. flowtask/components/NetworkNinja/models/photos.py +125 -0
  116. flowtask/components/NetworkNinja/models/project.py +44 -0
  117. flowtask/components/NetworkNinja/models/region.py +28 -0
  118. flowtask/components/NetworkNinja/models/store.py +203 -0
  119. flowtask/components/NetworkNinja/models/user.py +151 -0
  120. flowtask/components/NetworkNinja/router.py +854 -0
  121. flowtask/components/Odoo.py +175 -0
  122. flowtask/components/OdooInjector.py +192 -0
  123. flowtask/components/OpenFromXML.py +126 -0
  124. flowtask/components/OpenWeather.py +41 -0
  125. flowtask/components/OpenWithBase.py +616 -0
  126. flowtask/components/OpenWithPandas.py +715 -0
  127. flowtask/components/PGPDecrypt.py +199 -0
  128. flowtask/components/PandasIterator.py +187 -0
  129. flowtask/components/PandasToFile.py +189 -0
  130. flowtask/components/Paradox.py +339 -0
  131. flowtask/components/ParamIterator.py +117 -0
  132. flowtask/components/ParseHTML.py +84 -0
  133. flowtask/components/PlacerStores.py +249 -0
  134. flowtask/components/Pokemon.py +507 -0
  135. flowtask/components/PositiveBot.py +62 -0
  136. flowtask/components/PowerPointSlide.py +400 -0
  137. flowtask/components/PrintMessage.py +127 -0
  138. flowtask/components/ProductCompetitors/__init__.py +5 -0
  139. flowtask/components/ProductCompetitors/parsers/__init__.py +7 -0
  140. flowtask/components/ProductCompetitors/parsers/base.py +72 -0
  141. flowtask/components/ProductCompetitors/parsers/bestbuy.py +86 -0
  142. flowtask/components/ProductCompetitors/parsers/lowes.py +103 -0
  143. flowtask/components/ProductCompetitors/scrapper.py +155 -0
  144. flowtask/components/ProductCompliant.py +169 -0
  145. flowtask/components/ProductInfo/__init__.py +1 -0
  146. flowtask/components/ProductInfo/parsers/__init__.py +5 -0
  147. flowtask/components/ProductInfo/parsers/base.py +83 -0
  148. flowtask/components/ProductInfo/parsers/brother.py +97 -0
  149. flowtask/components/ProductInfo/parsers/canon.py +167 -0
  150. flowtask/components/ProductInfo/parsers/epson.py +118 -0
  151. flowtask/components/ProductInfo/parsers/hp.py +131 -0
  152. flowtask/components/ProductInfo/parsers/samsung.py +97 -0
  153. flowtask/components/ProductInfo/scraper.py +319 -0
  154. flowtask/components/ProductPricing.py +118 -0
  155. flowtask/components/QS.py +261 -0
  156. flowtask/components/QSBase.py +201 -0
  157. flowtask/components/QueryIterator.py +273 -0
  158. flowtask/components/QueryToInsert.py +327 -0
  159. flowtask/components/QueryToPandas.py +432 -0
  160. flowtask/components/RESTClient.py +195 -0
  161. flowtask/components/RethinkDBQuery.py +189 -0
  162. flowtask/components/Rsync.py +74 -0
  163. flowtask/components/RunSSH.py +59 -0
  164. flowtask/components/RunShell.py +71 -0
  165. flowtask/components/SalesForce.py +20 -0
  166. flowtask/components/SaveImageBank/__init__.py +257 -0
  167. flowtask/components/SchedulingVisits.py +592 -0
  168. flowtask/components/ScrapPage.py +216 -0
  169. flowtask/components/ScrapSearch.py +79 -0
  170. flowtask/components/SendNotify.py +257 -0
  171. flowtask/components/SentimentAnalysis.py +694 -0
  172. flowtask/components/ServiceScrapper/__init__.py +5 -0
  173. flowtask/components/ServiceScrapper/parsers/__init__.py +1 -0
  174. flowtask/components/ServiceScrapper/parsers/base.py +94 -0
  175. flowtask/components/ServiceScrapper/parsers/costco.py +93 -0
  176. flowtask/components/ServiceScrapper/scrapper.py +199 -0
  177. flowtask/components/SetVariables.py +156 -0
  178. flowtask/components/SubTask.py +182 -0
  179. flowtask/components/SuiteCRM.py +48 -0
  180. flowtask/components/Switch.py +175 -0
  181. flowtask/components/TableBase.py +148 -0
  182. flowtask/components/TableDelete.py +312 -0
  183. flowtask/components/TableInput.py +143 -0
  184. flowtask/components/TableOutput/TableOutput.py +384 -0
  185. flowtask/components/TableOutput/__init__.py +3 -0
  186. flowtask/components/TableSchema.py +534 -0
  187. flowtask/components/Target.py +223 -0
  188. flowtask/components/ThumbnailGenerator.py +156 -0
  189. flowtask/components/ToPandas.py +67 -0
  190. flowtask/components/TransformRows/TransformRows.py +507 -0
  191. flowtask/components/TransformRows/__init__.py +9 -0
  192. flowtask/components/TransformRows/functions.py +559 -0
  193. flowtask/components/TransposeRows.py +176 -0
  194. flowtask/components/UPCDatabase.py +86 -0
  195. flowtask/components/UnGzip.py +171 -0
  196. flowtask/components/Uncompress.py +172 -0
  197. flowtask/components/UniqueRows.py +126 -0
  198. flowtask/components/Unzip.py +107 -0
  199. flowtask/components/UpdateOperationalVars.py +147 -0
  200. flowtask/components/UploadTo.py +299 -0
  201. flowtask/components/UploadToS3.py +136 -0
  202. flowtask/components/UploadToSFTP.py +160 -0
  203. flowtask/components/UploadToSharepoint.py +205 -0
  204. flowtask/components/UserFunc.py +122 -0
  205. flowtask/components/VivaTracker.py +140 -0
  206. flowtask/components/WSDLClient.py +123 -0
  207. flowtask/components/Wait.py +18 -0
  208. flowtask/components/Walmart.py +199 -0
  209. flowtask/components/Workplace.py +134 -0
  210. flowtask/components/XMLToPandas.py +267 -0
  211. flowtask/components/Zammad/__init__.py +41 -0
  212. flowtask/components/Zammad/models.py +0 -0
  213. flowtask/components/ZoomInfoScraper.py +409 -0
  214. flowtask/components/__init__.py +104 -0
  215. flowtask/components/abstract.py +18 -0
  216. flowtask/components/flow.py +530 -0
  217. flowtask/components/google.py +335 -0
  218. flowtask/components/group.py +221 -0
  219. flowtask/components/py.typed +0 -0
  220. flowtask/components/reviewscrap.py +132 -0
  221. flowtask/components/tAutoincrement.py +117 -0
  222. flowtask/components/tConcat.py +109 -0
  223. flowtask/components/tExplode.py +119 -0
  224. flowtask/components/tFilter.py +184 -0
  225. flowtask/components/tGroup.py +236 -0
  226. flowtask/components/tJoin.py +270 -0
  227. flowtask/components/tMap/__init__.py +9 -0
  228. flowtask/components/tMap/functions.py +54 -0
  229. flowtask/components/tMap/tMap.py +450 -0
  230. flowtask/components/tMelt.py +112 -0
  231. flowtask/components/tMerge.py +114 -0
  232. flowtask/components/tOrder.py +93 -0
  233. flowtask/components/tPandas.py +94 -0
  234. flowtask/components/tPivot.py +71 -0
  235. flowtask/components/tPluckCols.py +76 -0
  236. flowtask/components/tUnnest.py +82 -0
  237. flowtask/components/user.py +401 -0
  238. flowtask/conf.py +457 -0
  239. flowtask/download.py +102 -0
  240. flowtask/events/__init__.py +11 -0
  241. flowtask/events/events/__init__.py +20 -0
  242. flowtask/events/events/abstract.py +95 -0
  243. flowtask/events/events/alerts/__init__.py +362 -0
  244. flowtask/events/events/alerts/colfunctions.py +131 -0
  245. flowtask/events/events/alerts/functions.py +158 -0
  246. flowtask/events/events/dummy.py +12 -0
  247. flowtask/events/events/exec.py +124 -0
  248. flowtask/events/events/file/__init__.py +7 -0
  249. flowtask/events/events/file/base.py +51 -0
  250. flowtask/events/events/file/copy.py +23 -0
  251. flowtask/events/events/file/delete.py +16 -0
  252. flowtask/events/events/interfaces/__init__.py +9 -0
  253. flowtask/events/events/interfaces/client.py +67 -0
  254. flowtask/events/events/interfaces/credentials.py +28 -0
  255. flowtask/events/events/interfaces/notifications.py +58 -0
  256. flowtask/events/events/jira.py +122 -0
  257. flowtask/events/events/log.py +26 -0
  258. flowtask/events/events/logerr.py +52 -0
  259. flowtask/events/events/notify.py +59 -0
  260. flowtask/events/events/notify_event.py +160 -0
  261. flowtask/events/events/publish.py +54 -0
  262. flowtask/events/events/sendfile.py +104 -0
  263. flowtask/events/events/task.py +97 -0
  264. flowtask/events/events/teams.py +98 -0
  265. flowtask/events/events/webhook.py +58 -0
  266. flowtask/events/manager.py +287 -0
  267. flowtask/exceptions.c +39393 -0
  268. flowtask/exceptions.cpython-310-x86_64-linux-gnu.so +0 -0
  269. flowtask/extensions/__init__.py +3 -0
  270. flowtask/extensions/abstract.py +82 -0
  271. flowtask/extensions/logging/__init__.py +65 -0
  272. flowtask/hooks/__init__.py +9 -0
  273. flowtask/hooks/actions/__init__.py +22 -0
  274. flowtask/hooks/actions/abstract.py +66 -0
  275. flowtask/hooks/actions/dummy.py +23 -0
  276. flowtask/hooks/actions/jira.py +74 -0
  277. flowtask/hooks/actions/rest.py +320 -0
  278. flowtask/hooks/actions/sampledata.py +37 -0
  279. flowtask/hooks/actions/sensor.py +23 -0
  280. flowtask/hooks/actions/task.py +9 -0
  281. flowtask/hooks/actions/ticket.py +37 -0
  282. flowtask/hooks/actions/zammad.py +55 -0
  283. flowtask/hooks/hook.py +62 -0
  284. flowtask/hooks/models.py +17 -0
  285. flowtask/hooks/service.py +187 -0
  286. flowtask/hooks/step.py +91 -0
  287. flowtask/hooks/types/__init__.py +23 -0
  288. flowtask/hooks/types/base.py +129 -0
  289. flowtask/hooks/types/brokers/__init__.py +11 -0
  290. flowtask/hooks/types/brokers/base.py +54 -0
  291. flowtask/hooks/types/brokers/mqtt.py +35 -0
  292. flowtask/hooks/types/brokers/rabbitmq.py +82 -0
  293. flowtask/hooks/types/brokers/redis.py +83 -0
  294. flowtask/hooks/types/brokers/sqs.py +44 -0
  295. flowtask/hooks/types/fs.py +232 -0
  296. flowtask/hooks/types/http.py +49 -0
  297. flowtask/hooks/types/imap.py +200 -0
  298. flowtask/hooks/types/jira.py +279 -0
  299. flowtask/hooks/types/mail.py +205 -0
  300. flowtask/hooks/types/postgres.py +98 -0
  301. flowtask/hooks/types/responses/__init__.py +8 -0
  302. flowtask/hooks/types/responses/base.py +5 -0
  303. flowtask/hooks/types/sharepoint.py +288 -0
  304. flowtask/hooks/types/ssh.py +141 -0
  305. flowtask/hooks/types/tagged.py +59 -0
  306. flowtask/hooks/types/upload.py +85 -0
  307. flowtask/hooks/types/watch.py +71 -0
  308. flowtask/hooks/types/web.py +36 -0
  309. flowtask/interfaces/AzureClient.py +137 -0
  310. flowtask/interfaces/AzureGraph.py +839 -0
  311. flowtask/interfaces/Boto3Client.py +326 -0
  312. flowtask/interfaces/DropboxClient.py +173 -0
  313. flowtask/interfaces/ExcelHandler.py +94 -0
  314. flowtask/interfaces/FTPClient.py +131 -0
  315. flowtask/interfaces/GoogleCalendar.py +201 -0
  316. flowtask/interfaces/GoogleClient.py +133 -0
  317. flowtask/interfaces/GoogleDrive.py +127 -0
  318. flowtask/interfaces/GoogleGCS.py +89 -0
  319. flowtask/interfaces/GoogleGeocoding.py +93 -0
  320. flowtask/interfaces/GoogleLang.py +114 -0
  321. flowtask/interfaces/GooglePub.py +61 -0
  322. flowtask/interfaces/GoogleSheet.py +68 -0
  323. flowtask/interfaces/IMAPClient.py +137 -0
  324. flowtask/interfaces/O365Calendar.py +113 -0
  325. flowtask/interfaces/O365Client.py +220 -0
  326. flowtask/interfaces/OneDrive.py +284 -0
  327. flowtask/interfaces/Outlook.py +155 -0
  328. flowtask/interfaces/ParrotBot.py +130 -0
  329. flowtask/interfaces/SSHClient.py +378 -0
  330. flowtask/interfaces/Sharepoint.py +496 -0
  331. flowtask/interfaces/__init__.py +36 -0
  332. flowtask/interfaces/azureauth.py +119 -0
  333. flowtask/interfaces/cache.py +201 -0
  334. flowtask/interfaces/client.py +82 -0
  335. flowtask/interfaces/compress.py +525 -0
  336. flowtask/interfaces/credentials.py +124 -0
  337. flowtask/interfaces/d2l.py +239 -0
  338. flowtask/interfaces/databases/__init__.py +5 -0
  339. flowtask/interfaces/databases/db.py +223 -0
  340. flowtask/interfaces/databases/documentdb.py +55 -0
  341. flowtask/interfaces/databases/rethink.py +39 -0
  342. flowtask/interfaces/dataframes/__init__.py +11 -0
  343. flowtask/interfaces/dataframes/abstract.py +21 -0
  344. flowtask/interfaces/dataframes/arrow.py +71 -0
  345. flowtask/interfaces/dataframes/dt.py +69 -0
  346. flowtask/interfaces/dataframes/pandas.py +167 -0
  347. flowtask/interfaces/dataframes/polars.py +60 -0
  348. flowtask/interfaces/db.py +263 -0
  349. flowtask/interfaces/env.py +46 -0
  350. flowtask/interfaces/func.py +137 -0
  351. flowtask/interfaces/http.py +1780 -0
  352. flowtask/interfaces/locale.py +40 -0
  353. flowtask/interfaces/log.py +75 -0
  354. flowtask/interfaces/mask.py +143 -0
  355. flowtask/interfaces/notification.py +154 -0
  356. flowtask/interfaces/playwright.py +339 -0
  357. flowtask/interfaces/powerpoint.py +368 -0
  358. flowtask/interfaces/py.typed +0 -0
  359. flowtask/interfaces/qs.py +376 -0
  360. flowtask/interfaces/result.py +87 -0
  361. flowtask/interfaces/selenium_service.py +779 -0
  362. flowtask/interfaces/smartsheet.py +154 -0
  363. flowtask/interfaces/stat.py +39 -0
  364. flowtask/interfaces/task.py +96 -0
  365. flowtask/interfaces/template.py +118 -0
  366. flowtask/interfaces/vectorstores/__init__.py +1 -0
  367. flowtask/interfaces/vectorstores/abstract.py +133 -0
  368. flowtask/interfaces/vectorstores/milvus.py +669 -0
  369. flowtask/interfaces/zammad.py +107 -0
  370. flowtask/models.py +193 -0
  371. flowtask/parsers/__init__.py +15 -0
  372. flowtask/parsers/_yaml.c +11978 -0
  373. flowtask/parsers/_yaml.cpython-310-x86_64-linux-gnu.so +0 -0
  374. flowtask/parsers/argparser.py +235 -0
  375. flowtask/parsers/base.c +15155 -0
  376. flowtask/parsers/base.cpython-310-x86_64-linux-gnu.so +0 -0
  377. flowtask/parsers/json.c +11968 -0
  378. flowtask/parsers/json.cpython-310-x86_64-linux-gnu.so +0 -0
  379. flowtask/parsers/maps.py +49 -0
  380. flowtask/parsers/toml.c +11968 -0
  381. flowtask/parsers/toml.cpython-310-x86_64-linux-gnu.so +0 -0
  382. flowtask/plugins/__init__.py +16 -0
  383. flowtask/plugins/components/__init__.py +0 -0
  384. flowtask/plugins/handler/__init__.py +45 -0
  385. flowtask/plugins/importer.py +31 -0
  386. flowtask/plugins/sources/__init__.py +0 -0
  387. flowtask/runner.py +283 -0
  388. flowtask/scheduler/__init__.py +9 -0
  389. flowtask/scheduler/functions.py +493 -0
  390. flowtask/scheduler/handlers/__init__.py +8 -0
  391. flowtask/scheduler/handlers/manager.py +504 -0
  392. flowtask/scheduler/handlers/models.py +58 -0
  393. flowtask/scheduler/handlers/service.py +72 -0
  394. flowtask/scheduler/notifications.py +65 -0
  395. flowtask/scheduler/scheduler.py +993 -0
  396. flowtask/services/__init__.py +0 -0
  397. flowtask/services/bots/__init__.py +0 -0
  398. flowtask/services/bots/telegram.py +264 -0
  399. flowtask/services/files/__init__.py +11 -0
  400. flowtask/services/files/manager.py +522 -0
  401. flowtask/services/files/model.py +37 -0
  402. flowtask/services/files/service.py +767 -0
  403. flowtask/services/jira/__init__.py +3 -0
  404. flowtask/services/jira/jira_actions.py +191 -0
  405. flowtask/services/tasks/__init__.py +13 -0
  406. flowtask/services/tasks/launcher.py +213 -0
  407. flowtask/services/tasks/manager.py +323 -0
  408. flowtask/services/tasks/service.py +275 -0
  409. flowtask/services/tasks/task_manager.py +376 -0
  410. flowtask/services/tasks/tasks.py +155 -0
  411. flowtask/storages/__init__.py +16 -0
  412. flowtask/storages/exceptions.py +12 -0
  413. flowtask/storages/files/__init__.py +8 -0
  414. flowtask/storages/files/abstract.py +29 -0
  415. flowtask/storages/files/filesystem.py +66 -0
  416. flowtask/storages/tasks/__init__.py +19 -0
  417. flowtask/storages/tasks/abstract.py +26 -0
  418. flowtask/storages/tasks/database.py +33 -0
  419. flowtask/storages/tasks/filesystem.py +108 -0
  420. flowtask/storages/tasks/github.py +119 -0
  421. flowtask/storages/tasks/memory.py +45 -0
  422. flowtask/storages/tasks/row.py +25 -0
  423. flowtask/tasks/__init__.py +0 -0
  424. flowtask/tasks/abstract.py +526 -0
  425. flowtask/tasks/command.py +118 -0
  426. flowtask/tasks/pile.py +486 -0
  427. flowtask/tasks/py.typed +0 -0
  428. flowtask/tasks/task.py +778 -0
  429. flowtask/template/__init__.py +161 -0
  430. flowtask/tests.py +257 -0
  431. flowtask/types/__init__.py +8 -0
  432. flowtask/types/typedefs.c +11347 -0
  433. flowtask/types/typedefs.cpython-310-x86_64-linux-gnu.so +0 -0
  434. flowtask/utils/__init__.py +24 -0
  435. flowtask/utils/constants.py +117 -0
  436. flowtask/utils/encoders.py +21 -0
  437. flowtask/utils/executor.py +112 -0
  438. flowtask/utils/functions.cpp +14280 -0
  439. flowtask/utils/functions.cpython-310-x86_64-linux-gnu.so +0 -0
  440. flowtask/utils/json.cpp +13349 -0
  441. flowtask/utils/json.cpython-310-x86_64-linux-gnu.so +0 -0
  442. flowtask/utils/mail.py +63 -0
  443. flowtask/utils/parseqs.c +13324 -0
  444. flowtask/utils/parserqs.cpython-310-x86_64-linux-gnu.so +0 -0
  445. flowtask/utils/stats.py +308 -0
  446. flowtask/utils/transformations.py +74 -0
  447. flowtask/utils/uv.py +12 -0
  448. flowtask/utils/validators.py +97 -0
  449. flowtask/version.py +11 -0
  450. flowtask-5.8.4.dist-info/LICENSE +201 -0
  451. flowtask-5.8.4.dist-info/METADATA +209 -0
  452. flowtask-5.8.4.dist-info/RECORD +470 -0
  453. flowtask-5.8.4.dist-info/WHEEL +6 -0
  454. flowtask-5.8.4.dist-info/entry_points.txt +3 -0
  455. flowtask-5.8.4.dist-info/top_level.txt +2 -0
  456. plugins/components/CreateQR.py +39 -0
  457. plugins/components/TestComponent.py +28 -0
  458. plugins/components/Use1.py +13 -0
  459. plugins/components/Workplace.py +117 -0
  460. plugins/components/__init__.py +3 -0
  461. plugins/sources/__init__.py +0 -0
  462. plugins/sources/get_populartimes.py +78 -0
  463. plugins/sources/google.py +150 -0
  464. plugins/sources/hubspot.py +679 -0
  465. plugins/sources/icims.py +679 -0
  466. plugins/sources/mobileinsight.py +501 -0
  467. plugins/sources/newrelic.py +262 -0
  468. plugins/sources/uap.py +268 -0
  469. plugins/sources/venu.py +244 -0
  470. plugins/sources/vocinity.py +314 -0
@@ -0,0 +1,326 @@
1
+ from typing import Dict, List, Optional
2
+ import re
3
+ import boto3
4
+ from botocore.exceptions import ClientError
5
+ import aiofiles
6
+ from navconfig.logging import logging
7
+ from io import BytesIO
8
+ from ..conf import aws_region
9
+ try:
10
+ from settings.settings import AWS_CREDENTIALS
11
+ except ImportError as e:
12
+ logging.exception(
13
+ f"AWS_CREDENTIALS not found. Please check your settings file: {e}"
14
+ )
15
+ from ..conf import AWS_CREDENTIALS
16
+ from .client import ClientInterface
17
+ from ..exceptions import FileNotFound, FileError, ComponentError
18
+
19
+
20
+ logging.getLogger("boto3").setLevel(logging.CRITICAL)
21
+ logging.getLogger("botocore").setLevel(logging.CRITICAL)
22
+ logging.getLogger("s3transfer").setLevel(logging.CRITICAL)
23
+ logging.getLogger("urllib3").setLevel(logging.CRITICAL)
24
+
25
+
26
+ class Boto3Client(ClientInterface):
27
+ """
28
+ Boto3 AWS Client.
29
+
30
+ Overview
31
+
32
+ Abstract class for interaction with Boto3 (AWS).
33
+
34
+ .. table:: Properties
35
+ :widths: auto
36
+
37
+ +------------------------+----------+-----------+-------------------------------------------------------+
38
+ | Name | Required | Summary |
39
+ +------------------------+----------+-----------+-------------------------------------------------------+
40
+ |_credentials | Yes | The function is loaded and then we define the necessary code to |
41
+ | | | call the script |
42
+ +------------------------+----------+-----------+-------------------------------------------------------+
43
+ | _init_ | Yes | Component for Data Integrator |
44
+ +------------------------+----------+-----------+-------------------------------------------------------+
45
+ | _host | Yes | The IPv4 or domain name of the server |
46
+ +------------------------+----------+-----------+-------------------------------------------------------+
47
+ | get_client | Yes | Gets the client access credentials, by which the user logs in to |
48
+ | | | perform an action |
49
+ +------------------------+----------+-----------+-------------------------------------------------------+
50
+ | print | Yes | Print message to display |
51
+ +------------------------+----------+-----------+-------------------------------------------------------+
52
+ | get_env_value | Yes | Get env value policies for setting virtual environment |
53
+ +------------------------+----------+-----------+-------------------------------------------------------+
54
+ | processing_credentials | Yes | client credentials configured for used of the app |
55
+ +------------------------+----------+-----------+-------------------------------------------------------+
56
+
57
+ Return the list of arbitrary days
58
+
59
+
60
+ """ # noqa
61
+
62
+ _credentials: Dict = {
63
+ "aws_key": str,
64
+ "aws_secret": str,
65
+ "client_id": str,
66
+ "client_secret": str,
67
+ "service": str,
68
+ "region_name": str,
69
+ "bucket": str,
70
+ }
71
+
72
+ def __init__(self, *args, **kwargs) -> None:
73
+ self.region_name: str = kwargs.pop('region_name', None)
74
+ self.service: str = kwargs.pop('service', 's3')
75
+ self.bucket: Optional[str] = kwargs.pop('bucket', None)
76
+ self.ContentType: str = kwargs.pop('ContentType', 'application/octet-stream')
77
+ if 'config_section' in kwargs:
78
+ self._config = kwargs.pop('config_section', 'default')
79
+ else:
80
+ self._config: str = kwargs.pop('config', 'default')
81
+ super().__init__(*args, **kwargs)
82
+
83
+ def define_host(self):
84
+ return True
85
+
86
+ async def open(
87
+ self,
88
+ host: str = None,
89
+ port: int = None,
90
+ credentials: dict = None,
91
+ **kwargs
92
+ ):
93
+ use_credentials = credentials.pop('use_credentials', True) if credentials else True
94
+ service = self.credentials.get('service', self.service)
95
+
96
+ if use_credentials is False:
97
+ self._logger.notice("Boto3: Using default credentials from environment")
98
+ self._connection = boto3.client(
99
+ service,
100
+ region_name=self.credentials.get("region_name", self.region_name)
101
+ )
102
+ else:
103
+ self._logger.notice("Boto3: Enter signed with explicit credentials")
104
+ cred = {
105
+ "aws_access_key_id": self.credentials["aws_key"],
106
+ "aws_secret_access_key": self.credentials["aws_secret"],
107
+ "region_name": self.credentials["region_name"],
108
+ }
109
+ self._connection = boto3.client(
110
+ service,
111
+ **cred
112
+ )
113
+ return self
114
+
115
+ def processing_credentials(self):
116
+ # getting credentials from self.credentials:
117
+ if self.credentials:
118
+ super().processing_credentials()
119
+ else:
120
+ # getting credentials from config
121
+ self.credentials = AWS_CREDENTIALS.get(self._config)
122
+ if not self.credentials:
123
+ raise ValueError(
124
+ f'Credentials not found for section {self._config}.'
125
+ )
126
+ ## getting Tenant and Site from credentials:
127
+ self.region_name = self.credentials.get('region_name', aws_region)
128
+ self.bucket = self.credentials.get('bucket_name', self.bucket)
129
+ self.service = self.credentials.get('service', 's3')
130
+
131
+ async def get_s3_object(self, bucket: str, filename: str):
132
+ """
133
+ Retrieve an object from an S3 bucket.
134
+
135
+ Parameters
136
+ ----------
137
+ bucket: str
138
+ The name of the S3 bucket.
139
+ filename: str
140
+ The name of the file (key) in the S3 bucket.
141
+
142
+ Returns
143
+ -------
144
+ dict
145
+ A dictionary containing the object data and metadata.
146
+
147
+ Raises
148
+ ------
149
+ FileNotFound
150
+ If the object is not found in the bucket.
151
+ ComponentError
152
+ If there is an issue with retrieving the object.
153
+ """
154
+ # Ensure connection is established
155
+ if not self._connection:
156
+ raise ComponentError(
157
+ "S3 client is not connected. Call `open` first."
158
+ )
159
+
160
+ # Get the object from S3
161
+ obj = self._connection.get_object(Bucket=bucket, Key=filename)
162
+ # Validate the response
163
+ status_code = int(obj["ResponseMetadata"]["HTTPStatusCode"])
164
+ if status_code != 200:
165
+ raise FileNotFound(
166
+ f"File '{filename}' not found in bucket '{bucket}'."
167
+ )
168
+ return obj
169
+
170
+ async def download_file(self, filename, obj):
171
+ result = None
172
+ ob_info = obj["ResponseMetadata"]["HTTPHeaders"]
173
+ rsp = obj["ResponseMetadata"]
174
+ status_code = int(rsp["HTTPStatusCode"])
175
+ if status_code == 200:
176
+ print('Content ', ob_info["content-type"])
177
+ filepath = self.directory.joinpath(filename)
178
+ if ob_info["content-type"] == self.ContentType:
179
+ contenttype = ob_info["content-type"]
180
+
181
+ # Usar BytesIO solo cuando es un archivo individual
182
+ if hasattr(self, '_srcfiles') and not self._srcfiles:
183
+ # Para múltiples archivos, usar streaming
184
+ async with aiofiles.open(filepath, mode="wb") as fp:
185
+ with obj["Body"] as stream:
186
+ chunk_size = 8192 # 8KB chunks
187
+ while True:
188
+ chunk = stream.read(chunk_size)
189
+ if not chunk:
190
+ break
191
+ await fp.write(chunk)
192
+ result = {
193
+ "type": contenttype,
194
+ "file": filepath
195
+ }
196
+ else:
197
+ # Para un archivo individual, mantener BytesIO
198
+ data = None
199
+ with obj["Body"] as stream:
200
+ data = stream.read()
201
+ output = BytesIO()
202
+ output.write(data)
203
+ output.seek(0)
204
+ result = {"type": contenttype, "data": output, "file": filepath}
205
+ # then save it into directory
206
+ await self.save_attachment(filepath, data)
207
+ else:
208
+ return FileError(
209
+ f'S3: Wrong File type: {ob_info["content-type"]!s}'
210
+ )
211
+ else:
212
+ return FileNotFound(
213
+ f"S3: File {filename} was not found: {rsp!s}"
214
+ )
215
+ return result
216
+
217
+ async def save_attachment(self, filepath, content):
218
+ try:
219
+ self._logger.info(f"S3: Saving attachment file: {filepath}")
220
+ if filepath.exists() is True:
221
+ if (
222
+ "replace" in self.destination and self.destination["replace"] is True
223
+ ):
224
+ # overwrite only if replace is True
225
+ async with aiofiles.open(filepath, mode="wb") as fp:
226
+ await fp.write(content)
227
+ else:
228
+ self._logger.warning(
229
+ f"S3: File {filepath!s} was not saved, already exists."
230
+ )
231
+ else:
232
+ # saving file:
233
+ async with aiofiles.open(filepath, mode="wb") as fp:
234
+ await fp.write(content)
235
+ except Exception as err:
236
+ raise FileError(f"File {filepath} was not saved: {err}") from err
237
+
238
+ async def close(self, **kwargs):
239
+ self._connection = None
240
+
241
+ async def _list_objects_with_pagination(self, kwargs: dict) -> List:
242
+ """Helper method to handle S3 pagination"""
243
+ all_objects = []
244
+ while True:
245
+ response = self._connection.list_objects_v2(**kwargs)
246
+ if response["KeyCount"] == 0:
247
+ if not all_objects: # Solo lanzar error si no hay objetos
248
+ raise FileNotFound(
249
+ f"S3 Bucket Error: Content not found on {self.bucket}"
250
+ )
251
+ break
252
+
253
+ all_objects.extend(response.get("Contents", []))
254
+
255
+ if not response.get("IsTruncated"): # No hay más resultados
256
+ break
257
+
258
+ kwargs["ContinuationToken"] = response["NextContinuationToken"]
259
+
260
+ return all_objects
261
+
262
+ async def s3_list(self, suffix: str = "") -> List:
263
+ kwargs = {
264
+ "Bucket": self.bucket,
265
+ "Delimiter": "/",
266
+ "Prefix": self.source_dir,
267
+ "MaxKeys": 1000
268
+ }
269
+ prefix = self.source_dir
270
+ files = []
271
+ _patterns = []
272
+
273
+ if not self._srcfiles:
274
+ _patterns.append(re.compile(f"^{self.source_dir}.{suffix}+$"))
275
+ # List objects in the S3 bucket with the specified prefix
276
+ objects = await self._list_objects_with_pagination(kwargs)
277
+
278
+ for obj in objects:
279
+ key = obj["Key"]
280
+ if obj["Size"] == 0:
281
+ # is a directory
282
+ continue
283
+ if suffix is not None:
284
+ if key.startswith(prefix) and re.match(
285
+ prefix + suffix, key
286
+ ):
287
+ files.append(obj)
288
+ else:
289
+ try:
290
+ for pat in _patterns:
291
+ mt = pat.match(key)
292
+ if mt:
293
+ files.append(obj)
294
+ except Exception as e:
295
+ self._logger.exception(e, stack_info=True)
296
+
297
+ if self._srcfiles:
298
+ for file in self._srcfiles:
299
+ _patterns.append(re.compile(f"^{self.source_dir}.{file}+$"))
300
+ objects = await self._list_objects_with_pagination(kwargs)
301
+
302
+ for obj in objects:
303
+ key = obj["Key"]
304
+ if obj["Size"] == 0:
305
+ continue
306
+ try:
307
+ if hasattr(self, "source") and "filename" in self.source:
308
+ if self.source["filename"] == key:
309
+ files.append(obj)
310
+ except (KeyError, AttributeError):
311
+ pass
312
+ if suffix is not None:
313
+ if key.startswith(prefix) and re.match(
314
+ prefix + suffix, key
315
+ ):
316
+ files.append(obj)
317
+ else:
318
+ try:
319
+ for pat in _patterns:
320
+ mt = pat.match(key)
321
+ if mt:
322
+ files.append(obj)
323
+ except Exception as e:
324
+ self._logger.exception(e, stack_info=True)
325
+
326
+ return files
@@ -0,0 +1,173 @@
1
+ from abc import ABC
2
+ from typing import Union
3
+ from pathlib import Path
4
+ import asyncio
5
+ import aiofiles
6
+ import dropbox
7
+ from dropbox.exceptions import ApiError
8
+ from dropbox.files import WriteMode
9
+ from ..exceptions import ComponentError
10
+
11
+
12
+ class DropboxClient(ABC):
13
+ """
14
+ Dropbox Client for downloading and uploading files and folders to/from Dropbox.
15
+ """
16
+ def __init__(
17
+ self,
18
+ *args,
19
+ access_key: Union[str, dict] = None,
20
+ **kwargs
21
+ ):
22
+ self.access_key: str = access_key
23
+ self.dbx = dropbox.Dropbox(self.access_key)
24
+ super().__init__(*args, **kwargs)
25
+
26
+ async def download_file(
27
+ self,
28
+ source_filename: str,
29
+ destination_dir: Union[str, Path] = "."
30
+ ) -> Path:
31
+ """
32
+ Download a file from Dropbox by its name.
33
+ """
34
+ try:
35
+ search_result = await asyncio.to_thread(
36
+ self.dbx.files_search_v2,
37
+ query=source_filename
38
+ )
39
+ if not search_result.matches:
40
+ raise ComponentError(
41
+ f"File '{source_filename}' not found in Dropbox."
42
+ )
43
+
44
+ file_path = Path(destination_dir) / source_filename
45
+ file_metadata = search_result.matches[0].metadata
46
+ file_id = file_metadata.metadata.id
47
+
48
+ async with aiofiles.open(file_path, 'wb') as f:
49
+ _, res = await asyncio.to_thread(self.dbx.files_download, file_id)
50
+ await f.write(res.content)
51
+
52
+ return file_path
53
+
54
+ except ApiError as error:
55
+ raise ComponentError(
56
+ f"Error downloading file from Dropbox: {error}"
57
+ )
58
+
59
+ async def download_folder(
60
+ self,
61
+ folder_name: str,
62
+ destination_dir: Union[str, Path] = "."
63
+ ) -> None:
64
+ """
65
+ Download all files within a specified Dropbox folder by name.
66
+ """
67
+ try:
68
+ search_result = await asyncio.to_thread(
69
+ self.dbx.files_search_v2,
70
+ query=folder_name
71
+ )
72
+ if not search_result.matches:
73
+ raise ComponentError(
74
+ f"Folder '{folder_name}' not found in Dropbox."
75
+ )
76
+
77
+ folder_metadata = search_result.matches[0].metadata
78
+ folder_id = folder_metadata.metadata.id
79
+ destination_dir = Path(destination_dir) / folder_name
80
+ destination_dir.mkdir(parents=True, exist_ok=True)
81
+
82
+ entries = await asyncio.to_thread(
83
+ self.dbx.files_list_folder,
84
+ folder_id
85
+ )
86
+
87
+ for entry in entries.entries:
88
+ if isinstance(entry, dropbox.files.FileMetadata):
89
+ file_name = entry.name
90
+ file_path = destination_dir / file_name
91
+
92
+ async with aiofiles.open(file_path, 'wb') as f:
93
+ _, res = await asyncio.to_thread(self.dbx.files_download, entry.id)
94
+ await f.write(res.content)
95
+
96
+ print(
97
+ f"Downloaded '{file_name}' to '{file_path}'."
98
+ )
99
+
100
+ except ApiError as error:
101
+ raise ComponentError(
102
+ f"Error downloading folder '{folder_name}' from Dropbox: {error}"
103
+ )
104
+
105
+ async def upload_file(
106
+ self,
107
+ source_filepath: Union[str, Path],
108
+ destination_path: Union[str, Path] = "/"
109
+ ) -> None:
110
+ """
111
+ Upload a file to Dropbox.
112
+ """
113
+ source_filepath = Path(source_filepath)
114
+ if not source_filepath.exists() or not source_filepath.is_file():
115
+ raise ComponentError(
116
+ f"Source file '{source_filepath}' does not exist."
117
+ )
118
+
119
+ try:
120
+ async with aiofiles.open(source_filepath, 'rb') as f:
121
+ file_data = await f.read()
122
+ destination_path = str(Path(destination_path) / source_filepath.name)
123
+
124
+ await asyncio.to_thread(
125
+ self.dbx.files_upload,
126
+ file_data,
127
+ destination_path,
128
+ mode=WriteMode.overwrite
129
+ )
130
+ print(
131
+ f"Uploaded file '{source_filepath.name}' to '{destination_path}'."
132
+ )
133
+
134
+ except ApiError as error:
135
+ raise ComponentError(
136
+ f"Error uploading file '{source_filepath}': {error}"
137
+ )
138
+
139
+ async def upload_folder(
140
+ self,
141
+ source_dir: Union[str, Path],
142
+ destination_path: Union[str, Path] = "/"
143
+ ) -> None:
144
+ """
145
+ Upload all files within a specified local folder to Dropbox.
146
+ """
147
+ source_dir = Path(source_dir)
148
+ if not source_dir.exists() or not source_dir.is_dir():
149
+ raise ComponentError(
150
+ f"Source directory '{source_dir}' does not exist."
151
+ )
152
+
153
+ for file_path in source_dir.rglob('*'):
154
+ if file_path.is_file():
155
+ # Preserve directory structure within Dropbox
156
+ relative_path = file_path.relative_to(source_dir)
157
+ dropbox_path = str(Path(destination_path) / relative_path)
158
+
159
+ try:
160
+ async with aiofiles.open(file_path, 'rb') as f:
161
+ file_data = await f.read()
162
+ await asyncio.to_thread(
163
+ self.dbx.files_upload,
164
+ file_data,
165
+ dropbox_path,
166
+ mode=WriteMode.overwrite
167
+ )
168
+ print(f"Uploaded '{file_path}' to '{dropbox_path}'.")
169
+
170
+ except ApiError as error:
171
+ raise ComponentError(
172
+ f"Error uploading file '{file_path}': {error}"
173
+ )
@@ -0,0 +1,94 @@
1
+ from pathlib import Path
2
+ from typing import Callable
3
+ import pandas as pd
4
+ from openpyxl import load_workbook, Workbook
5
+ from openpyxl.utils.dataframe import dataframe_to_rows
6
+ from openpyxl.workbook import Workbook as OpenpyxlWorkbook
7
+
8
+
9
+ class ExcelHandler:
10
+ def pandas_to_excel(self, df: pd.DataFrame, file_path: Path, **kwargs):
11
+ """
12
+ Save a pandas DataFrame to an Excel file.
13
+
14
+ :param df: DataFrame to save.
15
+ :param file_path: Path to save the Excel file.
16
+ :param kwargs: Additional keyword arguments for pandas' to_excel method.
17
+ """
18
+ df.to_excel(file_path, index=False, **kwargs)
19
+
20
+ def edit_excel(self, file_path: Path, edit_func: Callable[[OpenpyxlWorkbook], None]):
21
+ """
22
+ Edit an existing Excel file using a provided function.
23
+
24
+ :param file_path: Path to the Excel file.
25
+ :param edit_func: Function that takes a Workbook object and edits it.
26
+ """
27
+ if not file_path.exists():
28
+ raise FileNotFoundError(f"The file {file_path} does not exist.")
29
+ wb = load_workbook(file_path)
30
+ edit_func(wb)
31
+ wb.save(file_path)
32
+
33
+ def append_data_to_excel(
34
+ self,
35
+ df: pd.DataFrame,
36
+ file_path: Path,
37
+ sheet_name: str,
38
+ start_row: int = None,
39
+ start_col: int = 1,
40
+ include_header: bool = False
41
+ ):
42
+ """
43
+ Append data from a DataFrame to an existing Excel file.
44
+
45
+ :param df: DataFrame containing data to append.
46
+ :param file_path: Path to the Excel file.
47
+ :param sheet_name: Name of the sheet to append data to.
48
+ :param start_row: Starting row to append data (default is after last row).
49
+ :param start_col: Starting column to append data.
50
+ :param include_header: Whether to include the DataFrame's header.
51
+ """
52
+ if not file_path.exists():
53
+ raise FileNotFoundError(f"The file {file_path} does not exist.")
54
+ wb = load_workbook(file_path)
55
+ if sheet_name not in wb.sheetnames:
56
+ ws = wb.create_sheet(title=sheet_name)
57
+ start_row = 1
58
+ else:
59
+ ws = wb[sheet_name]
60
+ if start_row is None:
61
+ start_row = ws.max_row + 1
62
+
63
+ for r_idx, row in enumerate(
64
+ dataframe_to_rows(df, index=False, header=include_header), start=start_row
65
+ ):
66
+ for c_idx, value in enumerate(row, start=start_col):
67
+ ws.cell(row=r_idx, column=c_idx, value=value)
68
+
69
+ wb.save(file_path)
70
+
71
+ def create_new_excel_file(self, file_path: Path):
72
+ """
73
+ Create a new Excel file.
74
+
75
+ :param file_path: Path where the new Excel file will be saved.
76
+ """
77
+ if file_path.exists():
78
+ raise FileExistsError(f"The file {file_path} already exists.")
79
+ wb = Workbook()
80
+ wb.save(file_path)
81
+
82
+ def create_excel_from_template(self, template_path: Path, new_file_path: Path):
83
+ """
84
+ Create a new Excel file from a template.
85
+
86
+ :param template_path: Path to the Excel template.
87
+ :param new_file_path: Path where the new Excel file will be saved.
88
+ """
89
+ if not template_path.exists():
90
+ raise FileNotFoundError(f"The template {template_path} does not exist.")
91
+ if new_file_path.exists():
92
+ raise FileExistsError(f"The file {new_file_path} already exists.")
93
+ wb = load_workbook(template_path)
94
+ wb.save(new_file_path)