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,376 @@
|
|
1
|
+
"""
|
2
|
+
TaskManager.
|
3
|
+
|
4
|
+
Work with managing tasks, creation, deleting, listing, etc.
|
5
|
+
"""
|
6
|
+
import asyncio
|
7
|
+
import json
|
8
|
+
import datetime
|
9
|
+
import uuid
|
10
|
+
from functools import partial
|
11
|
+
from uuid import UUID
|
12
|
+
import logging
|
13
|
+
import ast
|
14
|
+
from aiohttp import web
|
15
|
+
from navigator.views import DataView
|
16
|
+
from asyncdb.utils.encoders import BaseEncoder, DefaultEncoder
|
17
|
+
from querysource.utils.functions import format_date
|
18
|
+
from .tasks import task_state, execute_task, launch_task
|
19
|
+
from ...exceptions import (
|
20
|
+
NotSupported,
|
21
|
+
ComponentError,
|
22
|
+
TaskNotFound,
|
23
|
+
TaskDefinition,
|
24
|
+
TaskFailed,
|
25
|
+
FileError,
|
26
|
+
FileNotFound,
|
27
|
+
)
|
28
|
+
|
29
|
+
|
30
|
+
def is_boolean(value: str) -> bool:
|
31
|
+
if isinstance(value, bool):
|
32
|
+
return value
|
33
|
+
try:
|
34
|
+
return ast.literal_eval(value)
|
35
|
+
except ValueError:
|
36
|
+
return False
|
37
|
+
|
38
|
+
|
39
|
+
class TaskManager(DataView):
|
40
|
+
async def get(self):
|
41
|
+
"""
|
42
|
+
GET Method.
|
43
|
+
---
|
44
|
+
description: get all tasks, or a task by ID (or get status of execution)
|
45
|
+
tags:
|
46
|
+
- tasks
|
47
|
+
- DataIntegration
|
48
|
+
consumes:
|
49
|
+
- application/json
|
50
|
+
produces:
|
51
|
+
- application/json
|
52
|
+
responses:
|
53
|
+
"200":
|
54
|
+
description: Existing Task was retrieved.
|
55
|
+
"403":
|
56
|
+
description: Forbidden Call
|
57
|
+
"404":
|
58
|
+
description: No Task(s) were found
|
59
|
+
"406":
|
60
|
+
description: Query Error
|
61
|
+
"""
|
62
|
+
try:
|
63
|
+
sql = "SELECT * FROM {program}.tasks"
|
64
|
+
await self.connect(self.request)
|
65
|
+
params = self.get_args()
|
66
|
+
print(params, sql)
|
67
|
+
# try:
|
68
|
+
# session = self.request['session']
|
69
|
+
# except KeyError:
|
70
|
+
# return self.error(request=self.request, response="Unknown User", state=403)
|
71
|
+
try:
|
72
|
+
program = params["program"]
|
73
|
+
except KeyError:
|
74
|
+
program = "troc"
|
75
|
+
try:
|
76
|
+
task = params["task_id"]
|
77
|
+
except KeyError:
|
78
|
+
task = None
|
79
|
+
sql = sql.format(program=program)
|
80
|
+
print(sql)
|
81
|
+
if task is not None:
|
82
|
+
sql = "{sql} WHERE task = '{id}' AND enabled = true".format(
|
83
|
+
sql=sql, id=task
|
84
|
+
)
|
85
|
+
print("SQL IS ", sql)
|
86
|
+
try:
|
87
|
+
result = await self.query(sql)
|
88
|
+
except Exception as e:
|
89
|
+
msg = {"error": str(e), "exception": str(e.__class__)}
|
90
|
+
return self.error(
|
91
|
+
request=self.request, response=msg, exception=e, state=400
|
92
|
+
)
|
93
|
+
if result:
|
94
|
+
data = []
|
95
|
+
for row in result:
|
96
|
+
data.append(dict(row))
|
97
|
+
for elements in data:
|
98
|
+
for key, value in elements.items():
|
99
|
+
elements[key] = (
|
100
|
+
str(value)
|
101
|
+
if isinstance(
|
102
|
+
value, (UUID, datetime.time, datetime.datetime)
|
103
|
+
)
|
104
|
+
else value
|
105
|
+
)
|
106
|
+
headers = {"X-STATUS": "OK", "X-MESSAGE": "Tasks List"}
|
107
|
+
return self.json_response(response=data, headers=headers)
|
108
|
+
else:
|
109
|
+
if self._lasterr:
|
110
|
+
msg = {"error": str(self._lasterr)}
|
111
|
+
return self.error(
|
112
|
+
request=self.request,
|
113
|
+
response=msg,
|
114
|
+
exception=self._lasterr,
|
115
|
+
state=400,
|
116
|
+
)
|
117
|
+
headers = {"X-STATUS": "EMPTY", "X-MESSAGE": "Data not Found"}
|
118
|
+
return self.no_content(headers=headers)
|
119
|
+
except Exception as e:
|
120
|
+
print(e)
|
121
|
+
return self.critical(self.request, e)
|
122
|
+
finally:
|
123
|
+
await self.close()
|
124
|
+
|
125
|
+
async def post(self):
|
126
|
+
"""
|
127
|
+
POST Method.
|
128
|
+
description: inserting or updating a Task or executing a Task
|
129
|
+
tags:
|
130
|
+
- tasks
|
131
|
+
- DataIntegration
|
132
|
+
consumes:
|
133
|
+
- application/json
|
134
|
+
produces:
|
135
|
+
- application/json
|
136
|
+
responses:
|
137
|
+
"200":
|
138
|
+
description: Existing Task was updated or executed.
|
139
|
+
"201":
|
140
|
+
description: New Task was inserted
|
141
|
+
"202":
|
142
|
+
description: Task was accepted to run
|
143
|
+
"400":
|
144
|
+
description: Task Failed to execute
|
145
|
+
"403":
|
146
|
+
description: Forbidden Call
|
147
|
+
"404":
|
148
|
+
description: No Data was found
|
149
|
+
"406":
|
150
|
+
description: Query Error
|
151
|
+
"409":
|
152
|
+
description: Conflict, a constraint was violated
|
153
|
+
"""
|
154
|
+
# using LOCATION header to return the URL of the API
|
155
|
+
await self.connect(self.request)
|
156
|
+
# get the URL parameters
|
157
|
+
params = self.get_args()
|
158
|
+
# get post Data
|
159
|
+
data = await self.post_data()
|
160
|
+
# long
|
161
|
+
longrunner = False
|
162
|
+
try:
|
163
|
+
program = params["program"]
|
164
|
+
del params["program"]
|
165
|
+
except KeyError:
|
166
|
+
# we need a program
|
167
|
+
try:
|
168
|
+
program = data["program"]
|
169
|
+
except KeyError:
|
170
|
+
headers = {
|
171
|
+
"X-STATUS": "Error",
|
172
|
+
"X-MESSAGE": "Resource Error: We need a Program Name",
|
173
|
+
}
|
174
|
+
msg = {
|
175
|
+
"state": "Failed",
|
176
|
+
"message": "Error: we need a program name",
|
177
|
+
"status": 400,
|
178
|
+
}
|
179
|
+
return self.error(
|
180
|
+
request=self.request, response=msg, headers=headers, state=400
|
181
|
+
)
|
182
|
+
try:
|
183
|
+
task_id = params["task_id"]
|
184
|
+
del params["task_id"]
|
185
|
+
except KeyError:
|
186
|
+
# we need a Task ID
|
187
|
+
try:
|
188
|
+
task_id = data["task_id"]
|
189
|
+
except KeyError:
|
190
|
+
headers = {
|
191
|
+
"X-STATUS": "Error",
|
192
|
+
"X-MESSAGE": "Resource Error: We need a Task Name",
|
193
|
+
}
|
194
|
+
msg = {
|
195
|
+
"state": "Failed",
|
196
|
+
"message": "Error: we need a Task ID",
|
197
|
+
"status": 400,
|
198
|
+
}
|
199
|
+
return self.error(
|
200
|
+
request=self.request, response=msg, headers=headers, state=400
|
201
|
+
)
|
202
|
+
try:
|
203
|
+
try:
|
204
|
+
longrunner = is_boolean(data["long_running"])
|
205
|
+
del data["long_running"]
|
206
|
+
except KeyError:
|
207
|
+
try:
|
208
|
+
longrunner = is_boolean(params["long_running"])
|
209
|
+
del params["long_running"]
|
210
|
+
except KeyError:
|
211
|
+
longrunner = False
|
212
|
+
try:
|
213
|
+
no_worker = is_boolean(data["no_worker"])
|
214
|
+
del data["no_worker"]
|
215
|
+
except KeyError:
|
216
|
+
no_worker = False
|
217
|
+
logging.debug(f"Long Runner: {longrunner}, No Worker: {no_worker}")
|
218
|
+
# cannot update or insert a Task, we need to Run that task
|
219
|
+
status = None
|
220
|
+
result = {}
|
221
|
+
try:
|
222
|
+
# TODO: passing arguments via URL to the task
|
223
|
+
args = {}
|
224
|
+
if isinstance(params, dict):
|
225
|
+
args = params
|
226
|
+
if data:
|
227
|
+
args = {**args, **data}
|
228
|
+
task_uuid = uuid.uuid4()
|
229
|
+
status, action, result = await launch_task(
|
230
|
+
program_slug=program,
|
231
|
+
task_id=task_id,
|
232
|
+
loop=self._loop,
|
233
|
+
task_uuid=task_uuid,
|
234
|
+
queued=longrunner,
|
235
|
+
no_worker=no_worker,
|
236
|
+
**args,
|
237
|
+
)
|
238
|
+
result = {"task": f"{program}.{task_id}", "task_execution": task_uuid}
|
239
|
+
if action == "Executed":
|
240
|
+
state = 200
|
241
|
+
else:
|
242
|
+
state = 202
|
243
|
+
response = {
|
244
|
+
"state": state,
|
245
|
+
"message": "Task {}.{} was {}".format(program, task_id, action),
|
246
|
+
**result,
|
247
|
+
}
|
248
|
+
headers = {
|
249
|
+
"X-STATUS": "Task OK",
|
250
|
+
"X-MESSAGE": "Execution of Task {}.{} on {}".format(
|
251
|
+
program, task_id, action
|
252
|
+
),
|
253
|
+
}
|
254
|
+
return self.json_response(
|
255
|
+
response=response,
|
256
|
+
headers=headers,
|
257
|
+
state=response["state"],
|
258
|
+
cls=BaseEncoder,
|
259
|
+
)
|
260
|
+
except TaskNotFound as err:
|
261
|
+
error = "Error: on Task {}.{}".format(program, task_id)
|
262
|
+
msg = {"message": error}
|
263
|
+
return self.error(
|
264
|
+
request=self.request, response=msg, exception=err, state=401
|
265
|
+
)
|
266
|
+
except TaskFailed as err:
|
267
|
+
print(err)
|
268
|
+
error = "Error: Task {} Failed".format(task_id)
|
269
|
+
msg = {"message": error}
|
270
|
+
return self.error(
|
271
|
+
request=self.request, response=msg, exception=err, state=400
|
272
|
+
)
|
273
|
+
except (FileNotFound, FileError) as err:
|
274
|
+
print(err)
|
275
|
+
error = "Error on Task {} File Not Found: {}".format(task_id, str(err))
|
276
|
+
msg = {"message": error}
|
277
|
+
return self.error(
|
278
|
+
request=self.request, response=msg, exception=err, state=404
|
279
|
+
)
|
280
|
+
except Exception as err:
|
281
|
+
print(err)
|
282
|
+
return self.critical(request=self.request, exception=err, state=500)
|
283
|
+
headers = {"X-STATUS": "EMPTY", "X-MESSAGE": "Data not Found"}
|
284
|
+
return self.no_content(headers=headers)
|
285
|
+
except Exception as e:
|
286
|
+
print(f"Generic Error on POST Method: {e}")
|
287
|
+
return self.critical(self.request, e)
|
288
|
+
finally:
|
289
|
+
await self.close()
|
290
|
+
|
291
|
+
async def put(self):
|
292
|
+
"""
|
293
|
+
PUT Method.
|
294
|
+
description: inserting or updating a Task
|
295
|
+
tags:
|
296
|
+
- tasks
|
297
|
+
- DataIntegration
|
298
|
+
produces:
|
299
|
+
- application/json
|
300
|
+
consumes:
|
301
|
+
- application/merge-patch+json
|
302
|
+
- application/json
|
303
|
+
responses:
|
304
|
+
"200":
|
305
|
+
description: Existing Task was updated.
|
306
|
+
"201":
|
307
|
+
description: New Task was inserted
|
308
|
+
"204":
|
309
|
+
description: success execution but no content on return (resource was deleted)
|
310
|
+
"400":
|
311
|
+
description: Invalid resource according data schema
|
312
|
+
"403":
|
313
|
+
description: Forbidden Call
|
314
|
+
"404":
|
315
|
+
description: No Data was found
|
316
|
+
"406":
|
317
|
+
description: Query Error
|
318
|
+
"409":
|
319
|
+
description: Conflict, a constraint was violated
|
320
|
+
"""
|
321
|
+
pass
|
322
|
+
|
323
|
+
async def delete(self):
|
324
|
+
"""
|
325
|
+
DELETE Method.
|
326
|
+
description: remove resource.
|
327
|
+
tags:
|
328
|
+
- tasks
|
329
|
+
- DataIntegration
|
330
|
+
produces:
|
331
|
+
- application/json
|
332
|
+
responses:
|
333
|
+
"200":
|
334
|
+
description: Existing Task was updated.
|
335
|
+
"201":
|
336
|
+
description: New Task was inserted
|
337
|
+
"403":
|
338
|
+
description: Forbidden Call
|
339
|
+
"404":
|
340
|
+
description: No Data was found
|
341
|
+
"406":
|
342
|
+
description: Query Error
|
343
|
+
"409":
|
344
|
+
description: Conflict, a constraint was violated
|
345
|
+
"""
|
346
|
+
pass
|
347
|
+
|
348
|
+
async def patch(self):
|
349
|
+
"""
|
350
|
+
PATCH Method.
|
351
|
+
description: updating partially info about a Task
|
352
|
+
tags:
|
353
|
+
- tasks
|
354
|
+
- DataIntegration
|
355
|
+
produces:
|
356
|
+
- application/json
|
357
|
+
responses:
|
358
|
+
"200":
|
359
|
+
description: Existing Task was updated.
|
360
|
+
"201":
|
361
|
+
description: New Task was inserted
|
362
|
+
"304":
|
363
|
+
description: Task not modified, its currently the actual version of Task
|
364
|
+
"403":
|
365
|
+
description: Forbidden Call
|
366
|
+
"404":
|
367
|
+
description: No Data was found
|
368
|
+
"406":
|
369
|
+
description: Query Error
|
370
|
+
"409":
|
371
|
+
description: Conflict, a constraint was violated
|
372
|
+
"""
|
373
|
+
pass
|
374
|
+
|
375
|
+
async def head(self):
|
376
|
+
pass
|
@@ -0,0 +1,155 @@
|
|
1
|
+
from typing import Union
|
2
|
+
import asyncio
|
3
|
+
from concurrent.futures import ThreadPoolExecutor
|
4
|
+
import jsonpickle
|
5
|
+
import pandas as pd
|
6
|
+
from navconfig import config as ENV
|
7
|
+
from navconfig.logging import logging
|
8
|
+
|
9
|
+
# Queue Worker Client:
|
10
|
+
from qw.client import QClient
|
11
|
+
from qw.wrappers import TaskWrapper
|
12
|
+
from ...conf import DEBUG, WORKER_LIST, WORKER_HIGH_LIST
|
13
|
+
from ...exceptions import (
|
14
|
+
NotSupported,
|
15
|
+
TaskNotFound,
|
16
|
+
TaskFailed,
|
17
|
+
FileError,
|
18
|
+
FileNotFound,
|
19
|
+
DataNotFound,
|
20
|
+
)
|
21
|
+
from ...tasks.task import Task
|
22
|
+
|
23
|
+
|
24
|
+
if WORKER_LIST:
|
25
|
+
QW = QClient(worker_list=WORKER_LIST)
|
26
|
+
QW_high = QClient(worker_list=WORKER_HIGH_LIST)
|
27
|
+
else:
|
28
|
+
QW = QClient() # auto-discovering of workers
|
29
|
+
QW_high = QW
|
30
|
+
|
31
|
+
|
32
|
+
async def launch_task(
|
33
|
+
program_slug: str,
|
34
|
+
task_id: str,
|
35
|
+
loop: asyncio.AbstractEventLoop = None,
|
36
|
+
task_uuid: str = None,
|
37
|
+
queued: bool = False,
|
38
|
+
no_worker: bool = False,
|
39
|
+
priority: str = "low",
|
40
|
+
userid: Union[int, str] = None,
|
41
|
+
**kwargs,
|
42
|
+
):
|
43
|
+
"""launch_task.
|
44
|
+
Runs (or queued) a Task from Task Monitor.
|
45
|
+
"""
|
46
|
+
state = None
|
47
|
+
result = {}
|
48
|
+
|
49
|
+
if no_worker is True:
|
50
|
+
# Running task in Local
|
51
|
+
print(f"RUNNING TASK {program_slug}.{task_id}")
|
52
|
+
task = Task(
|
53
|
+
task=task_id,
|
54
|
+
program=program_slug,
|
55
|
+
loop=loop,
|
56
|
+
ignore_results=False,
|
57
|
+
ENV=ENV,
|
58
|
+
debug=DEBUG,
|
59
|
+
userid=userid,
|
60
|
+
**kwargs,
|
61
|
+
)
|
62
|
+
try:
|
63
|
+
state = await task.start()
|
64
|
+
if not state:
|
65
|
+
logging.warning(
|
66
|
+
f"Task {program_slug}.{task_id} return False on Start Time."
|
67
|
+
)
|
68
|
+
except Exception as err:
|
69
|
+
logging.error(err)
|
70
|
+
raise
|
71
|
+
try:
|
72
|
+
state = await task.run()
|
73
|
+
try:
|
74
|
+
result["stats"] = task.stats.stats
|
75
|
+
except Exception as err:
|
76
|
+
result["stats"] = None
|
77
|
+
result["error"] = err
|
78
|
+
### gettting the result of Task execution
|
79
|
+
if isinstance(state, pd.DataFrame):
|
80
|
+
numrows = len(state.index)
|
81
|
+
columns = list(state.columns)
|
82
|
+
num_cols = len(columns)
|
83
|
+
state = {
|
84
|
+
"type": "Dataframe",
|
85
|
+
"numrows": numrows,
|
86
|
+
"columns": columns,
|
87
|
+
"num_cols": num_cols,
|
88
|
+
}
|
89
|
+
else:
|
90
|
+
state = f"{state!r}"
|
91
|
+
result["result"] = state
|
92
|
+
return (state, "Executed", result)
|
93
|
+
except DataNotFound as err:
|
94
|
+
raise
|
95
|
+
except NotSupported as err:
|
96
|
+
raise
|
97
|
+
except TaskNotFound as err:
|
98
|
+
raise TaskNotFound(f"Task: {task_id}: {err}") from err
|
99
|
+
except TaskFailed as err:
|
100
|
+
raise TaskFailed(f"Task {task_id} failed: {err}") from err
|
101
|
+
except FileNotFound:
|
102
|
+
raise
|
103
|
+
except FileError as err:
|
104
|
+
raise FileError(f"Task {task_id}, File Not Found error: {err}") from err
|
105
|
+
except Exception as err:
|
106
|
+
raise TaskFailed(f"Error: Task {task_id} failed: {err}") from err
|
107
|
+
finally:
|
108
|
+
await task.close()
|
109
|
+
else:
|
110
|
+
if queued:
|
111
|
+
action = "Queued"
|
112
|
+
else:
|
113
|
+
action = "Dispatched"
|
114
|
+
# Task:
|
115
|
+
task = TaskWrapper(
|
116
|
+
program=program_slug, task=task_id, ignore_results=True, userid=userid, **kwargs
|
117
|
+
)
|
118
|
+
### TODO: Add Publish into Broker
|
119
|
+
if action == "Queued":
|
120
|
+
if priority == "high":
|
121
|
+
result = await asyncio.wait_for(QW_high.queue(task), timeout=10)
|
122
|
+
else:
|
123
|
+
result = await asyncio.wait_for(QW.queue(task), timeout=10)
|
124
|
+
try:
|
125
|
+
result["message"] = result["message"].decode("utf-8")
|
126
|
+
except (TypeError, KeyError):
|
127
|
+
result["message"] = None
|
128
|
+
print(f"Task Queued: {result!s}")
|
129
|
+
return (task_uuid, action, result)
|
130
|
+
else:
|
131
|
+
try:
|
132
|
+
if priority == "high":
|
133
|
+
result = await QW_high.run(task)
|
134
|
+
else:
|
135
|
+
result = await QW.run(task)
|
136
|
+
if isinstance(result, str):
|
137
|
+
# check if can we unserialize the jsonpickle
|
138
|
+
try:
|
139
|
+
result = jsonpickle.decode(result)
|
140
|
+
except (TypeError, KeyError, ValueError, AttributeError) as ex:
|
141
|
+
result = {"message": result, "error": ex}
|
142
|
+
logging.debug(f"Executed Task: {result!s}")
|
143
|
+
try:
|
144
|
+
result["message"] = result["message"].decode("utf-8")
|
145
|
+
except (TypeError, KeyError):
|
146
|
+
result["message"] = None
|
147
|
+
except AttributeError:
|
148
|
+
pass
|
149
|
+
return (task_uuid, action, result)
|
150
|
+
except (NotSupported, TaskNotFound, TaskFailed, FileNotFound, FileError) as ex:
|
151
|
+
logging.error(ex)
|
152
|
+
raise
|
153
|
+
except Exception as exc:
|
154
|
+
logging.error(exc)
|
155
|
+
raise TaskFailed(f"Error: Task {task_id} failed: {exc}") from exc
|
@@ -0,0 +1,16 @@
|
|
1
|
+
"""
|
2
|
+
Storages.
|
3
|
+
|
4
|
+
Storages covering the ways to store the data processed by the tasks and the task/hooks definitions.
|
5
|
+
|
6
|
+
FileStore: how Flowtask can store files in the filesystem.
|
7
|
+
TaskStorage: how Flowtask can store the task definitions (yaml, json files).
|
8
|
+
"""
|
9
|
+
from .files import FileStore
|
10
|
+
from .tasks import (
|
11
|
+
FileTaskStorage,
|
12
|
+
RowTaskStorage,
|
13
|
+
MemoryTaskStorage,
|
14
|
+
DatabaseTaskStorage,
|
15
|
+
GitTaskStorage
|
16
|
+
)
|
@@ -0,0 +1,29 @@
|
|
1
|
+
from typing import Any
|
2
|
+
from abc import ABC, abstractmethod
|
3
|
+
from navconfig import DEBUG
|
4
|
+
from navconfig.logging import logging
|
5
|
+
from ..exceptions import StoreError
|
6
|
+
|
7
|
+
|
8
|
+
class AbstractStore(ABC):
|
9
|
+
"""Abstract class for File Store."""
|
10
|
+
|
11
|
+
def __init__(self, *args, **kwargs) -> None:
|
12
|
+
self._name = self.__class__.__name__
|
13
|
+
self._program: Any = kwargs.pop("program", None)
|
14
|
+
self.logger = logging.getLogger(f"FlowTask.Files.{self._name}")
|
15
|
+
if DEBUG is True:
|
16
|
+
self.logger.notice(f":: Starting Store {self._name}")
|
17
|
+
self.kwargs = kwargs
|
18
|
+
self.args = args
|
19
|
+
|
20
|
+
def set_program(self, program: str) -> None:
|
21
|
+
self._program = program
|
22
|
+
|
23
|
+
@abstractmethod
|
24
|
+
def default_directory(self, directory: str):
|
25
|
+
pass
|
26
|
+
|
27
|
+
@abstractmethod
|
28
|
+
def get_directory(self, directory: str):
|
29
|
+
pass
|
@@ -0,0 +1,66 @@
|
|
1
|
+
from typing import Union, Optional
|
2
|
+
from pathlib import Path, PurePath
|
3
|
+
from .abstract import AbstractStore
|
4
|
+
from ..exceptions import StoreError
|
5
|
+
from ...exceptions import FileNotFound
|
6
|
+
|
7
|
+
|
8
|
+
class FileStore(AbstractStore):
|
9
|
+
"""
|
10
|
+
FileStore: Saving files in local filesystem.
|
11
|
+
"""
|
12
|
+
|
13
|
+
def __init__(
|
14
|
+
self, path: Union[str, PurePath], prefix: str, *args, **kwargs
|
15
|
+
) -> None:
|
16
|
+
if isinstance(path, str):
|
17
|
+
path = Path(path)
|
18
|
+
if path.exists() and path.is_dir():
|
19
|
+
self.path: PurePath = path
|
20
|
+
else:
|
21
|
+
raise StoreError(
|
22
|
+
f"FileStore: directory doesn't exists: {path}"
|
23
|
+
)
|
24
|
+
self._prefix: str = prefix
|
25
|
+
super().__init__(*args, **kwargs)
|
26
|
+
|
27
|
+
def default_directory(self, directory: str):
|
28
|
+
return self.path.joinpath(self._program, self._prefix, directory)
|
29
|
+
|
30
|
+
def get_directory(self, directory: str, program: Optional[str] = None):
|
31
|
+
if not program:
|
32
|
+
program = self._program
|
33
|
+
if isinstance(directory, PurePath):
|
34
|
+
_dir = directory
|
35
|
+
if ":" in directory:
|
36
|
+
# relative directory to Storage:
|
37
|
+
_dir = self.path.joinpath(
|
38
|
+
program, self._prefix, directory.rsplit(":", 1)[1]
|
39
|
+
)
|
40
|
+
elif ".." in directory:
|
41
|
+
# relative directory to base directory:
|
42
|
+
_dir = self.path.joinpath(directory)
|
43
|
+
else:
|
44
|
+
_dir = Path(directory)
|
45
|
+
# If not relative, try to use as is:
|
46
|
+
if not _dir.is_absolute() or not _dir.exists():
|
47
|
+
# Try to use instead base directory:
|
48
|
+
_dir = self.path.joinpath(
|
49
|
+
program,
|
50
|
+
self._prefix,
|
51
|
+
directory
|
52
|
+
)
|
53
|
+
elif not _dir.exists():
|
54
|
+
_dir = Path(directory).resolve()
|
55
|
+
if _dir.exists() and _dir.is_dir():
|
56
|
+
self.logger.debug(
|
57
|
+
f"Directory: {_dir}"
|
58
|
+
)
|
59
|
+
return _dir
|
60
|
+
else:
|
61
|
+
self.logger.error(
|
62
|
+
f"Path doesn't exists: {_dir}"
|
63
|
+
)
|
64
|
+
raise FileNotFound(
|
65
|
+
f"Path doesn't exists: {_dir}"
|
66
|
+
)
|
@@ -0,0 +1,19 @@
|
|
1
|
+
"""
|
2
|
+
Task Storage.
|
3
|
+
|
4
|
+
Saving Tasks on different Storages (Filesystem, S3 buckets, databases, etc)
|
5
|
+
"""
|
6
|
+
|
7
|
+
from .filesystem import FileTaskStorage
|
8
|
+
from .database import DatabaseTaskStorage
|
9
|
+
from .row import RowTaskStorage
|
10
|
+
from .github import GitTaskStorage
|
11
|
+
from .memory import MemoryTaskStorage
|
12
|
+
|
13
|
+
__all__ = (
|
14
|
+
"FileTaskStorage",
|
15
|
+
"DatabaseTaskStorage",
|
16
|
+
"RowTaskStorage",
|
17
|
+
"GitTaskStorage",
|
18
|
+
"MemoryTaskStorage",
|
19
|
+
)
|