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,362 @@
|
|
1
|
+
import builtins
|
2
|
+
import traceback
|
3
|
+
## Notify System
|
4
|
+
from notify import Notify
|
5
|
+
from notify.providers.email import Email
|
6
|
+
from notify.providers.slack import Slack
|
7
|
+
from notify.providers.teams import Teams
|
8
|
+
from notify.models import (
|
9
|
+
Actor,
|
10
|
+
Chat,
|
11
|
+
Channel,
|
12
|
+
TeamsCard,
|
13
|
+
TeamsChannel
|
14
|
+
)
|
15
|
+
import querysource.utils.functions as qsfunctions
|
16
|
+
from ....conf import (
|
17
|
+
EVENT_CHAT_ID,
|
18
|
+
EVENT_CHAT_BOT,
|
19
|
+
DEFAULT_RECIPIENT,
|
20
|
+
NOTIFY_ON_ERROR,
|
21
|
+
EMAIL_USERNAME,
|
22
|
+
EMAIL_PASSWORD,
|
23
|
+
EMAIL_PORT,
|
24
|
+
EMAIL_HOST,
|
25
|
+
ENVIRONMENT,
|
26
|
+
SLACK_DEFAULT_CHANNEL,
|
27
|
+
SLACK_DEFAULT_CHANNEL_NAME,
|
28
|
+
MS_TEAMS_DEFAULT_TEAMS_ID,
|
29
|
+
MS_TEAMS_DEFAULT_CHANNEL_ID,
|
30
|
+
MS_TEAMS_DEFAULT_CHANNEL_NAME,
|
31
|
+
)
|
32
|
+
from ....utils import cPrint, check_empty
|
33
|
+
from ....exceptions import ConfigError, EventError
|
34
|
+
from . import functions as alertfunc
|
35
|
+
from . import colfunctions as colfunc
|
36
|
+
from ..abstract import AbstractEvent
|
37
|
+
from ....interfaces.notification import Notification
|
38
|
+
|
39
|
+
|
40
|
+
def recursive_lookup(d, target_key):
|
41
|
+
"""
|
42
|
+
Recursively finds the first dictionary that contains a given key inside a nested dictionary.
|
43
|
+
|
44
|
+
:param d: Dictionary to search
|
45
|
+
:param target_key: Key to find ("result" by default)
|
46
|
+
:return: The dictionary containing the key, or None if not found
|
47
|
+
"""
|
48
|
+
"""
|
49
|
+
Recursively finds the first dictionary that contains the given key.
|
50
|
+
|
51
|
+
:param d: Dictionary to search
|
52
|
+
:param target_key: Key to find dynamically (e.g., "result" or any other key)
|
53
|
+
:return: The dictionary containing the key, or None if not found
|
54
|
+
"""
|
55
|
+
if isinstance(d, dict):
|
56
|
+
if target_key in d:
|
57
|
+
return d # Return the entire dictionary that contains the target key
|
58
|
+
for _, value in d.items():
|
59
|
+
if isinstance(value, dict): # Recurse into nested dictionaries
|
60
|
+
found = recursive_lookup(value, target_key)
|
61
|
+
if found is not None:
|
62
|
+
return found
|
63
|
+
return None
|
64
|
+
|
65
|
+
|
66
|
+
class Alert(Notification, AbstractEvent):
|
67
|
+
def __init__(self, *args, **kwargs):
|
68
|
+
# adding checks:
|
69
|
+
self.system_checks: list = kwargs.pop("system_checks", [])
|
70
|
+
self.result_checks: list = kwargs.pop("result_checks", [])
|
71
|
+
self.column_checks: list = kwargs.pop("column_checks", [])
|
72
|
+
self.stat_checks: list = kwargs.pop("stat_checks", [])
|
73
|
+
self._channel: str = kwargs.pop("channel", NOTIFY_ON_ERROR)
|
74
|
+
super().__init__(*args, **kwargs)
|
75
|
+
|
76
|
+
async def __call__(self, *args, **kwargs):
|
77
|
+
task = kwargs.get("task", None)
|
78
|
+
program = task.getProgram()
|
79
|
+
task_name = f"{program}.{task.taskname}"
|
80
|
+
try:
|
81
|
+
stats = task.stats.to_json()
|
82
|
+
except AttributeError:
|
83
|
+
stats = None
|
84
|
+
|
85
|
+
df = task.resultset()
|
86
|
+
|
87
|
+
errors = []
|
88
|
+
|
89
|
+
if self.system_checks:
|
90
|
+
rst = await self.process_checks(self.system_checks, stats, task_name)
|
91
|
+
if rst:
|
92
|
+
errors += rst
|
93
|
+
|
94
|
+
if self.stat_checks:
|
95
|
+
if check_empty(stats):
|
96
|
+
self._logger.warning(f"No statistics found for the task {task_name}")
|
97
|
+
return None
|
98
|
+
steps = stats.get("steps", [])
|
99
|
+
rst = await self.stats_checks(self.stat_checks, stats, steps, task_name)
|
100
|
+
if rst:
|
101
|
+
errors += rst
|
102
|
+
|
103
|
+
if self.result_checks:
|
104
|
+
if check_empty(df):
|
105
|
+
return None
|
106
|
+
data = {
|
107
|
+
"num_rows": len(df),
|
108
|
+
"num_columns": df.shape[1],
|
109
|
+
"shape": df.shape,
|
110
|
+
"columns": df.columns.values.tolist()
|
111
|
+
}
|
112
|
+
rst = await self.process_checks(self.result_checks, data, task_name)
|
113
|
+
if rst:
|
114
|
+
errors += rst
|
115
|
+
|
116
|
+
if self.column_checks:
|
117
|
+
# Get the summary statistics of the DataFrame
|
118
|
+
desc = df.describe()
|
119
|
+
err = []
|
120
|
+
for check in self.column_checks:
|
121
|
+
fname, colname, fn, params = self.get_pandas_function(check)
|
122
|
+
# Check if the column exists in the DataFrame
|
123
|
+
if colname not in df.columns:
|
124
|
+
self._logger.warning(f"Column {colname} not found in DataFrame.")
|
125
|
+
continue
|
126
|
+
# execute the function:
|
127
|
+
self._logger.debug(f"Exec {fname} with args {params}")
|
128
|
+
actual_value, result = fn(df, desc, colname, **params)
|
129
|
+
if result is False:
|
130
|
+
# threshold was reached
|
131
|
+
self._logger.error(
|
132
|
+
f"{task_name}: Threshold for {fname} was reached with: {actual_value} on {colname}"
|
133
|
+
)
|
134
|
+
err.append(
|
135
|
+
{
|
136
|
+
"function": fname,
|
137
|
+
"column": colname,
|
138
|
+
"value": actual_value,
|
139
|
+
"expected": params.get("value", "Unknown")
|
140
|
+
}
|
141
|
+
)
|
142
|
+
|
143
|
+
if errors:
|
144
|
+
# TODO: send a notification about threshold violation.
|
145
|
+
await self.notify(task_name, program, errors, **kwargs)
|
146
|
+
|
147
|
+
def get_pandas_function(self, payload: dict):
|
148
|
+
fname = list(payload.keys())[0]
|
149
|
+
func = None
|
150
|
+
try:
|
151
|
+
params = payload[fname]
|
152
|
+
except KeyError:
|
153
|
+
params = {}
|
154
|
+
# Extract the column name from the parameters
|
155
|
+
col_name = params.pop("column")
|
156
|
+
try:
|
157
|
+
func = getattr(colfunc, fname)
|
158
|
+
except AttributeError:
|
159
|
+
self._logger.warning(f"Function {fname} does not exist on Alert System")
|
160
|
+
return fname, col_name, func, params
|
161
|
+
|
162
|
+
def get_function(self, payload: dict):
|
163
|
+
"""Get the function name, function object and parameters from the payload."""
|
164
|
+
fname = list(payload.keys())[0]
|
165
|
+
try:
|
166
|
+
params = payload[fname]
|
167
|
+
except KeyError:
|
168
|
+
params = {}
|
169
|
+
try:
|
170
|
+
func = getattr(alertfunc, fname)
|
171
|
+
except AttributeError:
|
172
|
+
try:
|
173
|
+
func = getattr(qsfunctions, fname)
|
174
|
+
except AttributeError:
|
175
|
+
try:
|
176
|
+
func = globals()[fname]
|
177
|
+
except (KeyError, AttributeError):
|
178
|
+
try:
|
179
|
+
func = getattr(builtins, fname)
|
180
|
+
except AttributeError:
|
181
|
+
func = None
|
182
|
+
if not func:
|
183
|
+
raise ConfigError(
|
184
|
+
f"Function {fname} doesn't exist on Flowtask."
|
185
|
+
)
|
186
|
+
return fname, func, params
|
187
|
+
|
188
|
+
def exec_function(self, fname, func, data, **kwargs):
|
189
|
+
self._logger.debug(f"Exec {fname} with args {kwargs}")
|
190
|
+
try:
|
191
|
+
return func(data, **kwargs)
|
192
|
+
except (TypeError, ValueError) as err:
|
193
|
+
self._logger.exception(str(err), exc_info=True, stack_info=True)
|
194
|
+
traceback.print_exc()
|
195
|
+
return None
|
196
|
+
|
197
|
+
async def process_checks(self, checks, data, task_name):
|
198
|
+
errors = []
|
199
|
+
for check in checks:
|
200
|
+
fname, fn, params = self.get_function(check)
|
201
|
+
colname, value, result = self.exec_function(fname, fn, data, **params)
|
202
|
+
if result is False:
|
203
|
+
# threshold was reached
|
204
|
+
self._logger.error(
|
205
|
+
f"{task_name}: Threshold was reached for {fname} {colname} = {value}"
|
206
|
+
)
|
207
|
+
errors.append(
|
208
|
+
{
|
209
|
+
"function": fname,
|
210
|
+
"column": colname,
|
211
|
+
"value": value,
|
212
|
+
"expected": params.get("value", "Unknown")
|
213
|
+
}
|
214
|
+
)
|
215
|
+
return errors
|
216
|
+
|
217
|
+
async def stats_checks(self, checks, stats: dict, steps: list, task_name: str):
|
218
|
+
errors = []
|
219
|
+
for fn in checks:
|
220
|
+
result = False
|
221
|
+
fname, fn, params = self.get_function(fn)
|
222
|
+
if "column" in params:
|
223
|
+
# extract the column from stats:
|
224
|
+
current_value = stats.get(params["column"], None)
|
225
|
+
if current_value is None:
|
226
|
+
self._logger.warning(f"Column {params['column']} not found in stats.")
|
227
|
+
continue
|
228
|
+
current_value = stats
|
229
|
+
elif 'component' in params:
|
230
|
+
component_name = params.pop('component')
|
231
|
+
component_dict = stats['steps'].get(component_name, {})
|
232
|
+
if component_dict is None:
|
233
|
+
self._logger.warning(f"Component {component_name} not found in stats.")
|
234
|
+
continue
|
235
|
+
if not params:
|
236
|
+
self._logger.warning(f"No key provided after 'component' for {component_name}.")
|
237
|
+
continue
|
238
|
+
dynamic_key, dyn_value = params.popitem()
|
239
|
+
# Recursively find the dictionary containing this key
|
240
|
+
result_dict = recursive_lookup(component_dict, dynamic_key)
|
241
|
+
if result_dict is None:
|
242
|
+
self._logger.warning(
|
243
|
+
f"No Dict containing '{dynamic_key}' found in {component_name}."
|
244
|
+
)
|
245
|
+
continue
|
246
|
+
current_value = result_dict
|
247
|
+
params = {
|
248
|
+
"column": dynamic_key,
|
249
|
+
"value": dyn_value
|
250
|
+
}
|
251
|
+
# Execute the query:
|
252
|
+
component, value, result = self.exec_function(fname, fn, current_value, **params)
|
253
|
+
if result is False:
|
254
|
+
# threshold was reached
|
255
|
+
self._logger.error(
|
256
|
+
f"{task_name}: Threshold for {fname} was reached with: {value} on {component}"
|
257
|
+
)
|
258
|
+
errors.append(
|
259
|
+
{
|
260
|
+
"function": fname,
|
261
|
+
"column": component,
|
262
|
+
"value": value,
|
263
|
+
"expected": params.get("value", "Unknown")
|
264
|
+
}
|
265
|
+
)
|
266
|
+
return errors
|
267
|
+
|
268
|
+
def getNotify(self, notify, **kwargs):
|
269
|
+
if notify == "telegram":
|
270
|
+
# defining the Default chat object:
|
271
|
+
recipient = Chat(**{"chat_id": EVENT_CHAT_ID, "chat_name": "Navigator"})
|
272
|
+
# send notifications to Telegram bot
|
273
|
+
args = {"bot_token": EVENT_CHAT_BOT, **kwargs}
|
274
|
+
ntf = Notify("telegram", **args)
|
275
|
+
elif notify == "slack":
|
276
|
+
recipient = Channel(
|
277
|
+
channel_id=SLACK_DEFAULT_CHANNEL,
|
278
|
+
channel_name=SLACK_DEFAULT_CHANNEL_NAME,
|
279
|
+
)
|
280
|
+
ntf = Slack()
|
281
|
+
elif notify == "email":
|
282
|
+
account = {
|
283
|
+
"host": EMAIL_HOST,
|
284
|
+
"port": EMAIL_PORT,
|
285
|
+
"username": EMAIL_USERNAME,
|
286
|
+
"password": EMAIL_PASSWORD,
|
287
|
+
**kwargs,
|
288
|
+
}
|
289
|
+
recipient = Actor(**DEFAULT_RECIPIENT)
|
290
|
+
ntf = Email(debug=True, **account)
|
291
|
+
elif notify == 'teams':
|
292
|
+
team_id = kwargs.pop("team_id", MS_TEAMS_DEFAULT_TEAMS_ID)
|
293
|
+
recipient = TeamsChannel(
|
294
|
+
name=MS_TEAMS_DEFAULT_CHANNEL_NAME,
|
295
|
+
team_id=team_id,
|
296
|
+
channel_id=MS_TEAMS_DEFAULT_CHANNEL_ID
|
297
|
+
)
|
298
|
+
ntf = Teams(
|
299
|
+
as_user=True,
|
300
|
+
team_id=team_id,
|
301
|
+
)
|
302
|
+
else:
|
303
|
+
# Any other Notify Provider:
|
304
|
+
recipient = Actor(**DEFAULT_RECIPIENT)
|
305
|
+
ntf = Notify(notify, **kwargs)
|
306
|
+
return [ntf, recipient]
|
307
|
+
|
308
|
+
async def notify(
|
309
|
+
self,
|
310
|
+
task_name: str,
|
311
|
+
program: str,
|
312
|
+
errors: list,
|
313
|
+
**kwargs
|
314
|
+
):
|
315
|
+
for error in errors:
|
316
|
+
fname = error.get("function", "Unknown")
|
317
|
+
colname = error.get("column", "Unknown")
|
318
|
+
value = error.get("value", "Unknown")
|
319
|
+
expected = error.get("expected", "Unknown")
|
320
|
+
cPrint(
|
321
|
+
"------------"
|
322
|
+
)
|
323
|
+
cPrint(
|
324
|
+
f"- {task_name}: {fname} reached for {colname} with value: {value}, expected: {expected}",
|
325
|
+
level='CRITICAL'
|
326
|
+
)
|
327
|
+
cPrint(
|
328
|
+
"------------"
|
329
|
+
)
|
330
|
+
# Getting a Notify component based on Alert configuration:
|
331
|
+
ntf, recipients = self.getNotify(self._channel, **kwargs)
|
332
|
+
# build notification message:
|
333
|
+
err_info = '\n'.join(
|
334
|
+
[
|
335
|
+
f"- {error.get('column', 'Unknown')}: {error.get('value', 'Unknown')}"
|
336
|
+
for error in errors
|
337
|
+
]
|
338
|
+
)
|
339
|
+
message = f"🛑 ::{ENVIRONMENT} - Task {program}.{task_name}, Error on: {err_info}"
|
340
|
+
# send the notification:
|
341
|
+
args = {"recipient": [recipients], "message": message}
|
342
|
+
if self._channel == 'teams':
|
343
|
+
channel = recipients
|
344
|
+
msg = TeamsCard(
|
345
|
+
text=str(message),
|
346
|
+
summary=f"Task Summary: {program}.{task_name}",
|
347
|
+
title=f"Task {program}.{task_name}",
|
348
|
+
)
|
349
|
+
async with ntf as conn:
|
350
|
+
return await conn.send(
|
351
|
+
recipient=channel,
|
352
|
+
message=msg
|
353
|
+
)
|
354
|
+
elif ntf.provider_type == "email":
|
355
|
+
args["subject"] = message
|
356
|
+
elif ntf.provider == "telegram":
|
357
|
+
args["disable_notification"] = True
|
358
|
+
else:
|
359
|
+
args["subject"] = message
|
360
|
+
async with ntf as t:
|
361
|
+
result = await t.send(**args)
|
362
|
+
return result
|
@@ -0,0 +1,131 @@
|
|
1
|
+
from typing import Union, Any
|
2
|
+
import pandas as pd
|
3
|
+
from navconfig.logging import logging
|
4
|
+
|
5
|
+
|
6
|
+
def average(
|
7
|
+
df: pd.DataFrame,
|
8
|
+
desc: Any,
|
9
|
+
column_name: str,
|
10
|
+
threshold: Union[int, float],
|
11
|
+
deviation: Union[int, float] = 2,
|
12
|
+
allow_below: bool = False,
|
13
|
+
allow_above: bool = False,
|
14
|
+
) -> tuple:
|
15
|
+
"""average.
|
16
|
+
|
17
|
+
Args:
|
18
|
+
df (pd.DataFrame): Dataframe.
|
19
|
+
desc (Any): Description of the DataFrame.
|
20
|
+
colname (str): Column Name.
|
21
|
+
threshold (Union[int, float]): Threshold value.
|
22
|
+
deviation (Union[int, float]): percent of deviation from the threshold
|
23
|
+
allow_below (bool): how many percent below the threshold is allowed
|
24
|
+
allow_above (bool): how many percent above the threshold is allowed
|
25
|
+
|
26
|
+
Returns:
|
27
|
+
[type]: [description]
|
28
|
+
"""
|
29
|
+
value = desc.loc["mean", column_name]
|
30
|
+
allowed_deviation = threshold * deviation / 100
|
31
|
+
_min = threshold - allowed_deviation
|
32
|
+
_max = threshold + allowed_deviation
|
33
|
+
print("MIN ", _min, "MAX ", _max)
|
34
|
+
val = bool(_min <= value <= _max)
|
35
|
+
logging.debug(f"Current Average value: {value}")
|
36
|
+
if value <= _min and allow_below is True:
|
37
|
+
val = True
|
38
|
+
if value >= _max and allow_above is True:
|
39
|
+
val = True
|
40
|
+
return value, val
|
41
|
+
|
42
|
+
|
43
|
+
def between(df: pd.DataFrame, desc: Any, column_name: str, values: tuple) -> tuple:
|
44
|
+
"""
|
45
|
+
Check if the values in a DataFrame column are between the given min and max values.
|
46
|
+
|
47
|
+
Args:
|
48
|
+
- df (pd.DataFrame): The DataFrame to check.
|
49
|
+
- desc (Any): The description (usually from df.describe()) of the DataFrame.
|
50
|
+
- column_name (str): The name of the column to check.
|
51
|
+
- values (tuple): A tuple containing the (min, max) values.
|
52
|
+
|
53
|
+
"""
|
54
|
+
min_value = desc.loc["min", column_name]
|
55
|
+
max_value = desc.loc["max", column_name]
|
56
|
+
min_threshold, max_threshold = values
|
57
|
+
val = min_threshold <= min_value and max_value <= max_threshold
|
58
|
+
return (min_value, max_value), val
|
59
|
+
|
60
|
+
|
61
|
+
def equal(df: pd.DataFrame, desc: Any, column_name: str, values: tuple) -> tuple:
|
62
|
+
"""
|
63
|
+
Check if all values in a DataFrame column are within the provided list of strings.
|
64
|
+
|
65
|
+
Args:
|
66
|
+
- df (pd.DataFrame): The DataFrame to check.
|
67
|
+
- desc (Any): The description (usually from df.describe()) of the DataFrame.
|
68
|
+
- column_name (str): The name of the column to check.
|
69
|
+
- values (tuple): A tuple containing the allowed strings.
|
70
|
+
|
71
|
+
"""
|
72
|
+
return values, bool(df[column_name].isin(values).all())
|
73
|
+
|
74
|
+
|
75
|
+
def count_nulls(df: pd.DataFrame, desc: Any, column_name: str, value: int) -> tuple:
|
76
|
+
"""
|
77
|
+
Check if the number of non-null values in a column is greater than a given threshold.
|
78
|
+
|
79
|
+
Args:
|
80
|
+
- df (pd.DataFrame): The DataFrame to check.
|
81
|
+
- desc (Any): The description (usually from df.describe()) of the DataFrame.
|
82
|
+
- column_name (str): The name of the column to check.
|
83
|
+
- min_length (int): The minimum number of non-null values required.
|
84
|
+
|
85
|
+
Returns:
|
86
|
+
tuple: (min_length, True/False)
|
87
|
+
"""
|
88
|
+
actual_length = df[column_name].notnull().sum() # Count non-null values
|
89
|
+
return actual_length, actual_length < value
|
90
|
+
|
91
|
+
def not_null(df: pd.DataFrame, desc: Any, column_name: str):
|
92
|
+
"""
|
93
|
+
Check if a DataFrame column contains only non-null values.
|
94
|
+
|
95
|
+
Args:
|
96
|
+
- df (pd.DataFrame): The DataFrame to check.
|
97
|
+
- desc (Any): The description (usually from df.describe()) of the DataFrame.
|
98
|
+
- column_name (str): The name of the column to check.
|
99
|
+
|
100
|
+
Returns:
|
101
|
+
tuple: (column_name, True/False)
|
102
|
+
"""
|
103
|
+
return column_name, df[column_name].notnull().all()
|
104
|
+
|
105
|
+
def column_size(df: pd.DataFrame, desc: Any, column_name: str, min_length: int, max_length: int) -> tuple:
|
106
|
+
"""
|
107
|
+
Check if all values in a string column have lengths within the specified range.
|
108
|
+
|
109
|
+
Args:
|
110
|
+
df (pd.DataFrame): The DataFrame to check.
|
111
|
+
desc (Any): Ignored, used for compatibility.
|
112
|
+
column_name (str): The name of the column to check.
|
113
|
+
min_length (int): The minimum length allowed for strings.
|
114
|
+
max_length (int): The maximum length allowed for strings.
|
115
|
+
|
116
|
+
Returns:
|
117
|
+
tuple: (column_name, min_length, max_length, True/False)
|
118
|
+
"""
|
119
|
+
# Ensure the column exists
|
120
|
+
if column_name not in df.columns:
|
121
|
+
return column_name, min_length, max_length, False
|
122
|
+
|
123
|
+
# Ensure all values are strings
|
124
|
+
if not df[column_name].map(lambda x: isinstance(x, str)).all():
|
125
|
+
return column_name, min_length, max_length, False
|
126
|
+
|
127
|
+
# Check string lengths
|
128
|
+
lengths = df[column_name].str.len()
|
129
|
+
within_range = (lengths >= min_length) & (lengths <= max_length)
|
130
|
+
|
131
|
+
return (min_length, max_length), within_range.all()
|
@@ -0,0 +1,158 @@
|
|
1
|
+
from typing import Union, Tuple
|
2
|
+
|
3
|
+
|
4
|
+
def average(
|
5
|
+
data: dict,
|
6
|
+
column: str,
|
7
|
+
threshold: Union[int, float],
|
8
|
+
deviation: Union[int, float],
|
9
|
+
allow_below: bool = False,
|
10
|
+
):
|
11
|
+
"""average.
|
12
|
+
|
13
|
+
Calculates the average of a value compared with a threshold.
|
14
|
+
Args:
|
15
|
+
data (dict): extract column from data.
|
16
|
+
column (str): column to calculate.
|
17
|
+
threshold (float): value to be used for threshold
|
18
|
+
deviation (float): max deviation acceptable for threshold
|
19
|
+
allow_below (bool): if True, the threshold is not evaluated on minimum values.
|
20
|
+
"""
|
21
|
+
value = data.get(column, None)
|
22
|
+
allowed_deviation = threshold * deviation / 100
|
23
|
+
_min = threshold - allowed_deviation
|
24
|
+
_max = threshold + allowed_deviation
|
25
|
+
print("MIN ", _min, "MAX ", _max)
|
26
|
+
val = _min <= value <= _max
|
27
|
+
if value <= _min and allow_below is True:
|
28
|
+
val = True
|
29
|
+
return column, value, val
|
30
|
+
|
31
|
+
|
32
|
+
def max_value(
|
33
|
+
data: dict, column: str, value: Union[int, float]
|
34
|
+
) -> Tuple[str, Union[int, float], bool]:
|
35
|
+
"""
|
36
|
+
Checks if the actual value of a specified column in the data is less than or equal to the
|
37
|
+
given threshold value.
|
38
|
+
|
39
|
+
Args:
|
40
|
+
data (dict): Dictionary containing the data to be checked.
|
41
|
+
column (str): Name of the column in the data whose value needs to be checked.
|
42
|
+
value (Union[int, float]): The threshold value. The actual value in the data
|
43
|
+
should be less than or equal to this.
|
44
|
+
|
45
|
+
Returns:
|
46
|
+
tuple: A tuple containing:
|
47
|
+
- column (str): Name of the column that was checked.
|
48
|
+
- actual_value (Union[int, float]): The actual value from the data for the specified column.
|
49
|
+
- val (bool): True if the actual value is less than or equal to the threshold, False otherwise.
|
50
|
+
"""
|
51
|
+
actual_value = data.get(column, None)
|
52
|
+
val = actual_value <= value
|
53
|
+
return column, actual_value, val
|
54
|
+
|
55
|
+
|
56
|
+
def min_value(
|
57
|
+
data: dict, column: str, value: Union[int, float]
|
58
|
+
) -> Tuple[str, Union[int, float], bool]:
|
59
|
+
"""
|
60
|
+
Checks if the actual value of a specified column in the data is greater than or
|
61
|
+
equal to the given threshold value.
|
62
|
+
|
63
|
+
Args:
|
64
|
+
data (dict): Dictionary containing the data to be checked.
|
65
|
+
column (str): Name of the column in the data whose value needs to be checked.
|
66
|
+
value (Union[int, float]): The threshold value. The actual value in the data
|
67
|
+
should be greater than or equal to this.
|
68
|
+
|
69
|
+
Returns:
|
70
|
+
tuple: A tuple containing:
|
71
|
+
- column (str): Name of the column that was checked.
|
72
|
+
- actual_value (Union[int, float]): The actual value from the data for the specified column.
|
73
|
+
- val (bool): True if the actual value is greater than or equal
|
74
|
+
to the threshold, False otherwise.
|
75
|
+
"""
|
76
|
+
actual_value = data.get(column, None)
|
77
|
+
val = actual_value >= value
|
78
|
+
return column, actual_value, val
|
79
|
+
|
80
|
+
def has_columns(data: dict, column: str = 'columns', value: list = []) -> Tuple[str, Union[int, float], bool]:
|
81
|
+
"""
|
82
|
+
Check if the actual value on a specified column in the data is equal to the given threshold value.
|
83
|
+
"""
|
84
|
+
actual_value = data.get(column, None)
|
85
|
+
val = actual_value in value
|
86
|
+
return column, actual_value, val
|
87
|
+
|
88
|
+
def missing_columns(data: dict, column: str = 'columns', value: list = []) -> Tuple[str, Union[int, float], bool]:
|
89
|
+
"""
|
90
|
+
Check if all required columns exist in the 'columns' field of the given data.
|
91
|
+
|
92
|
+
:param data: Dictionary containing the structure with "columns".
|
93
|
+
:param column: Name of the column to check (by default: "columns").
|
94
|
+
:param value: List of columns to check.
|
95
|
+
:return: Tuple (checked_key, missing_columns, bool)
|
96
|
+
"""
|
97
|
+
available_columns = data.get(column, None)
|
98
|
+
missing_columns = [col for col in value if col not in available_columns]
|
99
|
+
return "columns", missing_columns, len(missing_columns) == 0
|
100
|
+
|
101
|
+
def equal(
|
102
|
+
data: dict, column: str, value: Union[int, float]
|
103
|
+
) -> Tuple[str, Union[int, float], bool]:
|
104
|
+
"""
|
105
|
+
Check if the actual value on a specified column in the data is equal to the given threshold value.
|
106
|
+
"""
|
107
|
+
actual_value = data.get(column, None)
|
108
|
+
val = actual_value == value
|
109
|
+
return column, actual_value, val
|
110
|
+
|
111
|
+
def gt(
|
112
|
+
data: dict, column: str, value: Union[int, float]
|
113
|
+
) -> Tuple[str, Union[int, float], bool]:
|
114
|
+
"""
|
115
|
+
Check if the actual value on a specified column in the data is greater than to the given threshold value.
|
116
|
+
"""
|
117
|
+
try:
|
118
|
+
actual_value = data.get(column, None)
|
119
|
+
val = float(actual_value) >= float(value)
|
120
|
+
return column, actual_value, val
|
121
|
+
except Exception as e:
|
122
|
+
return column, None, False
|
123
|
+
|
124
|
+
def lt(
|
125
|
+
data: dict, column: str, value: Union[int, float]
|
126
|
+
) -> Tuple[str, Union[int, float], bool]:
|
127
|
+
"""
|
128
|
+
Check if the actual value on a specified column in the data is less than to the given threshold value.
|
129
|
+
"""
|
130
|
+
try:
|
131
|
+
actual_value = data.get(column, None)
|
132
|
+
val = float(actual_value) <= float(value)
|
133
|
+
return column, actual_value, val
|
134
|
+
except Exception as e:
|
135
|
+
return column, None, False
|
136
|
+
|
137
|
+
def between(data: dict, column: str, value: list) -> Tuple[str, Union[int, float], bool]:
|
138
|
+
"""
|
139
|
+
Checks if the actual value in the specified column is between two given values.
|
140
|
+
|
141
|
+
Args:
|
142
|
+
data (dict): Dictionary containing the column data.
|
143
|
+
column (str): Column name to evaluate.
|
144
|
+
value (list): A list containing two values: [min_value, max_value].
|
145
|
+
|
146
|
+
Returns:
|
147
|
+
tuple: (column, actual_value, True/False)
|
148
|
+
"""
|
149
|
+
if not isinstance(value, list) or len(value) != 2:
|
150
|
+
raise ValueError(f"Invalid value for 'between': {value}. Must be a list of two numbers.")
|
151
|
+
|
152
|
+
min_val, max_val = value # Unpack min and max
|
153
|
+
actual_value = data.get(column, None) # Extract the value from data
|
154
|
+
|
155
|
+
if actual_value is None:
|
156
|
+
return column, None, False # Column not found
|
157
|
+
|
158
|
+
return column, actual_value, min_val <= actual_value <= max_val
|
@@ -0,0 +1,12 @@
|
|
1
|
+
from ...utils import cPrint
|
2
|
+
from .abstract import AbstractEvent
|
3
|
+
|
4
|
+
|
5
|
+
class Dummy(AbstractEvent):
|
6
|
+
async def __call__(self, *args, **kwargs):
|
7
|
+
status = kwargs.pop("status", "event")
|
8
|
+
task = kwargs.pop("task", None)
|
9
|
+
cPrint(
|
10
|
+
f" == TASK {task} EXECUTED {status} WITH: {self._kwargs}, {args}, {kwargs} === ",
|
11
|
+
level="INFO",
|
12
|
+
)
|