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,173 @@
|
|
1
|
+
import os
|
2
|
+
import shutil
|
3
|
+
import asyncio
|
4
|
+
from navconfig.logging import logging
|
5
|
+
from asyncdb.exceptions import ProviderError
|
6
|
+
from asyncdb.drivers.pg import pg
|
7
|
+
from .flow import FlowComponent
|
8
|
+
from ..exceptions import ComponentError, DataNotFound
|
9
|
+
from querysource.conf import default_dsn, DB_TIMEOUT
|
10
|
+
import pandas as pd
|
11
|
+
|
12
|
+
|
13
|
+
class IcimsFolderCopy(FlowComponent):
|
14
|
+
"""
|
15
|
+
IcimsFolderCopy.
|
16
|
+
|
17
|
+
Copies folders from one directory to another based on data retrieved from a PostgreSQL database.
|
18
|
+
Supports three modes: copying all folders,
|
19
|
+
copying based on the associate's name, or copying based on the associate's ID.
|
20
|
+
|
21
|
+
Properties:
|
22
|
+
+-------------------+-------------+-------------------------------------------------+
|
23
|
+
| Name | Required | Summary |
|
24
|
+
+-------------------+-------------+-------------------------------------------------+
|
25
|
+
| driver | Yes | pg (default asyncdb PostgreSQL driver) |
|
26
|
+
| source_directory | Yes | Directory where folders are located |
|
27
|
+
| destination_dir | Yes | Directory where folders will be copied to |
|
28
|
+
| by_name | No | Person's name to filter by |
|
29
|
+
| by_associate_id | No | Associate ID to filter by |
|
30
|
+
+-------------------+-------------+-------------------------------------------------+
|
31
|
+
"""
|
32
|
+
|
33
|
+
def __init__(self, loop: asyncio.AbstractEventLoop = None, job=None, stat=None, **kwargs):
|
34
|
+
self.source_directory = kwargs.get("source_directory")
|
35
|
+
self.destination_directory = kwargs.get("destination_directory")
|
36
|
+
self.driver = kwargs.get("driver", "pg")
|
37
|
+
self.by_name = kwargs.get("by_name", None)
|
38
|
+
self.by_associate_id = kwargs.get("by_associate_id", None)
|
39
|
+
|
40
|
+
# Automatically load environment-based credentials
|
41
|
+
self.dsn = default_dsn
|
42
|
+
self.timeout = DB_TIMEOUT
|
43
|
+
|
44
|
+
# Initialize FlowComponent
|
45
|
+
FlowComponent.__init__(self, loop=loop, job=job, stat=stat, **kwargs)
|
46
|
+
|
47
|
+
async def start(self, **kwargs) -> bool:
|
48
|
+
"""Prepare component for execution."""
|
49
|
+
await super(IcimsFolderCopy, self).start(**kwargs)
|
50
|
+
return True
|
51
|
+
|
52
|
+
async def run(self):
|
53
|
+
"""Execute the folder copying process based on database results using Pandas."""
|
54
|
+
try:
|
55
|
+
db = pg(dsn=self.dsn, timeout=self.timeout)
|
56
|
+
except ProviderError as e:
|
57
|
+
raise ComponentError(f"Error connecting to database: {e}")
|
58
|
+
|
59
|
+
try:
|
60
|
+
# Establish connection and assign it to _connection
|
61
|
+
self._connection = await db.connection()
|
62
|
+
|
63
|
+
if not self._connection.is_connected():
|
64
|
+
raise ComponentError(f"DB Error: driver {self.driver} is not connected.")
|
65
|
+
|
66
|
+
query_to_run = ""
|
67
|
+
|
68
|
+
if self.by_name:
|
69
|
+
associate_query = (
|
70
|
+
f"SELECT associate_id, full_name FROM icims.forms_list "
|
71
|
+
f"WHERE full_name LIKE '%{self.by_name}%' "
|
72
|
+
f"GROUP BY associate_id, full_name"
|
73
|
+
)
|
74
|
+
query_to_run = associate_query
|
75
|
+
logging.info(f"Running query: {query_to_run}")
|
76
|
+
associate_result = await self._connection.query(associate_query)
|
77
|
+
|
78
|
+
elif self.by_associate_id:
|
79
|
+
associate_query = (
|
80
|
+
f"SELECT associate_id, full_name FROM icims.forms_list "
|
81
|
+
f"WHERE associate_id = '{self.by_associate_id}' "
|
82
|
+
f"GROUP BY associate_id, full_name"
|
83
|
+
)
|
84
|
+
query_to_run = associate_query
|
85
|
+
logging.info(f"Running query: {query_to_run}")
|
86
|
+
associate_result = await self._connection.query(associate_query)
|
87
|
+
|
88
|
+
elif hasattr(self, "query"):
|
89
|
+
# Custom query provided
|
90
|
+
query_to_run = self.query
|
91
|
+
logging.info(f"Running custom query: {query_to_run}")
|
92
|
+
associate_result = await self._connection.query(query_to_run)
|
93
|
+
else:
|
94
|
+
raise ComponentError("Either by_name, by_associate_id, or a custom query is required for this operation.")
|
95
|
+
|
96
|
+
# Flatten and filter out None
|
97
|
+
associate_result = [item for sublist in associate_result if sublist is not None for item in sublist]
|
98
|
+
|
99
|
+
# Dynamically extract field names and values
|
100
|
+
data = [{k: v for k, v in row.items()} for row in associate_result]
|
101
|
+
|
102
|
+
# Convert to DataFrame
|
103
|
+
df = pd.DataFrame(data)
|
104
|
+
|
105
|
+
# Handle missing values
|
106
|
+
df.dropna(subset=["associate_id"], inplace=True)
|
107
|
+
|
108
|
+
# Extract folder codes as a list
|
109
|
+
folder_codes = df["associate_id"].tolist()
|
110
|
+
|
111
|
+
# Copy folders
|
112
|
+
copied_count = self.copy_folders(folder_codes)
|
113
|
+
|
114
|
+
# Check if no folders were copied
|
115
|
+
if copied_count == 0:
|
116
|
+
raise ComponentError("No folders were copied. Please check the source or the query results.")
|
117
|
+
|
118
|
+
except ProviderError as e:
|
119
|
+
raise ComponentError(f"Error querying database: {e}") from e
|
120
|
+
except Exception as e:
|
121
|
+
self._logger.error(e)
|
122
|
+
raise
|
123
|
+
return True
|
124
|
+
|
125
|
+
|
126
|
+
def copy_folders(self, folder_codes):
|
127
|
+
"""Copy folders and handle missing folders gracefully."""
|
128
|
+
copied_count = 0
|
129
|
+
failed_folders = []
|
130
|
+
|
131
|
+
for code in folder_codes:
|
132
|
+
src_folder = os.path.join(self.source_directory, code)
|
133
|
+
dest_folder = os.path.join(self.destination_directory, code)
|
134
|
+
|
135
|
+
if os.path.exists(src_folder):
|
136
|
+
if not os.path.exists(dest_folder):
|
137
|
+
os.makedirs(dest_folder)
|
138
|
+
|
139
|
+
for root, dirs, files in os.walk(src_folder):
|
140
|
+
for file in files:
|
141
|
+
src_file = os.path.join(root, file)
|
142
|
+
rel_path = os.path.relpath(src_file, src_folder)
|
143
|
+
dest_file = os.path.join(dest_folder, rel_path)
|
144
|
+
|
145
|
+
os.makedirs(os.path.dirname(dest_file), exist_ok=True)
|
146
|
+
|
147
|
+
try:
|
148
|
+
shutil.copy2(src_file, dest_file)
|
149
|
+
except shutil.Error as e:
|
150
|
+
self._logger.error(f"Error copying file {src_file}: {e}")
|
151
|
+
copied_count += 1
|
152
|
+
else:
|
153
|
+
failed_folders.append(code)
|
154
|
+
logging.warning(f"Folder {code} does not exist in the source directory.")
|
155
|
+
|
156
|
+
if failed_folders:
|
157
|
+
self._logger.error(f"Failed to find folders for the following associate_ids: {failed_folders}")
|
158
|
+
|
159
|
+
logging.info(f"Total folders copied or merged: {copied_count} out of {len(folder_codes)} requested.")
|
160
|
+
return copied_count
|
161
|
+
|
162
|
+
async def close(self, connection=None):
|
163
|
+
"""Close the database connection."""
|
164
|
+
if not connection:
|
165
|
+
connection = getattr(self, '_connection', None) # Safely get the connection
|
166
|
+
try:
|
167
|
+
if connection is not None:
|
168
|
+
await connection.close()
|
169
|
+
logging.info("Database connection closed successfully.")
|
170
|
+
else:
|
171
|
+
logging.warning("No active connection to close.")
|
172
|
+
except Exception as err:
|
173
|
+
self._logger.error(f"Error closing database connection: {err}")
|
@@ -0,0 +1,233 @@
|
|
1
|
+
import asyncio
|
2
|
+
from collections.abc import Callable
|
3
|
+
from contextlib import AsyncExitStack
|
4
|
+
from typing import Any
|
5
|
+
from PIL import Image, UnidentifiedImageError
|
6
|
+
import pyheif
|
7
|
+
from pillow_heif import register_heif_opener
|
8
|
+
from io import BytesIO
|
9
|
+
import filetype
|
10
|
+
from ..flow import FlowComponent
|
11
|
+
from ...exceptions import (
|
12
|
+
ConfigError,
|
13
|
+
ComponentError,
|
14
|
+
FileError
|
15
|
+
)
|
16
|
+
# Parrot Image Processing plug-ins
|
17
|
+
from parrot.interfaces.images.plugins import PLUGINS, ImagePlugin
|
18
|
+
|
19
|
+
register_heif_opener() # HEIF support
|
20
|
+
|
21
|
+
class ImageFeatures(FlowComponent):
|
22
|
+
"""
|
23
|
+
ImageFeatures is a component for extracting image features.
|
24
|
+
It extends the FlowComponent class and implements a Plugin system for various image processing tasks.
|
25
|
+
|
26
|
+
Args:
|
27
|
+
*args: Variable length argument list.
|
28
|
+
**kwargs: Arbitrary keyword arguments.
|
29
|
+
|
30
|
+
Attributes:
|
31
|
+
_model_name (str): The name of the model used for feature extraction.
|
32
|
+
"""
|
33
|
+
def __init__(
|
34
|
+
self,
|
35
|
+
loop: asyncio.AbstractEventLoop = None,
|
36
|
+
job: Callable = None,
|
37
|
+
stat: Callable = None,
|
38
|
+
**kwargs,
|
39
|
+
):
|
40
|
+
self._plugins_list: list = kwargs.get("plugins")
|
41
|
+
self._plugins: list = []
|
42
|
+
self._semaphore = asyncio.Semaphore(8) # limit GPU tasks
|
43
|
+
if not self._plugins_list:
|
44
|
+
raise ConfigError("Plugins list is required.")
|
45
|
+
super().__init__(loop=loop, job=job, stat=stat, **kwargs)
|
46
|
+
|
47
|
+
async def start(self, **kwargs):
|
48
|
+
"""
|
49
|
+
start.
|
50
|
+
|
51
|
+
Initialize Task.
|
52
|
+
"""
|
53
|
+
if self.previous:
|
54
|
+
self.data = self.input
|
55
|
+
if self.data_column not in self.data.columns:
|
56
|
+
raise ValueError(
|
57
|
+
f'Data column {self.data_column} not found in data.'
|
58
|
+
)
|
59
|
+
# Check plugin Names:
|
60
|
+
plugins = []
|
61
|
+
for n in self._plugins_list:
|
62
|
+
# n is a dictionary with the plugin name and args
|
63
|
+
if isinstance(n, dict):
|
64
|
+
name = list(n.keys())[0].lower()
|
65
|
+
args = n[name]
|
66
|
+
plugin = PLUGINS.get(name)
|
67
|
+
if not plugin:
|
68
|
+
raise ConfigError(
|
69
|
+
f'Plugin {n} not found in available plugins.'
|
70
|
+
)
|
71
|
+
if not issubclass(plugin, ImagePlugin):
|
72
|
+
raise ConfigError(
|
73
|
+
f'Plugin {n} is not a subclass of ImagePlugin.'
|
74
|
+
)
|
75
|
+
if not args:
|
76
|
+
args = {}
|
77
|
+
if not isinstance(args, dict):
|
78
|
+
raise ConfigError(
|
79
|
+
f'Plugin {n} args must be a dictionary.'
|
80
|
+
)
|
81
|
+
plugins.append(
|
82
|
+
{
|
83
|
+
"plugin": plugin,
|
84
|
+
"args": args
|
85
|
+
}
|
86
|
+
)
|
87
|
+
self._plugins = plugins
|
88
|
+
|
89
|
+
async def close(self):
|
90
|
+
pass
|
91
|
+
|
92
|
+
def get_bio(self, bio: Any) -> BytesIO:
|
93
|
+
"""Return a BytesIO object for a payload."""
|
94
|
+
if isinstance(bio, Image.Image):
|
95
|
+
return bio
|
96
|
+
if isinstance(bio, bytes):
|
97
|
+
bio = BytesIO(bio)
|
98
|
+
if isinstance(bio, str):
|
99
|
+
bio = BytesIO(bio.encode('utf-8'))
|
100
|
+
if isinstance(bio, BytesIO):
|
101
|
+
return bio
|
102
|
+
if hasattr(bio, "read"):
|
103
|
+
bio = BytesIO(bio.read())
|
104
|
+
if hasattr(bio, "getvalue"):
|
105
|
+
bio = BytesIO(bio.getvalue())
|
106
|
+
else:
|
107
|
+
raise TypeError(
|
108
|
+
f"Expected bytes, str, or BytesIO, got {type(bio)}"
|
109
|
+
)
|
110
|
+
if not bio.readable():
|
111
|
+
raise TypeError("BytesIO is not readable.")
|
112
|
+
bio.seek(0)
|
113
|
+
return bio
|
114
|
+
|
115
|
+
async def _run_plugin(self, plugin, img: Image.Image, heif: Any = None, **kwargs):
|
116
|
+
"""
|
117
|
+
Call plugin.analyze(); transparently await if it's an async def.
|
118
|
+
"""
|
119
|
+
if asyncio.iscoroutinefunction(plugin.analyze):
|
120
|
+
return await plugin.analyze(img, heif=heif, **kwargs)
|
121
|
+
return plugin.analyze(img, heif)
|
122
|
+
|
123
|
+
async def run(self):
|
124
|
+
"""
|
125
|
+
run.
|
126
|
+
|
127
|
+
Execute the plugin List to extract image features.
|
128
|
+
"""
|
129
|
+
# Iterate over all plugins (create one single instance of each plugin):
|
130
|
+
_plugins = []
|
131
|
+
async with AsyncExitStack() as stack:
|
132
|
+
for spec in self._plugins:
|
133
|
+
cls, args = spec["plugin"], spec["args"]
|
134
|
+
if cls.column_name not in self.data.columns:
|
135
|
+
# Create a new column in the DataFrame for the plugin's results
|
136
|
+
self.data[cls.column_name] = None
|
137
|
+
plugin = cls(**args)
|
138
|
+
try:
|
139
|
+
await plugin.start()
|
140
|
+
except Exception as e:
|
141
|
+
raise ComponentError(
|
142
|
+
f"Error starting plugin {plugin}: {str(e)}"
|
143
|
+
) from e
|
144
|
+
# If the plugin implements .open() returning an async‑context
|
145
|
+
if hasattr(plugin, "open"):
|
146
|
+
plugin = await stack.enter_async_context(plugin) # ⇦ one‑time open
|
147
|
+
_plugins.append(plugin)
|
148
|
+
|
149
|
+
# Iterate over all rows in the DataFrame:
|
150
|
+
# - Convert the image to a PIL Image
|
151
|
+
# - Call the plugin's analyze method
|
152
|
+
# - Store the result in the DataFrame
|
153
|
+
# - Use a semaphore to limit concurrent tasks
|
154
|
+
# - Use asyncio.gather to run the tasks concurrently
|
155
|
+
# - Use a memoryview to avoid copying the image data
|
156
|
+
# Convert BytesIO → bytes/PIL *one* time per row.
|
157
|
+
async def process_row(idx, row):
|
158
|
+
bio = row[self.data_column]
|
159
|
+
if not bio:
|
160
|
+
return
|
161
|
+
async with self._semaphore:
|
162
|
+
try:
|
163
|
+
try:
|
164
|
+
bio = self.get_bio(bio)
|
165
|
+
except Exception as e:
|
166
|
+
self._logger.error(
|
167
|
+
f"Error getting BytesIO from {bio}: {e}"
|
168
|
+
)
|
169
|
+
return
|
170
|
+
kind = filetype.guess(bio)
|
171
|
+
heic = None
|
172
|
+
if kind == 'image/heic':
|
173
|
+
try:
|
174
|
+
heic = pyheif.read_heif(bio)
|
175
|
+
except Exception as e:
|
176
|
+
self._logger.error(
|
177
|
+
"Unable to parse Apple Heic Photo"
|
178
|
+
)
|
179
|
+
return
|
180
|
+
if isinstance(bio, Image.Image):
|
181
|
+
image = bio
|
182
|
+
elif kind == 'image/heic':
|
183
|
+
image = Image.frombytes(
|
184
|
+
mode=heic.mode,
|
185
|
+
size=heic.size,
|
186
|
+
data=heic.data
|
187
|
+
)
|
188
|
+
else:
|
189
|
+
# Decode the image once
|
190
|
+
try:
|
191
|
+
image = Image.open(bio)
|
192
|
+
except UnidentifiedImageError:
|
193
|
+
raise FileError(
|
194
|
+
f"PIL cannot identify image file. MIME: {kind.mime}"
|
195
|
+
)
|
196
|
+
# Results from all plugins for this row
|
197
|
+
for plugin in _plugins:
|
198
|
+
result = await self._run_plugin(plugin, image, heic)
|
199
|
+
self.data.at[idx, plugin.column_name] = result
|
200
|
+
except FileError as e:
|
201
|
+
self._logger.error(
|
202
|
+
f"Image Error on {row}: {e}"
|
203
|
+
)
|
204
|
+
return
|
205
|
+
except Exception as e:
|
206
|
+
self._logger.error(
|
207
|
+
f'Error processing image at index {idx}: {e}'
|
208
|
+
)
|
209
|
+
return
|
210
|
+
# Kick off tasks – DataFrame scanned exactly once
|
211
|
+
tasks = [
|
212
|
+
process_row(idx, row)
|
213
|
+
for idx, row in self.data.iterrows()
|
214
|
+
]
|
215
|
+
try:
|
216
|
+
await asyncio.gather(*tasks)
|
217
|
+
self._print_data_(self.data, ':: Image Features ::')
|
218
|
+
self._result = self.data
|
219
|
+
return self._result
|
220
|
+
except Exception as e:
|
221
|
+
raise ComponentError(
|
222
|
+
f"Error in ImageFeatures run: {str(e)}"
|
223
|
+
) from e
|
224
|
+
finally:
|
225
|
+
# Dispose of all plugins
|
226
|
+
for plugin in _plugins:
|
227
|
+
if hasattr(plugin, "dispose"):
|
228
|
+
try:
|
229
|
+
await plugin.dispose()
|
230
|
+
except Exception as e:
|
231
|
+
self._logger.error(
|
232
|
+
f"Error disposing plugin {plugin}: {str(e)}"
|
233
|
+
)
|
@@ -0,0 +1,251 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
from typing import Any
|
3
|
+
import threading
|
4
|
+
from threading import Semaphore
|
5
|
+
import asyncio
|
6
|
+
from collections.abc import Callable
|
7
|
+
from navconfig.logging import logging
|
8
|
+
from asyncdb.exceptions import NoDataFound, ProviderError
|
9
|
+
from ..exceptions import (
|
10
|
+
ComponentError,
|
11
|
+
NotSupported,
|
12
|
+
DataNotFound,
|
13
|
+
FileNotFound
|
14
|
+
)
|
15
|
+
|
16
|
+
from .flow import FlowComponent
|
17
|
+
from ..interfaces.log import SkipErrors
|
18
|
+
|
19
|
+
|
20
|
+
class ThreadJob(threading.Thread):
|
21
|
+
def __init__(self, job: Any, step_name: str, semaphore: Semaphore):
|
22
|
+
super().__init__()
|
23
|
+
self.step_name = step_name
|
24
|
+
self.job = job
|
25
|
+
self.exc = None
|
26
|
+
self.result = None
|
27
|
+
self.semaphore = semaphore
|
28
|
+
|
29
|
+
def run(self):
|
30
|
+
try:
|
31
|
+
asyncio.run(self.execute_job(self.job, self.step_name))
|
32
|
+
except Exception as ex:
|
33
|
+
self.exc = ex
|
34
|
+
finally:
|
35
|
+
# Release semaphore
|
36
|
+
self.semaphore.release()
|
37
|
+
|
38
|
+
async def execute_job(self, job: Any, step_name: str):
|
39
|
+
start = getattr(job, "start", None)
|
40
|
+
if callable(start):
|
41
|
+
try:
|
42
|
+
if asyncio.iscoroutinefunction(start):
|
43
|
+
st = await job.start()
|
44
|
+
else:
|
45
|
+
st = job.start()
|
46
|
+
self._logger.debug(f"STARTED: {st}")
|
47
|
+
except (NoDataFound, DataNotFound) as err:
|
48
|
+
raise DataNotFound(f"{err!s}") from err
|
49
|
+
except (ProviderError, ComponentError, NotSupported) as err:
|
50
|
+
raise ComponentError(
|
51
|
+
f"Error running Start Function on {step_name}, error: {err}"
|
52
|
+
) from err
|
53
|
+
else:
|
54
|
+
raise ComponentError(f"Error running Function on {step_name}")
|
55
|
+
try:
|
56
|
+
run = getattr(job, "run", None)
|
57
|
+
if asyncio.iscoroutinefunction(run):
|
58
|
+
self.result = await job.run()
|
59
|
+
else:
|
60
|
+
self.result = job.run()
|
61
|
+
return self.result
|
62
|
+
except (NoDataFound, DataNotFound) as err:
|
63
|
+
raise DataNotFound(f"{err!s}") from err
|
64
|
+
except (ProviderError, ComponentError, NotSupported) as err:
|
65
|
+
raise NotSupported(
|
66
|
+
f"Error running Component {step_name}, error: {err}"
|
67
|
+
) from err
|
68
|
+
except Exception as err:
|
69
|
+
self._logger.exception(err, exc_info=True)
|
70
|
+
raise ComponentError(
|
71
|
+
f"Iterator Error on {step_name}, error: {err}"
|
72
|
+
) from err
|
73
|
+
finally:
|
74
|
+
try:
|
75
|
+
close = getattr(job, "close", None)
|
76
|
+
if asyncio.iscoroutinefunction(close):
|
77
|
+
await job.close()
|
78
|
+
else:
|
79
|
+
job.close()
|
80
|
+
except Exception:
|
81
|
+
pass
|
82
|
+
|
83
|
+
|
84
|
+
class IteratorBase(FlowComponent):
|
85
|
+
"""
|
86
|
+
IteratorBase
|
87
|
+
|
88
|
+
Overview
|
89
|
+
|
90
|
+
The IteratorBase class is an abstract component for handling iterative tasks. It extends the FlowComponent class
|
91
|
+
and provides methods for starting tasks, retrieving steps, and executing jobs asynchronously.
|
92
|
+
|
93
|
+
.. table:: Properties
|
94
|
+
:widths: auto
|
95
|
+
|
96
|
+
+-----------------+----------+-------------------------------------------------------------------------------+
|
97
|
+
| Name | Required | Description |
|
98
|
+
+-----------------+----------+-------------------------------------------------------------------------------+
|
99
|
+
| iterate | No | Boolean flag indicating if the component should |
|
100
|
+
| | | iterate the components or return the list, defaults to False. |
|
101
|
+
+-----------------+----------+-------------------------------------------------------------------------------+
|
102
|
+
|
103
|
+
The methods in this class manage the execution of iterative tasks, including initialization, step retrieval,
|
104
|
+
job creation, and asynchronous execution.
|
105
|
+
|
106
|
+
"""
|
107
|
+
def __init__(
|
108
|
+
self,
|
109
|
+
loop: asyncio.AbstractEventLoop = None,
|
110
|
+
job: Callable = None,
|
111
|
+
stat: Callable = None,
|
112
|
+
**kwargs,
|
113
|
+
):
|
114
|
+
self.iterate: bool = False
|
115
|
+
self._iterator: bool = True
|
116
|
+
self._conditions: dict = {}
|
117
|
+
super(IteratorBase, self).__init__(loop=loop, job=job, stat=stat, **kwargs)
|
118
|
+
|
119
|
+
async def start(self, **kwargs):
|
120
|
+
"""
|
121
|
+
start.
|
122
|
+
|
123
|
+
Initialize (if needed) a task
|
124
|
+
"""
|
125
|
+
if self.previous:
|
126
|
+
self.data = self.input
|
127
|
+
return True
|
128
|
+
|
129
|
+
def get_step(self):
|
130
|
+
params = None
|
131
|
+
try:
|
132
|
+
if not self._TaskPile:
|
133
|
+
raise ComponentError("No Components in TaskPile")
|
134
|
+
step, idx = self._TaskPile.nextStep(self.StepName)
|
135
|
+
params = step.params()
|
136
|
+
try:
|
137
|
+
if params["conditions"]:
|
138
|
+
self._conditions[step.name] = params["conditions"]
|
139
|
+
except KeyError:
|
140
|
+
pass
|
141
|
+
params["ENV"] = self._environment
|
142
|
+
# program
|
143
|
+
if hasattr(self, "_program"):
|
144
|
+
params["_program"] = self._program
|
145
|
+
# params
|
146
|
+
params["params"] = self._params
|
147
|
+
# parameters
|
148
|
+
params["parameters"] = self._parameters
|
149
|
+
# useful to change variables in set var components
|
150
|
+
params["_vars"] = self._vars
|
151
|
+
# variables dictionary
|
152
|
+
params["variables"] = self._variables
|
153
|
+
params["_args"] = self._args
|
154
|
+
# argument list for components (or tasks) that need argument lists
|
155
|
+
params["arguments"] = self._arguments
|
156
|
+
# for components with conditions, we can add more conditions
|
157
|
+
conditions = params.get("conditions", {})
|
158
|
+
step_conds = self._conditions.get(step.name, {})
|
159
|
+
if self.conditions is not None:
|
160
|
+
step_conds = {**self.conditions, **step_conds}
|
161
|
+
params["conditions"] = {**conditions, **step_conds}
|
162
|
+
# attributes only usable component-only
|
163
|
+
params["attributes"] = self._attributes
|
164
|
+
# the current Pile of components
|
165
|
+
params["TaskPile"] = self._TaskPile
|
166
|
+
# params['TaskName'] = step_name
|
167
|
+
params["debug"] = self._debug
|
168
|
+
params["argparser"] = self._argparser
|
169
|
+
# the current in-memory connector
|
170
|
+
params["memory"] = self._memory
|
171
|
+
target = step.component
|
172
|
+
# remove this element from tasks, doesn't need to run again
|
173
|
+
self._TaskPile.delStep(idx)
|
174
|
+
# return target and params
|
175
|
+
return [step, target, params]
|
176
|
+
finally:
|
177
|
+
pass
|
178
|
+
|
179
|
+
def get_job(self, target, **params):
|
180
|
+
job = None
|
181
|
+
try:
|
182
|
+
job = target(job=self, loop=self._loop, stat=self.stat, **params)
|
183
|
+
return job
|
184
|
+
except Exception as err:
|
185
|
+
raise ComponentError(
|
186
|
+
f"Generic Component Error on {target}, error: {err}"
|
187
|
+
) from err
|
188
|
+
|
189
|
+
async def async_job(self, job, step_name):
|
190
|
+
start = getattr(job, "start", None)
|
191
|
+
if callable(start):
|
192
|
+
try:
|
193
|
+
if asyncio.iscoroutinefunction(start):
|
194
|
+
st = await job.start()
|
195
|
+
else:
|
196
|
+
st = job.start()
|
197
|
+
self._logger.debug(f"STARTED: {st}")
|
198
|
+
except (NoDataFound, DataNotFound) as err:
|
199
|
+
raise DataNotFound(f"{err!s}") from err
|
200
|
+
except (ProviderError, ComponentError, NotSupported) as err:
|
201
|
+
raise ComponentError(
|
202
|
+
f"Error running Start Function on {step_name}, error: {err}"
|
203
|
+
) from err
|
204
|
+
else:
|
205
|
+
raise ComponentError(
|
206
|
+
f"Error running Function on {step_name}"
|
207
|
+
)
|
208
|
+
try:
|
209
|
+
run = getattr(job, "run", None)
|
210
|
+
if asyncio.iscoroutinefunction(run):
|
211
|
+
result = await job.run()
|
212
|
+
else:
|
213
|
+
result = job.run()
|
214
|
+
self._result = result
|
215
|
+
return self._result
|
216
|
+
except (NoDataFound, DataNotFound, FileNotFound) as err:
|
217
|
+
try:
|
218
|
+
if job.skipError == SkipErrors.SKIP:
|
219
|
+
self._logger.warning(
|
220
|
+
f"Component {job!s} was Skipped, error: {err}"
|
221
|
+
)
|
222
|
+
self._result = self.data
|
223
|
+
return self._result
|
224
|
+
elif job.skipError == SkipErrors.ENFORCE:
|
225
|
+
# Enforcing to Raise Error:
|
226
|
+
raise DataNotFound(f"{err!s}") from err
|
227
|
+
else:
|
228
|
+
# Log Only
|
229
|
+
self._logger.error(
|
230
|
+
f"Component {job!s} was Skipped, error: {err}"
|
231
|
+
)
|
232
|
+
except AttributeError:
|
233
|
+
raise DataNotFound(f"{err!s}") from err
|
234
|
+
except (ProviderError, ComponentError, NotSupported) as err:
|
235
|
+
raise NotSupported(
|
236
|
+
f"Error running Component {step_name}, error: {err}"
|
237
|
+
) from err
|
238
|
+
except Exception as err:
|
239
|
+
self._logger.exception(err, exc_info=True)
|
240
|
+
raise ComponentError(
|
241
|
+
f"Iterator Error on {step_name}, error: {err}"
|
242
|
+
) from err
|
243
|
+
finally:
|
244
|
+
try:
|
245
|
+
close = getattr(job, "close", None)
|
246
|
+
if asyncio.iscoroutinefunction(close):
|
247
|
+
await job.close()
|
248
|
+
else:
|
249
|
+
job.close()
|
250
|
+
except Exception:
|
251
|
+
pass
|