flowtask 5.8.4__cp312-cp312-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.
- flowtask/__init__.py +93 -0
- flowtask/__main__.py +38 -0
- flowtask/bots/__init__.py +6 -0
- flowtask/bots/check.py +93 -0
- flowtask/bots/codebot.py +51 -0
- flowtask/components/ASPX.py +148 -0
- flowtask/components/AddDataset.py +352 -0
- flowtask/components/Amazon.py +523 -0
- flowtask/components/AutoTask.py +314 -0
- flowtask/components/Azure.py +80 -0
- flowtask/components/AzureUsers.py +106 -0
- flowtask/components/BaseAction.py +91 -0
- flowtask/components/BaseLoop.py +198 -0
- flowtask/components/BestBuy.py +800 -0
- flowtask/components/CSVToGCS.py +120 -0
- flowtask/components/CompanyScraper/__init__.py +1 -0
- flowtask/components/CompanyScraper/parsers/__init__.py +6 -0
- flowtask/components/CompanyScraper/parsers/base.py +102 -0
- flowtask/components/CompanyScraper/parsers/explorium.py +192 -0
- flowtask/components/CompanyScraper/parsers/leadiq.py +206 -0
- flowtask/components/CompanyScraper/parsers/rocket.py +133 -0
- flowtask/components/CompanyScraper/parsers/siccode.py +109 -0
- flowtask/components/CompanyScraper/parsers/visualvisitor.py +130 -0
- flowtask/components/CompanyScraper/parsers/zoominfo.py +118 -0
- flowtask/components/CompanyScraper/scrapper.py +1054 -0
- flowtask/components/CopyTo.py +177 -0
- flowtask/components/CopyToBigQuery.py +243 -0
- flowtask/components/CopyToMongoDB.py +291 -0
- flowtask/components/CopyToPg.py +609 -0
- flowtask/components/CopyToRethink.py +207 -0
- flowtask/components/CreateGCSBucket.py +102 -0
- flowtask/components/CreateReport/CreateReport.py +228 -0
- flowtask/components/CreateReport/__init__.py +9 -0
- flowtask/components/CreateReport/charts/__init__.py +15 -0
- flowtask/components/CreateReport/charts/bar.py +51 -0
- flowtask/components/CreateReport/charts/base.py +66 -0
- flowtask/components/CreateReport/charts/pie.py +64 -0
- flowtask/components/CreateReport/utils.py +9 -0
- flowtask/components/CustomerSatisfaction.py +196 -0
- flowtask/components/DataInput.py +200 -0
- flowtask/components/DateList.py +255 -0
- flowtask/components/DbClient.py +163 -0
- flowtask/components/DialPad.py +146 -0
- flowtask/components/DocumentDBQuery.py +200 -0
- flowtask/components/DownloadFrom.py +371 -0
- flowtask/components/DownloadFromD2L.py +113 -0
- flowtask/components/DownloadFromFTP.py +181 -0
- flowtask/components/DownloadFromIMAP.py +315 -0
- flowtask/components/DownloadFromS3.py +198 -0
- flowtask/components/DownloadFromSFTP.py +265 -0
- flowtask/components/DownloadFromSharepoint.py +110 -0
- flowtask/components/DownloadFromSmartSheet.py +114 -0
- flowtask/components/DownloadS3File.py +229 -0
- flowtask/components/Dummy.py +59 -0
- flowtask/components/DuplicatePhoto.py +411 -0
- flowtask/components/EmployeeEvaluation.py +237 -0
- flowtask/components/ExecuteSQL.py +323 -0
- flowtask/components/ExtractHTML.py +178 -0
- flowtask/components/FileBase.py +178 -0
- flowtask/components/FileCopy.py +181 -0
- flowtask/components/FileDelete.py +82 -0
- flowtask/components/FileExists.py +146 -0
- flowtask/components/FileIteratorDelete.py +112 -0
- flowtask/components/FileList.py +194 -0
- flowtask/components/FileOpen.py +75 -0
- flowtask/components/FileRead.py +120 -0
- flowtask/components/FileRename.py +106 -0
- flowtask/components/FilterIf.py +284 -0
- flowtask/components/FilterRows/FilterRows.py +200 -0
- flowtask/components/FilterRows/__init__.py +10 -0
- flowtask/components/FilterRows/functions.py +4 -0
- flowtask/components/GCSToBigQuery.py +103 -0
- flowtask/components/GoogleA4.py +150 -0
- flowtask/components/GoogleGeoCoding.py +344 -0
- flowtask/components/GooglePlaces.py +315 -0
- flowtask/components/GoogleSearch.py +539 -0
- flowtask/components/HTTPClient.py +268 -0
- flowtask/components/ICIMS.py +146 -0
- flowtask/components/IF.py +179 -0
- flowtask/components/IcimsFolderCopy.py +173 -0
- flowtask/components/ImageFeatures/__init__.py +5 -0
- flowtask/components/ImageFeatures/process.py +233 -0
- flowtask/components/IteratorBase.py +251 -0
- flowtask/components/LangchainLoader/__init__.py +5 -0
- flowtask/components/LangchainLoader/loader.py +194 -0
- flowtask/components/LangchainLoader/loaders/__init__.py +22 -0
- flowtask/components/LangchainLoader/loaders/abstract.py +362 -0
- flowtask/components/LangchainLoader/loaders/basepdf.py +50 -0
- flowtask/components/LangchainLoader/loaders/docx.py +91 -0
- flowtask/components/LangchainLoader/loaders/html.py +119 -0
- flowtask/components/LangchainLoader/loaders/pdfblocks.py +146 -0
- flowtask/components/LangchainLoader/loaders/pdfmark.py +79 -0
- flowtask/components/LangchainLoader/loaders/pdftables.py +135 -0
- flowtask/components/LangchainLoader/loaders/qa.py +67 -0
- flowtask/components/LangchainLoader/loaders/txt.py +55 -0
- flowtask/components/LeadIQ.py +650 -0
- flowtask/components/Loop.py +253 -0
- flowtask/components/Lowes.py +334 -0
- flowtask/components/MS365Usage.py +156 -0
- flowtask/components/MSTeamsMessages.py +320 -0
- flowtask/components/MarketClustering.py +1051 -0
- flowtask/components/MergeFiles.py +362 -0
- flowtask/components/MilvusOutput.py +87 -0
- flowtask/components/NearByStores.py +175 -0
- flowtask/components/NetworkNinja/__init__.py +6 -0
- flowtask/components/NetworkNinja/models/__init__.py +52 -0
- flowtask/components/NetworkNinja/models/abstract.py +177 -0
- flowtask/components/NetworkNinja/models/account.py +39 -0
- flowtask/components/NetworkNinja/models/client.py +19 -0
- flowtask/components/NetworkNinja/models/district.py +14 -0
- flowtask/components/NetworkNinja/models/events.py +101 -0
- flowtask/components/NetworkNinja/models/forms.py +499 -0
- flowtask/components/NetworkNinja/models/market.py +16 -0
- flowtask/components/NetworkNinja/models/organization.py +34 -0
- flowtask/components/NetworkNinja/models/photos.py +125 -0
- flowtask/components/NetworkNinja/models/project.py +44 -0
- flowtask/components/NetworkNinja/models/region.py +28 -0
- flowtask/components/NetworkNinja/models/store.py +203 -0
- flowtask/components/NetworkNinja/models/user.py +151 -0
- flowtask/components/NetworkNinja/router.py +854 -0
- flowtask/components/Odoo.py +175 -0
- flowtask/components/OdooInjector.py +192 -0
- flowtask/components/OpenFromXML.py +126 -0
- flowtask/components/OpenWeather.py +41 -0
- flowtask/components/OpenWithBase.py +616 -0
- flowtask/components/OpenWithPandas.py +715 -0
- flowtask/components/PGPDecrypt.py +199 -0
- flowtask/components/PandasIterator.py +187 -0
- flowtask/components/PandasToFile.py +189 -0
- flowtask/components/Paradox.py +339 -0
- flowtask/components/ParamIterator.py +117 -0
- flowtask/components/ParseHTML.py +84 -0
- flowtask/components/PlacerStores.py +249 -0
- flowtask/components/Pokemon.py +507 -0
- flowtask/components/PositiveBot.py +62 -0
- flowtask/components/PowerPointSlide.py +400 -0
- flowtask/components/PrintMessage.py +127 -0
- flowtask/components/ProductCompetitors/__init__.py +5 -0
- flowtask/components/ProductCompetitors/parsers/__init__.py +7 -0
- flowtask/components/ProductCompetitors/parsers/base.py +72 -0
- flowtask/components/ProductCompetitors/parsers/bestbuy.py +86 -0
- flowtask/components/ProductCompetitors/parsers/lowes.py +103 -0
- flowtask/components/ProductCompetitors/scrapper.py +155 -0
- flowtask/components/ProductCompliant.py +169 -0
- flowtask/components/ProductInfo/__init__.py +1 -0
- flowtask/components/ProductInfo/parsers/__init__.py +5 -0
- flowtask/components/ProductInfo/parsers/base.py +83 -0
- flowtask/components/ProductInfo/parsers/brother.py +97 -0
- flowtask/components/ProductInfo/parsers/canon.py +167 -0
- flowtask/components/ProductInfo/parsers/epson.py +118 -0
- flowtask/components/ProductInfo/parsers/hp.py +131 -0
- flowtask/components/ProductInfo/parsers/samsung.py +97 -0
- flowtask/components/ProductInfo/scraper.py +319 -0
- flowtask/components/ProductPricing.py +118 -0
- flowtask/components/QS.py +261 -0
- flowtask/components/QSBase.py +201 -0
- flowtask/components/QueryIterator.py +273 -0
- flowtask/components/QueryToInsert.py +327 -0
- flowtask/components/QueryToPandas.py +432 -0
- flowtask/components/RESTClient.py +195 -0
- flowtask/components/RethinkDBQuery.py +189 -0
- flowtask/components/Rsync.py +74 -0
- flowtask/components/RunSSH.py +59 -0
- flowtask/components/RunShell.py +71 -0
- flowtask/components/SalesForce.py +20 -0
- flowtask/components/SaveImageBank/__init__.py +257 -0
- flowtask/components/SchedulingVisits.py +592 -0
- flowtask/components/ScrapPage.py +216 -0
- flowtask/components/ScrapSearch.py +79 -0
- flowtask/components/SendNotify.py +257 -0
- flowtask/components/SentimentAnalysis.py +694 -0
- flowtask/components/ServiceScrapper/__init__.py +5 -0
- flowtask/components/ServiceScrapper/parsers/__init__.py +1 -0
- flowtask/components/ServiceScrapper/parsers/base.py +94 -0
- flowtask/components/ServiceScrapper/parsers/costco.py +93 -0
- flowtask/components/ServiceScrapper/scrapper.py +199 -0
- flowtask/components/SetVariables.py +156 -0
- flowtask/components/SubTask.py +182 -0
- flowtask/components/SuiteCRM.py +48 -0
- flowtask/components/Switch.py +175 -0
- flowtask/components/TableBase.py +148 -0
- flowtask/components/TableDelete.py +312 -0
- flowtask/components/TableInput.py +143 -0
- flowtask/components/TableOutput/TableOutput.py +384 -0
- flowtask/components/TableOutput/__init__.py +3 -0
- flowtask/components/TableSchema.py +534 -0
- flowtask/components/Target.py +223 -0
- flowtask/components/ThumbnailGenerator.py +156 -0
- flowtask/components/ToPandas.py +67 -0
- flowtask/components/TransformRows/TransformRows.py +507 -0
- flowtask/components/TransformRows/__init__.py +9 -0
- flowtask/components/TransformRows/functions.py +559 -0
- flowtask/components/TransposeRows.py +176 -0
- flowtask/components/UPCDatabase.py +86 -0
- flowtask/components/UnGzip.py +171 -0
- flowtask/components/Uncompress.py +172 -0
- flowtask/components/UniqueRows.py +126 -0
- flowtask/components/Unzip.py +107 -0
- flowtask/components/UpdateOperationalVars.py +147 -0
- flowtask/components/UploadTo.py +299 -0
- flowtask/components/UploadToS3.py +136 -0
- flowtask/components/UploadToSFTP.py +160 -0
- flowtask/components/UploadToSharepoint.py +205 -0
- flowtask/components/UserFunc.py +122 -0
- flowtask/components/VivaTracker.py +140 -0
- flowtask/components/WSDLClient.py +123 -0
- flowtask/components/Wait.py +18 -0
- flowtask/components/Walmart.py +199 -0
- flowtask/components/Workplace.py +134 -0
- flowtask/components/XMLToPandas.py +267 -0
- flowtask/components/Zammad/__init__.py +41 -0
- flowtask/components/Zammad/models.py +0 -0
- flowtask/components/ZoomInfoScraper.py +409 -0
- flowtask/components/__init__.py +104 -0
- flowtask/components/abstract.py +18 -0
- flowtask/components/flow.py +530 -0
- flowtask/components/google.py +335 -0
- flowtask/components/group.py +221 -0
- flowtask/components/py.typed +0 -0
- flowtask/components/reviewscrap.py +132 -0
- flowtask/components/tAutoincrement.py +117 -0
- flowtask/components/tConcat.py +109 -0
- flowtask/components/tExplode.py +119 -0
- flowtask/components/tFilter.py +184 -0
- flowtask/components/tGroup.py +236 -0
- flowtask/components/tJoin.py +270 -0
- flowtask/components/tMap/__init__.py +9 -0
- flowtask/components/tMap/functions.py +54 -0
- flowtask/components/tMap/tMap.py +450 -0
- flowtask/components/tMelt.py +112 -0
- flowtask/components/tMerge.py +114 -0
- flowtask/components/tOrder.py +93 -0
- flowtask/components/tPandas.py +94 -0
- flowtask/components/tPivot.py +71 -0
- flowtask/components/tPluckCols.py +76 -0
- flowtask/components/tUnnest.py +82 -0
- flowtask/components/user.py +401 -0
- flowtask/conf.py +457 -0
- flowtask/download.py +102 -0
- flowtask/events/__init__.py +11 -0
- flowtask/events/events/__init__.py +20 -0
- flowtask/events/events/abstract.py +95 -0
- flowtask/events/events/alerts/__init__.py +362 -0
- flowtask/events/events/alerts/colfunctions.py +131 -0
- flowtask/events/events/alerts/functions.py +158 -0
- flowtask/events/events/dummy.py +12 -0
- flowtask/events/events/exec.py +124 -0
- flowtask/events/events/file/__init__.py +7 -0
- flowtask/events/events/file/base.py +51 -0
- flowtask/events/events/file/copy.py +23 -0
- flowtask/events/events/file/delete.py +16 -0
- flowtask/events/events/interfaces/__init__.py +9 -0
- flowtask/events/events/interfaces/client.py +67 -0
- flowtask/events/events/interfaces/credentials.py +28 -0
- flowtask/events/events/interfaces/notifications.py +58 -0
- flowtask/events/events/jira.py +122 -0
- flowtask/events/events/log.py +26 -0
- flowtask/events/events/logerr.py +52 -0
- flowtask/events/events/notify.py +59 -0
- flowtask/events/events/notify_event.py +160 -0
- flowtask/events/events/publish.py +54 -0
- flowtask/events/events/sendfile.py +104 -0
- flowtask/events/events/task.py +97 -0
- flowtask/events/events/teams.py +98 -0
- flowtask/events/events/webhook.py +58 -0
- flowtask/events/manager.py +287 -0
- flowtask/exceptions.c +39393 -0
- flowtask/exceptions.cpython-312-x86_64-linux-gnu.so +0 -0
- flowtask/extensions/__init__.py +3 -0
- flowtask/extensions/abstract.py +82 -0
- flowtask/extensions/logging/__init__.py +65 -0
- flowtask/hooks/__init__.py +9 -0
- flowtask/hooks/actions/__init__.py +22 -0
- flowtask/hooks/actions/abstract.py +66 -0
- flowtask/hooks/actions/dummy.py +23 -0
- flowtask/hooks/actions/jira.py +74 -0
- flowtask/hooks/actions/rest.py +320 -0
- flowtask/hooks/actions/sampledata.py +37 -0
- flowtask/hooks/actions/sensor.py +23 -0
- flowtask/hooks/actions/task.py +9 -0
- flowtask/hooks/actions/ticket.py +37 -0
- flowtask/hooks/actions/zammad.py +55 -0
- flowtask/hooks/hook.py +62 -0
- flowtask/hooks/models.py +17 -0
- flowtask/hooks/service.py +187 -0
- flowtask/hooks/step.py +91 -0
- flowtask/hooks/types/__init__.py +23 -0
- flowtask/hooks/types/base.py +129 -0
- flowtask/hooks/types/brokers/__init__.py +11 -0
- flowtask/hooks/types/brokers/base.py +54 -0
- flowtask/hooks/types/brokers/mqtt.py +35 -0
- flowtask/hooks/types/brokers/rabbitmq.py +82 -0
- flowtask/hooks/types/brokers/redis.py +83 -0
- flowtask/hooks/types/brokers/sqs.py +44 -0
- flowtask/hooks/types/fs.py +232 -0
- flowtask/hooks/types/http.py +49 -0
- flowtask/hooks/types/imap.py +200 -0
- flowtask/hooks/types/jira.py +279 -0
- flowtask/hooks/types/mail.py +205 -0
- flowtask/hooks/types/postgres.py +98 -0
- flowtask/hooks/types/responses/__init__.py +8 -0
- flowtask/hooks/types/responses/base.py +5 -0
- flowtask/hooks/types/sharepoint.py +288 -0
- flowtask/hooks/types/ssh.py +141 -0
- flowtask/hooks/types/tagged.py +59 -0
- flowtask/hooks/types/upload.py +85 -0
- flowtask/hooks/types/watch.py +71 -0
- flowtask/hooks/types/web.py +36 -0
- flowtask/interfaces/AzureClient.py +137 -0
- flowtask/interfaces/AzureGraph.py +839 -0
- flowtask/interfaces/Boto3Client.py +326 -0
- flowtask/interfaces/DropboxClient.py +173 -0
- flowtask/interfaces/ExcelHandler.py +94 -0
- flowtask/interfaces/FTPClient.py +131 -0
- flowtask/interfaces/GoogleCalendar.py +201 -0
- flowtask/interfaces/GoogleClient.py +133 -0
- flowtask/interfaces/GoogleDrive.py +127 -0
- flowtask/interfaces/GoogleGCS.py +89 -0
- flowtask/interfaces/GoogleGeocoding.py +93 -0
- flowtask/interfaces/GoogleLang.py +114 -0
- flowtask/interfaces/GooglePub.py +61 -0
- flowtask/interfaces/GoogleSheet.py +68 -0
- flowtask/interfaces/IMAPClient.py +137 -0
- flowtask/interfaces/O365Calendar.py +113 -0
- flowtask/interfaces/O365Client.py +220 -0
- flowtask/interfaces/OneDrive.py +284 -0
- flowtask/interfaces/Outlook.py +155 -0
- flowtask/interfaces/ParrotBot.py +130 -0
- flowtask/interfaces/SSHClient.py +378 -0
- flowtask/interfaces/Sharepoint.py +496 -0
- flowtask/interfaces/__init__.py +36 -0
- flowtask/interfaces/azureauth.py +119 -0
- flowtask/interfaces/cache.py +201 -0
- flowtask/interfaces/client.py +82 -0
- flowtask/interfaces/compress.py +525 -0
- flowtask/interfaces/credentials.py +124 -0
- flowtask/interfaces/d2l.py +239 -0
- flowtask/interfaces/databases/__init__.py +5 -0
- flowtask/interfaces/databases/db.py +223 -0
- flowtask/interfaces/databases/documentdb.py +55 -0
- flowtask/interfaces/databases/rethink.py +39 -0
- flowtask/interfaces/dataframes/__init__.py +11 -0
- flowtask/interfaces/dataframes/abstract.py +21 -0
- flowtask/interfaces/dataframes/arrow.py +71 -0
- flowtask/interfaces/dataframes/dt.py +69 -0
- flowtask/interfaces/dataframes/pandas.py +167 -0
- flowtask/interfaces/dataframes/polars.py +60 -0
- flowtask/interfaces/db.py +263 -0
- flowtask/interfaces/env.py +46 -0
- flowtask/interfaces/func.py +137 -0
- flowtask/interfaces/http.py +1780 -0
- flowtask/interfaces/locale.py +40 -0
- flowtask/interfaces/log.py +75 -0
- flowtask/interfaces/mask.py +143 -0
- flowtask/interfaces/notification.py +154 -0
- flowtask/interfaces/playwright.py +339 -0
- flowtask/interfaces/powerpoint.py +368 -0
- flowtask/interfaces/py.typed +0 -0
- flowtask/interfaces/qs.py +376 -0
- flowtask/interfaces/result.py +87 -0
- flowtask/interfaces/selenium_service.py +779 -0
- flowtask/interfaces/smartsheet.py +154 -0
- flowtask/interfaces/stat.py +39 -0
- flowtask/interfaces/task.py +96 -0
- flowtask/interfaces/template.py +118 -0
- flowtask/interfaces/vectorstores/__init__.py +1 -0
- flowtask/interfaces/vectorstores/abstract.py +133 -0
- flowtask/interfaces/vectorstores/milvus.py +669 -0
- flowtask/interfaces/zammad.py +107 -0
- flowtask/models.py +193 -0
- flowtask/parsers/__init__.py +15 -0
- flowtask/parsers/_yaml.c +11978 -0
- flowtask/parsers/_yaml.cpython-312-x86_64-linux-gnu.so +0 -0
- flowtask/parsers/argparser.py +235 -0
- flowtask/parsers/base.c +15155 -0
- flowtask/parsers/base.cpython-312-x86_64-linux-gnu.so +0 -0
- flowtask/parsers/json.c +11968 -0
- flowtask/parsers/json.cpython-312-x86_64-linux-gnu.so +0 -0
- flowtask/parsers/maps.py +49 -0
- flowtask/parsers/toml.c +11968 -0
- flowtask/parsers/toml.cpython-312-x86_64-linux-gnu.so +0 -0
- flowtask/plugins/__init__.py +16 -0
- flowtask/plugins/components/__init__.py +0 -0
- flowtask/plugins/handler/__init__.py +45 -0
- flowtask/plugins/importer.py +31 -0
- flowtask/plugins/sources/__init__.py +0 -0
- flowtask/runner.py +283 -0
- flowtask/scheduler/__init__.py +9 -0
- flowtask/scheduler/functions.py +493 -0
- flowtask/scheduler/handlers/__init__.py +8 -0
- flowtask/scheduler/handlers/manager.py +504 -0
- flowtask/scheduler/handlers/models.py +58 -0
- flowtask/scheduler/handlers/service.py +72 -0
- flowtask/scheduler/notifications.py +65 -0
- flowtask/scheduler/scheduler.py +993 -0
- flowtask/services/__init__.py +0 -0
- flowtask/services/bots/__init__.py +0 -0
- flowtask/services/bots/telegram.py +264 -0
- flowtask/services/files/__init__.py +11 -0
- flowtask/services/files/manager.py +522 -0
- flowtask/services/files/model.py +37 -0
- flowtask/services/files/service.py +767 -0
- flowtask/services/jira/__init__.py +3 -0
- flowtask/services/jira/jira_actions.py +191 -0
- flowtask/services/tasks/__init__.py +13 -0
- flowtask/services/tasks/launcher.py +213 -0
- flowtask/services/tasks/manager.py +323 -0
- flowtask/services/tasks/service.py +275 -0
- flowtask/services/tasks/task_manager.py +376 -0
- flowtask/services/tasks/tasks.py +155 -0
- flowtask/storages/__init__.py +16 -0
- flowtask/storages/exceptions.py +12 -0
- flowtask/storages/files/__init__.py +8 -0
- flowtask/storages/files/abstract.py +29 -0
- flowtask/storages/files/filesystem.py +66 -0
- flowtask/storages/tasks/__init__.py +19 -0
- flowtask/storages/tasks/abstract.py +26 -0
- flowtask/storages/tasks/database.py +33 -0
- flowtask/storages/tasks/filesystem.py +108 -0
- flowtask/storages/tasks/github.py +119 -0
- flowtask/storages/tasks/memory.py +45 -0
- flowtask/storages/tasks/row.py +25 -0
- flowtask/tasks/__init__.py +0 -0
- flowtask/tasks/abstract.py +526 -0
- flowtask/tasks/command.py +118 -0
- flowtask/tasks/pile.py +486 -0
- flowtask/tasks/py.typed +0 -0
- flowtask/tasks/task.py +778 -0
- flowtask/template/__init__.py +161 -0
- flowtask/tests.py +257 -0
- flowtask/types/__init__.py +8 -0
- flowtask/types/typedefs.c +11347 -0
- flowtask/types/typedefs.cpython-312-x86_64-linux-gnu.so +0 -0
- flowtask/utils/__init__.py +24 -0
- flowtask/utils/constants.py +117 -0
- flowtask/utils/encoders.py +21 -0
- flowtask/utils/executor.py +112 -0
- flowtask/utils/functions.cpp +14280 -0
- flowtask/utils/functions.cpython-312-x86_64-linux-gnu.so +0 -0
- flowtask/utils/json.cpp +13349 -0
- flowtask/utils/json.cpython-312-x86_64-linux-gnu.so +0 -0
- flowtask/utils/mail.py +63 -0
- flowtask/utils/parseqs.c +13324 -0
- flowtask/utils/parserqs.cpython-312-x86_64-linux-gnu.so +0 -0
- flowtask/utils/stats.py +308 -0
- flowtask/utils/transformations.py +74 -0
- flowtask/utils/uv.py +12 -0
- flowtask/utils/validators.py +97 -0
- flowtask/version.py +11 -0
- flowtask-5.8.4.dist-info/LICENSE +201 -0
- flowtask-5.8.4.dist-info/METADATA +209 -0
- flowtask-5.8.4.dist-info/RECORD +470 -0
- flowtask-5.8.4.dist-info/WHEEL +6 -0
- flowtask-5.8.4.dist-info/entry_points.txt +3 -0
- flowtask-5.8.4.dist-info/top_level.txt +2 -0
- plugins/components/CreateQR.py +39 -0
- plugins/components/TestComponent.py +28 -0
- plugins/components/Use1.py +13 -0
- plugins/components/Workplace.py +117 -0
- plugins/components/__init__.py +3 -0
- plugins/sources/__init__.py +0 -0
- plugins/sources/get_populartimes.py +78 -0
- plugins/sources/google.py +150 -0
- plugins/sources/hubspot.py +679 -0
- plugins/sources/icims.py +679 -0
- plugins/sources/mobileinsight.py +501 -0
- plugins/sources/newrelic.py +262 -0
- plugins/sources/uap.py +268 -0
- plugins/sources/venu.py +244 -0
- plugins/sources/vocinity.py +314 -0
@@ -0,0 +1,176 @@
|
|
1
|
+
import asyncio
|
2
|
+
from collections.abc import Callable
|
3
|
+
import pandas as pd
|
4
|
+
import numpy as np
|
5
|
+
from ..exceptions import ComponentError
|
6
|
+
from .flow import FlowComponent
|
7
|
+
|
8
|
+
|
9
|
+
class TransposeRows(FlowComponent):
|
10
|
+
"""
|
11
|
+
TransposeRows
|
12
|
+
|
13
|
+
Overview
|
14
|
+
|
15
|
+
The TransposeRows class is a component for transposing specified rows in a DataFrame by converting row values
|
16
|
+
into new columns based on pivot settings. This component supports options for preserving the original data,
|
17
|
+
handling empty results, and custom column configurations for the transposition.
|
18
|
+
|
19
|
+
.. table:: Properties
|
20
|
+
:widths: auto
|
21
|
+
|
22
|
+
+------------------+----------+-----------+---------------------------------------------------------------+
|
23
|
+
| Name | Required | Summary |
|
24
|
+
+------------------+----------+-----------+---------------------------------------------------------------+
|
25
|
+
| pivot | Yes | List of columns to use as the pivot index for transposition. |
|
26
|
+
+------------------+----------+-----------+---------------------------------------------------------------+
|
27
|
+
| columns | Yes | Dictionary mapping row values to their target column names. |
|
28
|
+
+------------------+----------+-----------+---------------------------------------------------------------+
|
29
|
+
| preserve_original| No | Boolean indicating if the original rows should be preserved. |
|
30
|
+
+------------------+----------+-----------+---------------------------------------------------------------+
|
31
|
+
| allow_empty | No | Boolean indicating if empty columns should be allowed in the output. |
|
32
|
+
+------------------+----------+-----------+---------------------------------------------------------------+
|
33
|
+
|
34
|
+
Returns
|
35
|
+
|
36
|
+
This component returns a DataFrame with specified rows transposed into columns according to the provided pivot
|
37
|
+
and column configurations. If `preserve_original` is set to False, the original rows used in transposition
|
38
|
+
are removed. Any errors in column mapping or pivoting are raised with descriptive error messages.
|
39
|
+
|
40
|
+
|
41
|
+
Example:
|
42
|
+
|
43
|
+
```yaml
|
44
|
+
TransposeRows:
|
45
|
+
column: column_name
|
46
|
+
value: data
|
47
|
+
pivot:
|
48
|
+
- formid
|
49
|
+
- form_id
|
50
|
+
- orgid
|
51
|
+
preserve_original: true
|
52
|
+
allow_empty: true
|
53
|
+
columns:
|
54
|
+
'000_001': ad_hoc
|
55
|
+
'000_003': creation_timestamp
|
56
|
+
'000_004': user_device
|
57
|
+
000_008: geoloc
|
58
|
+
000_009: visit_length
|
59
|
+
'000_012': store_name
|
60
|
+
'000_013': store_id
|
61
|
+
'000_023': account_name
|
62
|
+
'000_024': store_designation
|
63
|
+
'000_026': region_name
|
64
|
+
000_029: store_timezone
|
65
|
+
'000_037': visitor_username
|
66
|
+
000_038: visitor_name
|
67
|
+
000_039: visitor_email
|
68
|
+
'000_045': visitor_role
|
69
|
+
'000_055': updated_timestamp
|
70
|
+
'000_065': activity_item_id
|
71
|
+
'000_063': time_in
|
72
|
+
'000_064': time_out
|
73
|
+
'000_066': position_id
|
74
|
+
'000_067': position_manager
|
75
|
+
'000_070': visit_status
|
76
|
+
'194834': retailer
|
77
|
+
VisitDateLocal: visit_timestamp
|
78
|
+
```
|
79
|
+
|
80
|
+
""" #noqa
|
81
|
+
|
82
|
+
def __init__(
|
83
|
+
self,
|
84
|
+
loop: asyncio.AbstractEventLoop = None,
|
85
|
+
job: Callable = None,
|
86
|
+
stat: Callable = None,
|
87
|
+
**kwargs,
|
88
|
+
):
|
89
|
+
"""Init Method."""
|
90
|
+
self._pivot: list = kwargs.pop("pivot")
|
91
|
+
self.preserve: bool = kwargs.pop("preserve_original", False)
|
92
|
+
self.allow_empty: bool = kwargs.pop("allow_empty", False)
|
93
|
+
if not self._pivot:
|
94
|
+
raise ComponentError("Missing List of Pivot Columns")
|
95
|
+
# columns to be transposed:
|
96
|
+
# TODO: if not, then all columns not in Pivot list.
|
97
|
+
self._columns = kwargs.pop("columns")
|
98
|
+
super(TransposeRows, self).__init__(loop=loop, job=job, stat=stat, **kwargs)
|
99
|
+
|
100
|
+
async def start(self, **kwargs):
|
101
|
+
if self.previous:
|
102
|
+
self.data = self.input
|
103
|
+
else:
|
104
|
+
raise ComponentError("Data Not Found", status=404)
|
105
|
+
if not isinstance(self.data, pd.DataFrame):
|
106
|
+
raise ComponentError("Transpose: Incompatible Pandas Dataframe", status=404)
|
107
|
+
if not hasattr(self, "column"):
|
108
|
+
raise ComponentError(
|
109
|
+
"Transpose: Missing Column name for extracting row values"
|
110
|
+
)
|
111
|
+
if not hasattr(self, "value"):
|
112
|
+
raise ComponentError("Transpose: Missing Column for Values")
|
113
|
+
return True
|
114
|
+
|
115
|
+
async def close(self):
|
116
|
+
pass
|
117
|
+
|
118
|
+
def row_to_column(self, df: pd.DataFrame, row_to_pivot: str, new_name: str):
|
119
|
+
"""
|
120
|
+
Add a pivoted column to the dataframe based on the given column name.
|
121
|
+
|
122
|
+
Parameters:
|
123
|
+
- df: The input dataframe.
|
124
|
+
- row_to_pivot: The column name to be pivoted.
|
125
|
+
- new_name: The name of the column to be transposed.
|
126
|
+
|
127
|
+
Returns:
|
128
|
+
- Dataframe with the new pivoted column.
|
129
|
+
"""
|
130
|
+
# Filter the dataframe to only include rows with the desired column_name
|
131
|
+
df_filtered = df[df[self.column] == row_to_pivot]
|
132
|
+
if df_filtered.empty is True:
|
133
|
+
# there is no data to be filtered:
|
134
|
+
if self.allow_empty is True:
|
135
|
+
df[new_name] = np.nan
|
136
|
+
return df
|
137
|
+
# Pivot the filtered dataframe
|
138
|
+
df_pivot = df_filtered.pivot_table(
|
139
|
+
index=self._pivot,
|
140
|
+
columns=self.column,
|
141
|
+
values=self.value,
|
142
|
+
aggfunc="first",
|
143
|
+
dropna=False, # Preserve NaN values
|
144
|
+
).reset_index()
|
145
|
+
df_pivot = df_pivot.rename(columns={row_to_pivot: new_name})
|
146
|
+
# Merge the pivoted dataframe with the original dataframe
|
147
|
+
df_merged = pd.merge(df, df_pivot, on=self._pivot, how="left")
|
148
|
+
if self.preserve is False:
|
149
|
+
# Drop the original column_name and value columns for the pivoted rows
|
150
|
+
df_merged = df_merged.drop(
|
151
|
+
df_merged[(df_merged[self.column] == row_to_pivot)].index
|
152
|
+
)
|
153
|
+
return df_merged
|
154
|
+
|
155
|
+
async def run(self):
|
156
|
+
try:
|
157
|
+
df = self.data
|
158
|
+
for column, value in self._columns.items():
|
159
|
+
try:
|
160
|
+
df_pivot = self.row_to_column(df, column, value)
|
161
|
+
except Exception as err:
|
162
|
+
print(err)
|
163
|
+
df = df_pivot
|
164
|
+
if self._debug is True:
|
165
|
+
print("=== TRANSPOSE ===")
|
166
|
+
print(" = Data Types: = ")
|
167
|
+
print(df.dtypes)
|
168
|
+
print("::: Printing Column Information === ")
|
169
|
+
for column, t in df.dtypes.items():
|
170
|
+
print(column, "->", t, "->", df[column].iloc[0])
|
171
|
+
self._result = df
|
172
|
+
return self._result
|
173
|
+
except (ValueError, KeyError) as err:
|
174
|
+
raise ComponentError(f"Crosstab Error: {err!s}") from err
|
175
|
+
except Exception as err:
|
176
|
+
raise ComponentError(f"Unknown error {err!s}") from err
|
@@ -0,0 +1,86 @@
|
|
1
|
+
from datetime import date
|
2
|
+
from .RESTClient import AbstractREST
|
3
|
+
|
4
|
+
|
5
|
+
class UPCDatabase(AbstractREST):
|
6
|
+
"""
|
7
|
+
UPCDatabase.
|
8
|
+
|
9
|
+
Querying UPC Database for Product information.
|
10
|
+
|
11
|
+
|
12
|
+
Example:
|
13
|
+
|
14
|
+
```yaml
|
15
|
+
UPCDatabase:
|
16
|
+
method: currency
|
17
|
+
base: USD
|
18
|
+
credentials:
|
19
|
+
apikey: UPC_API_KEY
|
20
|
+
```
|
21
|
+
|
22
|
+
"""
|
23
|
+
|
24
|
+
base_url: str = "https://api.upcdatabase.org/"
|
25
|
+
_default_method: str = "currency"
|
26
|
+
|
27
|
+
async def start(self, **kwargs):
|
28
|
+
if not self.credentials:
|
29
|
+
# obtengo las credenciales
|
30
|
+
self.credentials["apikey"] = self._environment.get("UPC_API_KEY")
|
31
|
+
if not self.credentials["apikey"]:
|
32
|
+
raise ValueError("UPC Database: Missing Credentials")
|
33
|
+
# calling method for this element:
|
34
|
+
await super(UPCDatabase, self).start(**kwargs)
|
35
|
+
|
36
|
+
async def currency(self):
|
37
|
+
"""currency.
|
38
|
+
|
39
|
+
Currency information and exchange rates supported by UPC
|
40
|
+
"""
|
41
|
+
self.method = "get"
|
42
|
+
self.url = self.base_url + "currency/latest/"
|
43
|
+
try:
|
44
|
+
self.parameters["base"] = self.base
|
45
|
+
except (ValueError, TypeError):
|
46
|
+
self.parameters["base"] = "USD"
|
47
|
+
|
48
|
+
async def currency_history(self):
|
49
|
+
"""currency.
|
50
|
+
|
51
|
+
Retrieves the currency conversion rates for a specific date.
|
52
|
+
"""
|
53
|
+
self.method = "get"
|
54
|
+
self.url = self.base_url + "currency/history"
|
55
|
+
try:
|
56
|
+
self.parameters["base"] = self.base
|
57
|
+
except (ValueError, TypeError):
|
58
|
+
self.parameters["base"] = "USD"
|
59
|
+
try:
|
60
|
+
self.parameters["date"] = self.date
|
61
|
+
except (ValueError, AttributeError):
|
62
|
+
today = date.today()
|
63
|
+
self.parameters["date"] = today.strftime("%Y-%m-%d")
|
64
|
+
|
65
|
+
async def product(self):
|
66
|
+
"""product.
|
67
|
+
|
68
|
+
Product information based on UPC barcode
|
69
|
+
"""
|
70
|
+
self.method = "get"
|
71
|
+
if not "barcode" in self._args:
|
72
|
+
raise ValueError("UPC Database: Missing Barcode")
|
73
|
+
self.url = self.base_url + "product/{barcode}"
|
74
|
+
|
75
|
+
async def search(self):
|
76
|
+
"""product.
|
77
|
+
|
78
|
+
Search for a product based on item parameters.
|
79
|
+
"""
|
80
|
+
self.method = "get"
|
81
|
+
self.url = self.base_url + "search/"
|
82
|
+
self.parameters["page"] = 1
|
83
|
+
try:
|
84
|
+
self.parameters["query"] = self.query
|
85
|
+
except (ValueError, TypeError) as e:
|
86
|
+
raise ValueError("UPC Database: Missing or wrong *query* Search.") from e
|
@@ -0,0 +1,171 @@
|
|
1
|
+
import os
|
2
|
+
import logging
|
3
|
+
import asyncio
|
4
|
+
from typing import List
|
5
|
+
from collections.abc import Callable
|
6
|
+
from pathlib import PosixPath, Path, PurePath
|
7
|
+
import tarfile
|
8
|
+
from ..exceptions import FileError, ComponentError, FileNotFound
|
9
|
+
from .FileCopy import FileCopy
|
10
|
+
from ..utils import check_empty
|
11
|
+
from ..interfaces.compress import CompressSupport
|
12
|
+
|
13
|
+
|
14
|
+
class UnGzip(CompressSupport, FileCopy):
|
15
|
+
"""
|
16
|
+
UnGzip
|
17
|
+
|
18
|
+
Overview
|
19
|
+
|
20
|
+
The UnGzip class is a component for decompressing Gzip (.gz) files, including compressed tarballs (e.g., .tar.gz, .tar.bz2, .tar.xz).
|
21
|
+
This component extracts the specified Gzip or tarball file into a target directory and supports optional source file deletion
|
22
|
+
after extraction.
|
23
|
+
|
24
|
+
.. table:: Properties
|
25
|
+
:widths: auto
|
26
|
+
|
27
|
+
+----------------+----------+-----------+---------------------------------------------------------------+
|
28
|
+
| Name | Required | Summary |
|
29
|
+
+----------------+----------+-----------+---------------------------------------------------------------+
|
30
|
+
| filename | Yes | The path to the Gzip file to uncompress. |
|
31
|
+
+----------------+----------+-----------+---------------------------------------------------------------+
|
32
|
+
| directory | Yes | The target directory where files will be extracted. |
|
33
|
+
+----------------+----------+-----------+---------------------------------------------------------------+
|
34
|
+
| delete_source | No | Boolean indicating if the source file should be deleted post-extraction. |
|
35
|
+
+----------------+----------+-----------+---------------------------------------------------------------+
|
36
|
+
| extract | No | Dictionary specifying filenames to extract and/or output directory. |
|
37
|
+
+----------------+----------+-----------+---------------------------------------------------------------+
|
38
|
+
|
39
|
+
Returns
|
40
|
+
|
41
|
+
This component extracts files from a specified Gzip or tarball archive into the designated directory
|
42
|
+
and returns a list of paths to the extracted files. It tracks metrics for the output directory and the source
|
43
|
+
Gzip file. If configured, the original compressed file is deleted after extraction. Errors encountered during
|
44
|
+
extraction or directory creation are logged and raised as exceptions.
|
45
|
+
|
46
|
+
|
47
|
+
Example:
|
48
|
+
|
49
|
+
```yaml
|
50
|
+
UnGzip:
|
51
|
+
source:
|
52
|
+
directory: /home/ubuntu/symbits/mso/files/commissions_statements/pr/
|
53
|
+
filename: STATEMENT_STATEMENT-*.CSV.gz
|
54
|
+
destination:
|
55
|
+
directory: /home/ubuntu/symbits/mso/files/commissions_statements/pr/
|
56
|
+
delete_source: true
|
57
|
+
```
|
58
|
+
|
59
|
+
""" # noqa
|
60
|
+
|
61
|
+
_namelist = []
|
62
|
+
_directory = ""
|
63
|
+
|
64
|
+
def __init__(
|
65
|
+
self,
|
66
|
+
loop: asyncio.AbstractEventLoop = None,
|
67
|
+
job: Callable = None,
|
68
|
+
stat: Callable = None,
|
69
|
+
**kwargs,
|
70
|
+
):
|
71
|
+
"""Init Method."""
|
72
|
+
self._output: PurePath = None
|
73
|
+
self._filenames: List = []
|
74
|
+
self.delete_source: bool = False
|
75
|
+
self._as_list: bool = kwargs.pop('as_list', False)
|
76
|
+
self._binary_sources: dict = None
|
77
|
+
super(UnGzip, self).__init__(loop=loop, job=job, stat=stat, **kwargs)
|
78
|
+
|
79
|
+
async def start(self, **kwargs):
|
80
|
+
if self.previous and not check_empty(self.input) and getattr(self, "ignore_previous", False) is False:
|
81
|
+
if isinstance(self.input, dict):
|
82
|
+
self._binary_sources = self.input.get('files', {})
|
83
|
+
return True
|
84
|
+
await super().start(**kwargs)
|
85
|
+
# Handle extraction settings
|
86
|
+
if hasattr(self, "destination"):
|
87
|
+
# New format using destination
|
88
|
+
if isinstance(self.destination, dict) and "directory" in self.destination:
|
89
|
+
self._destination = Path(self.destination["directory"]).resolve()
|
90
|
+
else:
|
91
|
+
self._destination = Path(self.destination).resolve()
|
92
|
+
elif hasattr(self, "extract"):
|
93
|
+
# Legacy format using extract
|
94
|
+
for _, filename in enumerate(self.extract["filenames"]):
|
95
|
+
filename = self.mask_replacement(filename)
|
96
|
+
self._filenames.append(filename)
|
97
|
+
if "directory" in self.extract:
|
98
|
+
self._destination = Path(self.extract["directory"]).resolve()
|
99
|
+
else:
|
100
|
+
# same directory as source
|
101
|
+
self._destination = Path(self.directory)
|
102
|
+
else:
|
103
|
+
# If no destination specified, use source directory
|
104
|
+
self._destination = Path(self.directory)
|
105
|
+
# Create destination directory if it doesn't exist
|
106
|
+
try:
|
107
|
+
self._destination.mkdir(parents=True, exist_ok=True)
|
108
|
+
except Exception as err:
|
109
|
+
logging.error(f"Error creating directory {self._destination}: {err}")
|
110
|
+
raise ComponentError(
|
111
|
+
f"Error creating directory {self._destination}: {err}"
|
112
|
+
) from err
|
113
|
+
# For backwards compatibility
|
114
|
+
self._output = self._destination
|
115
|
+
return True
|
116
|
+
|
117
|
+
async def close(self):
|
118
|
+
pass
|
119
|
+
|
120
|
+
async def run(self):
|
121
|
+
# Check if file exists
|
122
|
+
self._result = {}
|
123
|
+
filenames = []
|
124
|
+
if self._binary_sources:
|
125
|
+
for filename, contents in self._binary_sources.items():
|
126
|
+
# get binary contents:
|
127
|
+
data = contents.get('data')
|
128
|
+
data.seek(0) # restarts from beginning
|
129
|
+
# Uncompress gzip contents in memory:
|
130
|
+
try:
|
131
|
+
f = await self.uncompress_gzip(
|
132
|
+
source=data,
|
133
|
+
destination=None
|
134
|
+
)
|
135
|
+
filenames.append(
|
136
|
+
{"filename": filename, "data": f}
|
137
|
+
)
|
138
|
+
except RuntimeError as err:
|
139
|
+
raise FileError(f"UnGzip failed: {err}")
|
140
|
+
self._result = filenames
|
141
|
+
elif self._sources:
|
142
|
+
for file in self._sources:
|
143
|
+
if not file.exists() or not file.is_file():
|
144
|
+
raise FileNotFound(
|
145
|
+
f"Compressed File doesn't exist: {file}"
|
146
|
+
)
|
147
|
+
# Uncompress the gzip/tar.gz file
|
148
|
+
try:
|
149
|
+
files = await self.uncompress_gzip(
|
150
|
+
source=file,
|
151
|
+
destination=self._destination,
|
152
|
+
remove_source=self.delete_source,
|
153
|
+
)
|
154
|
+
except (FileNotFoundError, ComponentError) as err:
|
155
|
+
raise FileError(f"UnGzip failed: {err}")
|
156
|
+
except RuntimeError as err:
|
157
|
+
raise FileError(f"UnGzip failed: {err}")
|
158
|
+
|
159
|
+
if self.delete_source:
|
160
|
+
file.unlink(missing_ok=True)
|
161
|
+
|
162
|
+
filenames = []
|
163
|
+
for filename in files:
|
164
|
+
filenames.append(filename)
|
165
|
+
self._result[str(file)] = filenames
|
166
|
+
if self._as_list is True:
|
167
|
+
self._result = filenames
|
168
|
+
self.add_metric("OUTPUT_DIRECTORY", self._destination)
|
169
|
+
self.add_metric("FILES_UNCOMPRESS", len(filenames))
|
170
|
+
# Support both metrics for backwards compatibility
|
171
|
+
return self._result
|
@@ -0,0 +1,172 @@
|
|
1
|
+
import os
|
2
|
+
import logging
|
3
|
+
import asyncio
|
4
|
+
from typing import List
|
5
|
+
from collections.abc import Callable
|
6
|
+
from pathlib import PosixPath, Path, PurePath
|
7
|
+
from zipfile import ZipFile, BadZipFile
|
8
|
+
from ..exceptions import FileError, ComponentError, FileNotFound
|
9
|
+
from .flow import FlowComponent
|
10
|
+
from ..interfaces.compress import CompressSupport
|
11
|
+
|
12
|
+
|
13
|
+
class Uncompress(CompressSupport, FlowComponent):
|
14
|
+
"""
|
15
|
+
Uncompress
|
16
|
+
|
17
|
+
Overview
|
18
|
+
|
19
|
+
The Uncompress class is a component for decompressing files in various archive formats, including but not limited to:
|
20
|
+
7z (.7z), ACE (.ace), ALZIP (.alz), AR (.a), ARC (.arc), ARJ (.arj), BZIP2 (.bz2), CAB (.cab), compress (.Z),
|
21
|
+
CPIO (.cpio), DEB (.deb), DMS (.dms), GZIP (.gz), LRZIP (.lrz), LZH (.lha, .lzh), LZIP (.lz), LZMA (.lzma),
|
22
|
+
LZOP (.lzo), RPM (.rpm), RAR (.rar), RZIP (.rz), TAR (.tar), XZ (.xz), ZIP (.zip, .jar), and ZOO (.zoo).
|
23
|
+
It extracts the specified compressed file into a target directory and can optionally delete the source file
|
24
|
+
upon successful extraction.
|
25
|
+
|
26
|
+
.. table:: Properties
|
27
|
+
:widths: auto
|
28
|
+
|
29
|
+
+----------------+----------+-----------+---------------------------------------------------------------+
|
30
|
+
| Name | Required | Summary |
|
31
|
+
+----------------+----------+-----------+---------------------------------------------------------------+
|
32
|
+
| filename | Yes | The path to the compressed file to be decompressed. |
|
33
|
+
+----------------+----------+-----------+---------------------------------------------------------------+
|
34
|
+
| directory | Yes | The target directory where files will be extracted. |
|
35
|
+
+----------------+----------+-----------+---------------------------------------------------------------+
|
36
|
+
| delete_source | No | Boolean indicating if the source file should be deleted post-extraction. |
|
37
|
+
+----------------+----------+-----------+---------------------------------------------------------------+
|
38
|
+
| extract | No | Dictionary specifying filenames to extract and/or output directory. |
|
39
|
+
+----------------+----------+-----------+---------------------------------------------------------------+
|
40
|
+
| password | No | Optional password for encrypted files in supported formats. |
|
41
|
+
+----------------+----------+-----------+---------------------------------------------------------------+
|
42
|
+
|
43
|
+
Returns
|
44
|
+
|
45
|
+
This component extracts files from the specified compressed archive into the designated directory and returns
|
46
|
+
a list of paths to the extracted files. It tracks metrics for the output directory and compressed file name.
|
47
|
+
If configured, the original compressed file is deleted after extraction. Errors related to file corruption
|
48
|
+
or extraction issues are logged and raised as exceptions.
|
49
|
+
|
50
|
+
|
51
|
+
Example:
|
52
|
+
|
53
|
+
```yaml
|
54
|
+
Uncompress:
|
55
|
+
filename: organizational_unit_ancestors_{yesterday}.zip
|
56
|
+
masks:
|
57
|
+
yesterday:
|
58
|
+
- yesterday
|
59
|
+
- mask: '%Y-%m-%d'
|
60
|
+
directory: /home/ubuntu/symbits/polestar/files/organizational_unit_ancestors/
|
61
|
+
extract:
|
62
|
+
filenames:
|
63
|
+
- OrganizationalUnitAncestors.csv
|
64
|
+
directory: /home/ubuntu/symbits/polestar/files/organizational_unit_ancestors/
|
65
|
+
delete_source: false
|
66
|
+
```
|
67
|
+
|
68
|
+
""" #noqa
|
69
|
+
|
70
|
+
_namelist = []
|
71
|
+
_directory = ""
|
72
|
+
|
73
|
+
def __init__(
|
74
|
+
self,
|
75
|
+
loop: asyncio.AbstractEventLoop = None,
|
76
|
+
job: Callable = None,
|
77
|
+
stat: Callable = None,
|
78
|
+
**kwargs,
|
79
|
+
):
|
80
|
+
"""Init Method."""
|
81
|
+
self.filename: str = None
|
82
|
+
self.directory: PurePath = None
|
83
|
+
self._path: PurePath = None
|
84
|
+
self._output: PurePath = None
|
85
|
+
self._filenames: List = []
|
86
|
+
self.delete_source: bool = False
|
87
|
+
super(Uncompress, self).__init__(loop=loop, job=job, stat=stat, **kwargs)
|
88
|
+
|
89
|
+
async def start(self, **kwargs):
|
90
|
+
if isinstance(self.directory, str):
|
91
|
+
self.directory = PosixPath(self.directory).resolve()
|
92
|
+
self._path = PosixPath(self.directory, self.filename)
|
93
|
+
if self.filename is not None:
|
94
|
+
if hasattr(self, "masks"):
|
95
|
+
self.filename = self.mask_replacement(self.filename)
|
96
|
+
self._path = PosixPath(self.directory, self.filename)
|
97
|
+
elif self.previous:
|
98
|
+
if isinstance(self.input, PosixPath):
|
99
|
+
self.filename = self.input
|
100
|
+
elif isinstance(self.input, list):
|
101
|
+
self.filename = PosixPath(self.input[0])
|
102
|
+
elif isinstance(self.input, str):
|
103
|
+
self.filename = PosixPath(self.input)
|
104
|
+
else:
|
105
|
+
filenames = list(self.input.keys())
|
106
|
+
if filenames:
|
107
|
+
try:
|
108
|
+
self.filename = PosixPath(filenames[0])
|
109
|
+
except IndexError as err:
|
110
|
+
raise FileError("File is empty or doesnt exists") from err
|
111
|
+
self._variables["__FILEPATH__"] = self.filename
|
112
|
+
self._variables["__FILENAME__"] = os.path.basename(self.filename)
|
113
|
+
self._path = self.filename
|
114
|
+
else:
|
115
|
+
raise FileError("UnCompress: File is empty or doesn't exists")
|
116
|
+
if hasattr(self, "extract"):
|
117
|
+
for _, filename in enumerate(self.extract["filenames"]):
|
118
|
+
filename = self.mask_replacement(filename)
|
119
|
+
self._filenames.append(filename)
|
120
|
+
if "directory" in self.extract:
|
121
|
+
self._output = Path(self.extract["directory"]).resolve()
|
122
|
+
# Create directory if not exists
|
123
|
+
try:
|
124
|
+
self._output.mkdir(parents=True, exist_ok=True)
|
125
|
+
except Exception as err:
|
126
|
+
logging.error(f"Error creating directory {self._output}: {err}")
|
127
|
+
raise ComponentError(
|
128
|
+
f"Error creating directory {self._output}: {err}"
|
129
|
+
) from err
|
130
|
+
else:
|
131
|
+
# same directory:
|
132
|
+
self._output = Path(self.directory)
|
133
|
+
self.add_metric("OUTPUT_DIRECTORY", self._output)
|
134
|
+
self.add_metric("ZIP_FILE", self.filename)
|
135
|
+
return True
|
136
|
+
|
137
|
+
async def close(self):
|
138
|
+
pass
|
139
|
+
|
140
|
+
async def run(self):
|
141
|
+
# Check if File exists
|
142
|
+
self._result = None
|
143
|
+
if not self._path.exists() or not self._path.is_file():
|
144
|
+
raise FileNotFound(
|
145
|
+
f"Compressed File doesn't exists: {self._path}"
|
146
|
+
)
|
147
|
+
with ZipFile(self._path) as zfp:
|
148
|
+
status = zfp.testzip()
|
149
|
+
if not status: # Si no hay status
|
150
|
+
# If not exists namelist, extract all files
|
151
|
+
members = self._filenames if self._filenames else None
|
152
|
+
# If not exists password return None
|
153
|
+
pwd = self.password if hasattr(self, "password") else None
|
154
|
+
try:
|
155
|
+
zfp.extractall(path=self._output, members=members, pwd=pwd)
|
156
|
+
if self.delete_source is True:
|
157
|
+
self._path.unlink()
|
158
|
+
except BadZipFile as err:
|
159
|
+
# The error raised for bad ZIP files.
|
160
|
+
raise ComponentError(f"Bad Zip File: {err}") from err
|
161
|
+
except Exception as err:
|
162
|
+
# Undefined error
|
163
|
+
raise ComponentError(f"{self.__name__} ZIP Error: {err}") from err
|
164
|
+
result = self._filenames if self._filenames else zfp.namelist()
|
165
|
+
filenames = []
|
166
|
+
for filename in result:
|
167
|
+
f = self._output.joinpath(filename)
|
168
|
+
filenames.append(f)
|
169
|
+
self._result = filenames
|
170
|
+
else: # Si hay status devuelve el primer archivo corrupto
|
171
|
+
raise ComponentError(f"Zip File {status} is corrupted")
|
172
|
+
return self._result
|