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,126 @@
|
|
1
|
+
import asyncio
|
2
|
+
from typing import List
|
3
|
+
from collections.abc import Callable
|
4
|
+
import pandas as pd
|
5
|
+
from asyncdb.exceptions import StatementError, DataError
|
6
|
+
from ..exceptions import ComponentError
|
7
|
+
from .flow import FlowComponent
|
8
|
+
|
9
|
+
|
10
|
+
class UniqueRows(FlowComponent):
|
11
|
+
"""
|
12
|
+
UniqueRows
|
13
|
+
|
14
|
+
Overview
|
15
|
+
|
16
|
+
The UniqueRows class is a component for extracting unique rows from a Pandas DataFrame.
|
17
|
+
It supports pre-sorting of rows, custom options for handling duplicates, and an option to save
|
18
|
+
rejected rows that are duplicates.
|
19
|
+
|
20
|
+
.. table:: Properties
|
21
|
+
:widths: auto
|
22
|
+
|
23
|
+
+----------------+----------+-----------+---------------------------------------------------------------+
|
24
|
+
| Name | Required | Summary |
|
25
|
+
+----------------+----------+-----------+---------------------------------------------------------------+
|
26
|
+
| unique | Yes | List of columns to use for identifying unique rows. |
|
27
|
+
+----------------+----------+-----------+---------------------------------------------------------------+
|
28
|
+
| order | No | Dictionary specifying columns and sort order (`asc` or `desc`). |
|
29
|
+
+----------------+----------+-----------+---------------------------------------------------------------+
|
30
|
+
| keep | No | Specifies which duplicates to keep: `first`, `last`, or `False`. |
|
31
|
+
+----------------+----------+-----------+---------------------------------------------------------------+
|
32
|
+
| save_rejected | No | Dictionary with filename to save rejected rows as CSV, if specified. |
|
33
|
+
+----------------+----------+-----------+---------------------------------------------------------------+
|
34
|
+
|
35
|
+
Returns
|
36
|
+
|
37
|
+
This component returns a DataFrame containing only unique rows based on the specified columns.
|
38
|
+
If sorting is defined in `order`, rows are pre-sorted before duplicates are removed. Metrics such as
|
39
|
+
the number of rows passed and rejected are recorded. If `save_rejected` is specified, rejected rows
|
40
|
+
are saved to a file. Any data errors encountered during execution are raised with detailed error messages.
|
41
|
+
|
42
|
+
|
43
|
+
Example:
|
44
|
+
|
45
|
+
```yaml
|
46
|
+
UniqueRows:
|
47
|
+
unique:
|
48
|
+
- store_id
|
49
|
+
```
|
50
|
+
|
51
|
+
""" # noqa
|
52
|
+
|
53
|
+
def __init__(
|
54
|
+
self,
|
55
|
+
loop: asyncio.AbstractEventLoop = None,
|
56
|
+
job: Callable = None,
|
57
|
+
stat: Callable = None,
|
58
|
+
**kwargs,
|
59
|
+
):
|
60
|
+
"""Init Method."""
|
61
|
+
self.unique: List = None
|
62
|
+
super(UniqueRows, self).__init__(loop=loop, job=job, stat=stat, **kwargs)
|
63
|
+
|
64
|
+
async def start(self, **kwargs):
|
65
|
+
"""Start Component"""
|
66
|
+
if self.previous:
|
67
|
+
self.data = self.input
|
68
|
+
|
69
|
+
def close(self):
|
70
|
+
"""Close."""
|
71
|
+
|
72
|
+
async def run(self):
|
73
|
+
"""Getting Unique rows from a Dataframe."""
|
74
|
+
self._result = None
|
75
|
+
try:
|
76
|
+
if isinstance(self.data, pd.DataFrame):
|
77
|
+
start = len(self.data.index)
|
78
|
+
self.add_metric("Start", start)
|
79
|
+
if hasattr(self, "order"):
|
80
|
+
# making a pre-ordering before drop duplicates:
|
81
|
+
ordering = []
|
82
|
+
ascending = []
|
83
|
+
for col, order in self.order.items():
|
84
|
+
ordering.append(col)
|
85
|
+
if order == "asc":
|
86
|
+
ascending.append(True)
|
87
|
+
else:
|
88
|
+
order.append(False)
|
89
|
+
self.data.sort_values(
|
90
|
+
by=ordering, inplace=True, ascending=ascending
|
91
|
+
)
|
92
|
+
keep = {}
|
93
|
+
if hasattr(self, "keep"):
|
94
|
+
keep = {"keep": self.keep}
|
95
|
+
# get only unique rows from this dataframe
|
96
|
+
print('UNIQUE > ', self.unique)
|
97
|
+
self._result = self.data.drop_duplicates(self.unique, **keep)
|
98
|
+
passed = len(self._result.index)
|
99
|
+
self.add_metric("Passed", passed)
|
100
|
+
rejected = start - passed
|
101
|
+
self.add_metric("Rejected", rejected)
|
102
|
+
self._variables[f"{self.StepName}_PASSED"] = passed
|
103
|
+
self._variables[f"{self.StepName}_REJECTED"] = rejected
|
104
|
+
if hasattr(self, "save_rejected"):
|
105
|
+
# Identify the indices of the rows that were removed
|
106
|
+
removed_indices = set(self.data.index) - set(self._result.index)
|
107
|
+
# Select these rows from the original DataFrame
|
108
|
+
rejected = self.data.loc[list(removed_indices)]
|
109
|
+
filename = self.save_rejected.get("filename", "rejected_rows.csv")
|
110
|
+
try:
|
111
|
+
rejected.to_csv(filename, sep="|")
|
112
|
+
except IOError:
|
113
|
+
self._logger.warning(f"Error writing Rejectd File: {filename}")
|
114
|
+
self.add_metric(
|
115
|
+
"rejected_file", filename
|
116
|
+
)
|
117
|
+
else:
|
118
|
+
# return expected data
|
119
|
+
self._result = self.data
|
120
|
+
return self._result
|
121
|
+
except StatementError as err:
|
122
|
+
print(err)
|
123
|
+
return None
|
124
|
+
except DataError as err:
|
125
|
+
print(err)
|
126
|
+
raise ComponentError(f"UniqueRows: Error with Data: {err}") from err
|
@@ -0,0 +1,107 @@
|
|
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 .FileCopy import FileCopy
|
10
|
+
from ..interfaces.compress import CompressSupport
|
11
|
+
|
12
|
+
|
13
|
+
class Unzip(CompressSupport, FileCopy):
|
14
|
+
"""
|
15
|
+
Unzip
|
16
|
+
|
17
|
+
Overview
|
18
|
+
|
19
|
+
The Unzip class is a component for decompressing ZIP files in specified directories.
|
20
|
+
It supports selecting specific files within the archive, applying directory masks, and
|
21
|
+
optionally deleting the source ZIP file after extraction.
|
22
|
+
|
23
|
+
.. table:: Properties
|
24
|
+
:widths: auto
|
25
|
+
|
26
|
+
+----------------+----------+-----------+---------------------------------------------------------------+
|
27
|
+
| Name | Required | Summary |
|
28
|
+
+----------------+----------+-----------+---------------------------------------------------------------+
|
29
|
+
| filename | Yes | The name of the ZIP file to decompress. |
|
30
|
+
+----------------+----------+-----------+---------------------------------------------------------------+
|
31
|
+
| directory | Yes | The target directory for decompression. |
|
32
|
+
+----------------+----------+-----------+---------------------------------------------------------------+
|
33
|
+
| extract | No | Dictionary specifying files to extract and/or target output directory. |
|
34
|
+
+----------------+----------+-----------+---------------------------------------------------------------+
|
35
|
+
| delete_source | No | Boolean indicating if the ZIP file should be deleted after extraction. |
|
36
|
+
+----------------+----------+-----------+---------------------------------------------------------------+
|
37
|
+
| password | No | Optional password for encrypted ZIP files. |
|
38
|
+
+----------------+----------+-----------+---------------------------------------------------------------+
|
39
|
+
|
40
|
+
Returns
|
41
|
+
|
42
|
+
This component extracts the specified files from a ZIP archive into the target directory and
|
43
|
+
returns a list of extracted file paths. Metrics such as the output directory and ZIP file name
|
44
|
+
are tracked, and any errors related to file extraction or directory creation are logged for
|
45
|
+
debugging purposes. If specified, the original ZIP file is deleted after extraction.
|
46
|
+
""" # noqa
|
47
|
+
|
48
|
+
_namelist = []
|
49
|
+
_directory = ""
|
50
|
+
|
51
|
+
def __init__(
|
52
|
+
self,
|
53
|
+
loop: asyncio.AbstractEventLoop = None,
|
54
|
+
job: Callable = None,
|
55
|
+
stat: Callable = None,
|
56
|
+
**kwargs,
|
57
|
+
):
|
58
|
+
"""Init Method."""
|
59
|
+
self._output: PurePath = None
|
60
|
+
self._filenames: List = []
|
61
|
+
self.delete_source: bool = False
|
62
|
+
super(Unzip, self).__init__(
|
63
|
+
loop=loop,
|
64
|
+
job=job,
|
65
|
+
stat=stat,
|
66
|
+
**kwargs
|
67
|
+
)
|
68
|
+
|
69
|
+
async def start(self, **kwargs):
|
70
|
+
await super().start(**kwargs)
|
71
|
+
return True
|
72
|
+
|
73
|
+
async def close(self):
|
74
|
+
pass
|
75
|
+
|
76
|
+
async def run(self):
|
77
|
+
# Check if File exists
|
78
|
+
self._result = {}
|
79
|
+
for file in self._sources:
|
80
|
+
if not file.exists() or not file.is_file():
|
81
|
+
raise FileNotFound(
|
82
|
+
f"Compressed File doesn't exists: {file}"
|
83
|
+
)
|
84
|
+
try:
|
85
|
+
files = await self.uncompress_zip(
|
86
|
+
source=file,
|
87
|
+
destination=self._destination,
|
88
|
+
source_files=self._filenames,
|
89
|
+
password=self.password if hasattr(self, "password") else None,
|
90
|
+
remove_source=self.delete_source,
|
91
|
+
)
|
92
|
+
except (FileNotFoundError, ComponentError) as err:
|
93
|
+
raise FileError(
|
94
|
+
f"UnZip failed: {err}"
|
95
|
+
)
|
96
|
+
except RuntimeError as err:
|
97
|
+
raise FileError(
|
98
|
+
f"UnZip failed: {err}"
|
99
|
+
)
|
100
|
+
if self.delete_source:
|
101
|
+
file.unlink(missing_ok=True)
|
102
|
+
|
103
|
+
filenames = []
|
104
|
+
for filename in files:
|
105
|
+
filenames.append(filename)
|
106
|
+
self._result[str(file)] = filenames
|
107
|
+
return self._result
|
@@ -0,0 +1,147 @@
|
|
1
|
+
"""
|
2
|
+
UpdateOperationalVars
|
3
|
+
|
4
|
+
Overview
|
5
|
+
|
6
|
+
This component updates operational variables stored in the `process_variables` table within the `troc` schema.
|
7
|
+
It supports dynamic variable replacement and mask application, making it versatile for runtime updates in task flows.
|
8
|
+
|
9
|
+
.. table:: Properties
|
10
|
+
:widths: auto
|
11
|
+
|
12
|
+
+--------------+----------+-----------+---------------------------------------------------------------+
|
13
|
+
| Name | Required | Summary |
|
14
|
+
+--------------+----------+-----------+---------------------------------------------------------------+
|
15
|
+
| name | Yes | The name of the variable to update. |
|
16
|
+
+--------------+----------+-----------+---------------------------------------------------------------+
|
17
|
+
| value | Yes | The new value to assign to the variable after the update. |
|
18
|
+
+--------------+----------+-----------+---------------------------------------------------------------+
|
19
|
+
| masks | Yes | Defines a section for dynamically setting the value of the variable. |
|
20
|
+
+--------------+----------+-----------+---------------------------------------------------------------+
|
21
|
+
|
22
|
+
Returns
|
23
|
+
|
24
|
+
This component does not return data directly. Instead, it updates specified variables in the database and
|
25
|
+
records metrics on the update status. Additionally, logging is provided for SQL execution, and potential errors
|
26
|
+
are managed with detailed logging and exception handling for effective debugging.
|
27
|
+
|
28
|
+
|
29
|
+
Example:
|
30
|
+
|
31
|
+
```yaml
|
32
|
+
UpdateOperationalVars:
|
33
|
+
name: EPSON_SALES
|
34
|
+
value: '{saturday}'
|
35
|
+
masks:
|
36
|
+
'{saturday}':
|
37
|
+
- date_diff_dow
|
38
|
+
- diff: 2
|
39
|
+
day_of_week: monday
|
40
|
+
mask: '%Y-%m-%d'
|
41
|
+
```
|
42
|
+
|
43
|
+
""" #noqa
|
44
|
+
|
45
|
+
import asyncio
|
46
|
+
import logging
|
47
|
+
from typing import Any
|
48
|
+
from collections.abc import Callable
|
49
|
+
from ..exceptions import ComponentError
|
50
|
+
from .flow import FlowComponent
|
51
|
+
from ..interfaces import DBSupport
|
52
|
+
|
53
|
+
|
54
|
+
class UpdateOperationalVars(DBSupport, FlowComponent):
|
55
|
+
def __init__(
|
56
|
+
self,
|
57
|
+
loop: asyncio.AbstractEventLoop = None,
|
58
|
+
job: Callable = None,
|
59
|
+
stat: Callable = None,
|
60
|
+
**kwargs,
|
61
|
+
):
|
62
|
+
"""Init Method."""
|
63
|
+
self.value: Any = None
|
64
|
+
super().__init__(
|
65
|
+
loop=loop, job=job, stat=stat, **kwargs
|
66
|
+
)
|
67
|
+
|
68
|
+
async def start(self, **kwargs):
|
69
|
+
if self.previous:
|
70
|
+
self.data = self.input
|
71
|
+
await super().start(**kwargs)
|
72
|
+
self.processing_credentials()
|
73
|
+
try:
|
74
|
+
self.value = self.mask_replacement(self.value)
|
75
|
+
except Exception as err:
|
76
|
+
raise ComponentError(
|
77
|
+
f"Error adding mask [{err.__class__.__name__}]: {err}"
|
78
|
+
) from err
|
79
|
+
return True
|
80
|
+
|
81
|
+
async def close(self):
|
82
|
+
pass
|
83
|
+
|
84
|
+
async def set_variable(self, variable, value, program: str = None):
|
85
|
+
if not program:
|
86
|
+
program = self._program
|
87
|
+
sql = f"""UPDATE troc.process_variables SET raw_value = '{value}', \
|
88
|
+
updated_at = CURRENT_DATE
|
89
|
+
WHERE program_slug = '{program}' AND variable_name = '{variable}'"""
|
90
|
+
logging.debug(f"VAR SQL: {sql}")
|
91
|
+
try:
|
92
|
+
connection = self.default_connection('pg')
|
93
|
+
except Exception as err:
|
94
|
+
logging.exception(err, stack_info=True)
|
95
|
+
raise
|
96
|
+
async with await connection.connection() as conn:
|
97
|
+
try:
|
98
|
+
ok = await conn.execute(sql)
|
99
|
+
if ok:
|
100
|
+
self.add_metric("SET_VARIABLE", f"{variable}={value}")
|
101
|
+
return True
|
102
|
+
else:
|
103
|
+
return False
|
104
|
+
except Exception as err:
|
105
|
+
logging.exception(err)
|
106
|
+
return False
|
107
|
+
|
108
|
+
async def run(self):
|
109
|
+
self._result = self.data
|
110
|
+
try:
|
111
|
+
# Replace variables
|
112
|
+
for val in self._variables:
|
113
|
+
if isinstance(self._variables[val], list):
|
114
|
+
if isinstance(self._variables[val], int):
|
115
|
+
self._variables[val] = ", ".join(self._variables[val])
|
116
|
+
else:
|
117
|
+
self._variables[val] = ", ".join(
|
118
|
+
"'{}'".format(v) for v in self._variables[val]
|
119
|
+
)
|
120
|
+
self.value = self.value.replace(
|
121
|
+
"{{{}}}".format(str(val)), str(self._variables[val])
|
122
|
+
)
|
123
|
+
if hasattr(self, "program_slug"):
|
124
|
+
program = self.program_slug
|
125
|
+
else:
|
126
|
+
program = self._program
|
127
|
+
if hasattr(self, "name"):
|
128
|
+
self._environment.set(self.name, self.value)
|
129
|
+
value = self._environment.get(self.name)
|
130
|
+
if value == self.value:
|
131
|
+
await self.set_variable(self.name, value, program)
|
132
|
+
elif hasattr(self, "names"):
|
133
|
+
value = None
|
134
|
+
for name in self.names:
|
135
|
+
try:
|
136
|
+
self._environment.set(name, self.value)
|
137
|
+
value = self._environment.get(name)
|
138
|
+
except Exception as err:
|
139
|
+
print(err)
|
140
|
+
if value == self.value:
|
141
|
+
await self.set_variable(name, value, program)
|
142
|
+
return self._result
|
143
|
+
except Exception as err:
|
144
|
+
print(err)
|
145
|
+
raise ComponentError(
|
146
|
+
f"Error setting operational variable [{err.__class__.__name__}]: {err}"
|
147
|
+
) from err
|
@@ -0,0 +1,299 @@
|
|
1
|
+
from typing import List, Dict
|
2
|
+
from abc import abstractmethod
|
3
|
+
from collections.abc import Callable
|
4
|
+
import asyncio
|
5
|
+
import logging
|
6
|
+
import random
|
7
|
+
import ssl
|
8
|
+
from pathlib import Path, PosixPath
|
9
|
+
from functools import partial
|
10
|
+
import aiohttp
|
11
|
+
from aiohttp import web
|
12
|
+
from tqdm import tqdm
|
13
|
+
from datamodel.parsers.json import json_encoder
|
14
|
+
from datamodel.parsers.encoders import DefaultEncoder
|
15
|
+
from ..exceptions import ComponentError, FileNotFound
|
16
|
+
from .flow import FlowComponent
|
17
|
+
from ..interfaces.http import ua
|
18
|
+
|
19
|
+
|
20
|
+
class UploadToBase(FlowComponent):
|
21
|
+
"""
|
22
|
+
UploadToBase
|
23
|
+
|
24
|
+
Overview
|
25
|
+
|
26
|
+
The `UploadToBase` class is an abstract component designed to handle file uploads to various destinations,
|
27
|
+
including servers over HTTP/HTTPS. This class manages credentials, connection settings, SSL configurations,
|
28
|
+
and supports progress tracking during file uploads.
|
29
|
+
|
30
|
+
.. table:: Properties
|
31
|
+
:widths: auto
|
32
|
+
|
33
|
+
+-------------------------+----------+-----------+----------------------------------------------------------------------------+
|
34
|
+
| Name | Required | Description |
|
35
|
+
+-------------------------+----------+-----------+----------------------------------------------------------------------------+
|
36
|
+
| url | Yes | The URL to which files will be uploaded. |
|
37
|
+
+-------------------------+----------+-----------+----------------------------------------------------------------------------+
|
38
|
+
| credentials | Yes | A dictionary containing the credentials necessary for authentication. |
|
39
|
+
+-------------------------+----------+-----------+----------------------------------------------------------------------------+
|
40
|
+
| source_file | No | The path to the source file to be uploaded. |
|
41
|
+
+-------------------------+----------+-----------+----------------------------------------------------------------------------+
|
42
|
+
| source_dir | No | The directory containing the source files to be uploaded. |
|
43
|
+
+-------------------------+----------+-----------+----------------------------------------------------------------------------+
|
44
|
+
| filename | No | The destination filename for the uploaded file. |
|
45
|
+
+-------------------------+----------+-----------+----------------------------------------------------------------------------+
|
46
|
+
| create_destination | No | A flag indicating whether to create the destination directory if it doesn't exist.|
|
47
|
+
+-------------------------+----------+-----------+----------------------------------------------------------------------------+
|
48
|
+
| ssl | No | A flag indicating whether to use SSL/TLS for the connection. |
|
49
|
+
+-------------------------+----------+-----------+----------------------------------------------------------------------------+
|
50
|
+
| ssl_cafile | No | The path to the CA file for SSL/TLS validation. |
|
51
|
+
+-------------------------+----------+-----------+----------------------------------------------------------------------------+
|
52
|
+
| ssl_certs | No | A list of SSL certificates to be used for the connection. |
|
53
|
+
+-------------------------+----------+-----------+----------------------------------------------------------------------------+
|
54
|
+
| host | Yes | The host address of the destination server. |
|
55
|
+
+-------------------------+----------+-----------+----------------------------------------------------------------------------+
|
56
|
+
| port | Yes | The port number of the destination server. |
|
57
|
+
+-------------------------+----------+-----------+----------------------------------------------------------------------------+
|
58
|
+
| overwrite | No | A flag indicating whether to overwrite the file if it already exists. |
|
59
|
+
+-------------------------+----------+-----------+----------------------------------------------------------------------------+
|
60
|
+
| rename | No | A flag indicating whether to rename the file if a file with the same name exists.|
|
61
|
+
+-------------------------+----------+-----------+----------------------------------------------------------------------------+
|
62
|
+
| timeout | No | The timeout value for the upload operation. |
|
63
|
+
+-------------------------+----------+-----------+----------------------------------------------------------------------------+
|
64
|
+
| response_status | No | A list of acceptable HTTP response statuses for a successful upload. |
|
65
|
+
+-------------------------+----------+-----------+----------------------------------------------------------------------------+
|
66
|
+
|
67
|
+
Return
|
68
|
+
|
69
|
+
The methods in this class manage the upload of files to specified destinations, including initialization,
|
70
|
+
execution, and result handling.
|
71
|
+
|
72
|
+
""" # noqa
|
73
|
+
url: str = None
|
74
|
+
_credentials: Dict = {"username": str, "password": str}
|
75
|
+
|
76
|
+
def __init__(
|
77
|
+
self,
|
78
|
+
loop: asyncio.AbstractEventLoop = None,
|
79
|
+
job: Callable = None,
|
80
|
+
stat: Callable = None,
|
81
|
+
**kwargs,
|
82
|
+
):
|
83
|
+
self.accept: str = "text/plain"
|
84
|
+
self.url: str = kwargs.get('url', None)
|
85
|
+
self.overwrite: bool = True
|
86
|
+
self.rename: bool = True
|
87
|
+
self.create_destination: bool = kwargs.get('create_destination', False)
|
88
|
+
# source:
|
89
|
+
self.source_file: str = None
|
90
|
+
self.source_dir: str = None
|
91
|
+
# destination:
|
92
|
+
self.filename: str = None
|
93
|
+
self._filenames: List = []
|
94
|
+
self._destination: List = []
|
95
|
+
self._connection: Callable = None
|
96
|
+
self.ssl: bool = False
|
97
|
+
self.ssl_cafile: str = None
|
98
|
+
self.ssl_certs: list = []
|
99
|
+
super().__init__(
|
100
|
+
loop=loop,
|
101
|
+
job=job,
|
102
|
+
stat=stat,
|
103
|
+
**kwargs
|
104
|
+
)
|
105
|
+
self._encoder = DefaultEncoder()
|
106
|
+
self._valid_response_status: List = (200, 201, 202)
|
107
|
+
# SSL Context:
|
108
|
+
if self.ssl:
|
109
|
+
# TODO: add CAFile and cert-chain
|
110
|
+
self.ssl_ctx = ssl.SSLContext(ssl.PROTOCOL_TLS, cafile=self.ssl_cafile)
|
111
|
+
self.ssl_ctx.options &= ~ssl.OP_NO_SSLv3
|
112
|
+
self.ssl_ctx.verify_mode = ssl.CERT_NONE
|
113
|
+
if self.ssl_certs:
|
114
|
+
self.ssl_ctx.load_cert_chain(*self.ssl_certs)
|
115
|
+
else:
|
116
|
+
self.ssl_ctx = None
|
117
|
+
|
118
|
+
def define_host(self):
|
119
|
+
try:
|
120
|
+
self.host = self.credentials["host"]
|
121
|
+
except KeyError:
|
122
|
+
self.host = self.host
|
123
|
+
try:
|
124
|
+
self.port = self.credentials["port"]
|
125
|
+
except KeyError:
|
126
|
+
self.port = self.port
|
127
|
+
# getting from environment:
|
128
|
+
self.host = self.get_env_value(self.host, default=self.host)
|
129
|
+
self.port = self.get_env_value(str(self.port), default=self.port)
|
130
|
+
if self.host:
|
131
|
+
self._logger.debug(f"<{__name__}>: HOST: {self.host}, PORT: {self.port}")
|
132
|
+
|
133
|
+
def build_headers(self):
|
134
|
+
self.headers = {
|
135
|
+
"Accept": self.accept,
|
136
|
+
"Accept-Encoding": "gzip, deflate",
|
137
|
+
"DNT": "1",
|
138
|
+
"Connection": "keep-alive",
|
139
|
+
"Upgrade-Insecure-Requests": "1",
|
140
|
+
"User-Agent": random.choice(ua),
|
141
|
+
**self.headers,
|
142
|
+
}
|
143
|
+
|
144
|
+
async def start(self, **kwargs):
|
145
|
+
"""Start.
|
146
|
+
|
147
|
+
Processing variables and credentials.
|
148
|
+
"""
|
149
|
+
if getattr(self, 'define_host', None) is not None:
|
150
|
+
self.define_host()
|
151
|
+
try:
|
152
|
+
self.processing_credentials()
|
153
|
+
except Exception as err:
|
154
|
+
self._logger.error(err)
|
155
|
+
raise
|
156
|
+
if hasattr(self, "file"):
|
157
|
+
filename = self.process_pattern("file")
|
158
|
+
if hasattr(self, "masks"):
|
159
|
+
filename = self.mask_replacement(filename)
|
160
|
+
# path for file
|
161
|
+
# get path of all files:
|
162
|
+
self._logger.debug("Filename > {}".format(filename))
|
163
|
+
self._filenames.append(filename)
|
164
|
+
if hasattr(self, "source"): # using the destination filosophy
|
165
|
+
try:
|
166
|
+
if hasattr(self, "masks"):
|
167
|
+
self.source_dir = self.mask_replacement(self.source["directory"])
|
168
|
+
else:
|
169
|
+
self.source_dir = self.source["directory"]
|
170
|
+
except KeyError:
|
171
|
+
self.source_dir = "/"
|
172
|
+
print(":: Source Dir: ", self.source_dir)
|
173
|
+
self.source_dir = Path(self.source_dir)
|
174
|
+
# filename:
|
175
|
+
if "file" in self.source:
|
176
|
+
self.source_file = self.process_pattern("file", parent=self.source)
|
177
|
+
else:
|
178
|
+
try:
|
179
|
+
self.source_file = self.mask_replacement(self.source["filename"])
|
180
|
+
except KeyError:
|
181
|
+
self.source_file = None
|
182
|
+
if hasattr(self, "destination"):
|
183
|
+
self.directory = self.destination.get('directory')
|
184
|
+
self.directory = self.mask_replacement(self.directory)
|
185
|
+
if isinstance(self.directory, str):
|
186
|
+
self.directory = Path(self.directory).resolve()
|
187
|
+
# Create directory if not exists
|
188
|
+
try:
|
189
|
+
if self.create_destination is True:
|
190
|
+
self.directory.mkdir(parents=True, exist_ok=True)
|
191
|
+
except OSError as err:
|
192
|
+
raise ComponentError(
|
193
|
+
f"UploadTo: Error creating destination directory {self.directory}: {err}"
|
194
|
+
) from err
|
195
|
+
except Exception as err:
|
196
|
+
self._logger.error(
|
197
|
+
f"Error creating destination directory {self.directory}: {err}"
|
198
|
+
)
|
199
|
+
raise ComponentError(
|
200
|
+
f"Error creating destination directory {self.directory}: {err}"
|
201
|
+
) from err
|
202
|
+
try:
|
203
|
+
fname = self.destination.get('filename')
|
204
|
+
if self.directory.exists():
|
205
|
+
self.filename = self.directory.joinpath(fname)
|
206
|
+
else:
|
207
|
+
self.filename = fname
|
208
|
+
self._logger.debug(
|
209
|
+
f"Raw Filename: {self.filename}\n"
|
210
|
+
)
|
211
|
+
if hasattr(self, "masks"):
|
212
|
+
self.filename = self.mask_replacement(self.filename)
|
213
|
+
self._destination.append(self.filename)
|
214
|
+
except Exception:
|
215
|
+
pass
|
216
|
+
if self.url:
|
217
|
+
self.build_headers()
|
218
|
+
return True
|
219
|
+
|
220
|
+
async def http_response(self, response: web.Response):
|
221
|
+
"""http_response.
|
222
|
+
|
223
|
+
Return the request response of the HTTP Session
|
224
|
+
|
225
|
+
Args:
|
226
|
+
response (web.Response): the Response of the HTTP Session.
|
227
|
+
|
228
|
+
Returns:
|
229
|
+
Any: any processed data.
|
230
|
+
"""
|
231
|
+
return response
|
232
|
+
|
233
|
+
async def upload_session(
|
234
|
+
self, url, method: str = "get", data: Dict = None, data_format: str = "json"
|
235
|
+
):
|
236
|
+
"""
|
237
|
+
session.
|
238
|
+
connect to an http source using aiohttp
|
239
|
+
"""
|
240
|
+
timeout = aiohttp.ClientTimeout(total=self.timeout)
|
241
|
+
# TODO: Auth, Data, etc
|
242
|
+
auth = {}
|
243
|
+
params = {}
|
244
|
+
_data = {"data": None}
|
245
|
+
if self.credentials:
|
246
|
+
if "username" in self.credentials: # basic Authentication
|
247
|
+
auth = aiohttp.BasicAuth(
|
248
|
+
self.credentials["username"], self.credentials["password"]
|
249
|
+
)
|
250
|
+
params = {"auth": auth}
|
251
|
+
elif "token" in self.credentials:
|
252
|
+
self.headers["Authorization"] = "{scheme} {token}".format(
|
253
|
+
scheme=self.credentials["scheme"], token=self.credentials["token"]
|
254
|
+
)
|
255
|
+
if data_format == "json":
|
256
|
+
params["json_serialize"] = json_encoder
|
257
|
+
_data["json"] = data
|
258
|
+
else:
|
259
|
+
_data["data"] = data
|
260
|
+
async with aiohttp.ClientSession(**params) as session:
|
261
|
+
meth = getattr(session, method)
|
262
|
+
if self.ssl:
|
263
|
+
ssl = {"ssl": self.ssl_ctx, "verify_ssl": True}
|
264
|
+
else:
|
265
|
+
ssl = {}
|
266
|
+
fn = partial(
|
267
|
+
meth,
|
268
|
+
self.url,
|
269
|
+
headers=self.headers,
|
270
|
+
timeout=timeout,
|
271
|
+
allow_redirects=True,
|
272
|
+
**ssl,
|
273
|
+
**_data,
|
274
|
+
)
|
275
|
+
try:
|
276
|
+
async with fn() as response:
|
277
|
+
if response.status in self._valid_response_status:
|
278
|
+
return await self.http_response(response)
|
279
|
+
else:
|
280
|
+
raise ComponentError(
|
281
|
+
f"UploadTo: Error getting data from URL {response}"
|
282
|
+
)
|
283
|
+
except aiohttp.HTTPError as err:
|
284
|
+
raise ComponentError(
|
285
|
+
f"UploadTo: Error Making an SSL Connection to ({self.url}): {err}"
|
286
|
+
) from err
|
287
|
+
except aiohttp.ClientSSLError as err:
|
288
|
+
raise ComponentError(f"UploadTo: SSL Certificate Error: {err}") from err
|
289
|
+
|
290
|
+
@abstractmethod
|
291
|
+
async def close(self):
|
292
|
+
pass
|
293
|
+
|
294
|
+
@abstractmethod
|
295
|
+
async def run(self):
|
296
|
+
pass
|
297
|
+
|
298
|
+
def start_pbar(self, total: int = 1):
|
299
|
+
return tqdm(total=total)
|