flowtask 5.8.4__cp39-cp39-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-39-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-39-x86_64-linux-gnu.so +0 -0
- flowtask/parsers/argparser.py +235 -0
- flowtask/parsers/base.c +15155 -0
- flowtask/parsers/base.cpython-39-x86_64-linux-gnu.so +0 -0
- flowtask/parsers/json.c +11968 -0
- flowtask/parsers/json.cpython-39-x86_64-linux-gnu.so +0 -0
- flowtask/parsers/maps.py +49 -0
- flowtask/parsers/toml.c +11968 -0
- flowtask/parsers/toml.cpython-39-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-39-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-39-x86_64-linux-gnu.so +0 -0
- flowtask/utils/json.cpp +13349 -0
- flowtask/utils/json.cpython-39-x86_64-linux-gnu.so +0 -0
- flowtask/utils/mail.py +63 -0
- flowtask/utils/parseqs.c +13324 -0
- flowtask/utils/parserqs.cpython-39-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,450 @@
|
|
1
|
+
import asyncio
|
2
|
+
import copy
|
3
|
+
import re
|
4
|
+
from typing import Dict, List, Union
|
5
|
+
from collections.abc import Callable
|
6
|
+
import pandas as pd
|
7
|
+
import numpy as np
|
8
|
+
from navconfig.logging import logging
|
9
|
+
from asyncdb import AsyncDB
|
10
|
+
from asyncdb.exceptions import NoDataFound
|
11
|
+
from querysource.conf import asyncpg_url
|
12
|
+
from querysource.types.dt import transforms as qsdfunctions
|
13
|
+
from ...exceptions import ComponentError
|
14
|
+
from ...parsers.maps import open_map, open_model
|
15
|
+
from ..TransformRows import functions as tfunctions
|
16
|
+
from ...utils.executor import getFunction
|
17
|
+
from ..flow import FlowComponent
|
18
|
+
from . import functions as tmapfn
|
19
|
+
|
20
|
+
|
21
|
+
def is_snakecase(value):
|
22
|
+
## already in snake case:
|
23
|
+
return re.match(r"^[a-zA-Z][a-zA-Z0-9_]+_[a-zA-Z0-9]*$", value.strip()) is not None
|
24
|
+
|
25
|
+
|
26
|
+
def is_camelcase(value):
|
27
|
+
return re.match(r"^[A-Za-z][a-z0-9]*([A-Z][a-z0-9]*)*$", value.strip()) is not None
|
28
|
+
|
29
|
+
|
30
|
+
def is_titlecase(value):
|
31
|
+
return re.match(r"^([A-Z][a-z]*\s?)*$", value.strip()) is not None
|
32
|
+
|
33
|
+
|
34
|
+
def camelCase_split(value):
|
35
|
+
if bool(re.match(r"[A-Z]+$", value)):
|
36
|
+
return re.findall(r"[A-Z]+$", value)
|
37
|
+
elif bool(re.search(r"\d", value)):
|
38
|
+
return re.findall(r"[A-Z](?:[a-z]+[1-9]?|[A-Z]*(?=[A-Z])|$)", value)
|
39
|
+
elif value[0].isupper():
|
40
|
+
return re.findall(r"[A-Z](?:[a-z]+|[A-Z]*(?=[A-Z]|$))", value)
|
41
|
+
else:
|
42
|
+
# value = value.capitalize()
|
43
|
+
return re.findall(r"^[a-z]+|[A-Z][^A-Z]*", value)
|
44
|
+
|
45
|
+
|
46
|
+
class tMap(FlowComponent):
|
47
|
+
"""
|
48
|
+
tMap
|
49
|
+
|
50
|
+
Overview
|
51
|
+
|
52
|
+
The tMap class is a component for transforming and mapping data in a Pandas DataFrame. It supports various column name
|
53
|
+
transformations, data type conversions, and function applications to columns. It extends the FlowComponent class and
|
54
|
+
provides methods for column information retrieval, data transformation, and function execution.
|
55
|
+
|
56
|
+
.. table:: Properties
|
57
|
+
:widths: auto
|
58
|
+
|
59
|
+
+------------------+----------+-----------+--------------------------------------------------------------------------------------+
|
60
|
+
| Name | Required | Description |
|
61
|
+
+------------------+----------+-----------+--------------------------------------------------------------------------------------+
|
62
|
+
| tablename | No | The name of the table to retrieve column information from. |
|
63
|
+
+------------------+----------+-----------+--------------------------------------------------------------------------------------+
|
64
|
+
| schema | No | The schema of the table to retrieve column information from. |
|
65
|
+
+------------------+----------+-----------+--------------------------------------------------------------------------------------+
|
66
|
+
| model | No | The model to use for data transformation. |
|
67
|
+
+------------------+----------+-----------+--------------------------------------------------------------------------------------+
|
68
|
+
| _modelinfo | No | A dictionary containing the model information. |
|
69
|
+
+------------------+----------+-----------+--------------------------------------------------------------------------------------+
|
70
|
+
| map | No | The map file to use for column transformations. |
|
71
|
+
+------------------+----------+-----------+--------------------------------------------------------------------------------------+
|
72
|
+
| _mapping | No | A dictionary containing the column mappings. |
|
73
|
+
+------------------+----------+-----------+--------------------------------------------------------------------------------------+
|
74
|
+
| force_map | No | A flag indicating if the map file should be forced, defaults to False. |
|
75
|
+
+------------------+----------+-----------+--------------------------------------------------------------------------------------+
|
76
|
+
| replace_columns | No | A flag indicating if columns should be replaced, defaults to True. |
|
77
|
+
+------------------+----------+-----------+--------------------------------------------------------------------------------------+
|
78
|
+
| drop_missing | No | A flag indicating if missing columns should be dropped, defaults to False. |
|
79
|
+
+------------------+----------+-----------+--------------------------------------------------------------------------------------+
|
80
|
+
| column_info | Yes | I access the information of the column through a statement in sql to extract the data |
|
81
|
+
+------------------+----------+-----------+--------------------------------------------------------------------------------------+
|
82
|
+
| clean_names | Yes | Remove duplicate names from data |
|
83
|
+
+------------------+----------+-----------+--------------------------------------------------------------------------------------+
|
84
|
+
|
85
|
+
Return
|
86
|
+
|
87
|
+
The methods in this class manage the transformation and mapping of data in a Pandas DataFrame, including initialization,
|
88
|
+
column information retrieval, data transformation, and function execution.
|
89
|
+
|
90
|
+
|
91
|
+
|
92
|
+
Example:
|
93
|
+
|
94
|
+
```yaml
|
95
|
+
tMap:
|
96
|
+
schema: bose
|
97
|
+
map: products_by_store
|
98
|
+
drop_missing: false
|
99
|
+
```
|
100
|
+
|
101
|
+
""" # noqa
|
102
|
+
def __init__(
|
103
|
+
self,
|
104
|
+
loop: asyncio.AbstractEventLoop = None,
|
105
|
+
job: Callable = None,
|
106
|
+
stat: Callable = None,
|
107
|
+
**kwargs,
|
108
|
+
):
|
109
|
+
self.tablename: str = None
|
110
|
+
self.schema: str = None
|
111
|
+
self.model: str = None
|
112
|
+
self._modelinfo: dict = None
|
113
|
+
self.map: str = None
|
114
|
+
self._mapping: dict = None
|
115
|
+
self.force_map: bool = False
|
116
|
+
self.replace_columns: bool = True
|
117
|
+
self.drop_missing: bool = False
|
118
|
+
# use it for getting column information
|
119
|
+
self._flavor = kwargs.pop('flavor', 'postgres')
|
120
|
+
super(tMap, self).__init__(loop=loop, job=job, stat=stat, **kwargs)
|
121
|
+
if not self.schema:
|
122
|
+
self.schema = self._program
|
123
|
+
|
124
|
+
def _get_df_function(self, fn: str) -> Union[Callable, None]:
|
125
|
+
func = getattr(tfunctions, fn, None)
|
126
|
+
if func is None:
|
127
|
+
func = getattr(qsdfunctions, fn, None)
|
128
|
+
return func
|
129
|
+
|
130
|
+
async def column_info(
|
131
|
+
self, table: str, schema: str = "public", flavor: str = "postgres"
|
132
|
+
) -> list:
|
133
|
+
if not self.force_map:
|
134
|
+
result = None
|
135
|
+
if flavor == "postgres":
|
136
|
+
tablename = f"{schema}.{table}"
|
137
|
+
discover = f"""SELECT attname AS column_name, atttypid::regtype
|
138
|
+
AS data_type, attnotnull::boolean as notnull
|
139
|
+
FROM pg_attribute WHERE attrelid = '{tablename}'::regclass
|
140
|
+
AND attnum > 0 AND NOT attisdropped ORDER BY attnum;
|
141
|
+
"""
|
142
|
+
try:
|
143
|
+
try:
|
144
|
+
event_loop = asyncio.get_running_loop()
|
145
|
+
except RuntimeError:
|
146
|
+
event_loop = asyncio.get_event_loop()
|
147
|
+
db = AsyncDB("pg", dsn=asyncpg_url, loop=event_loop)
|
148
|
+
async with await db.connection() as conn:
|
149
|
+
result, error = await conn.query(discover)
|
150
|
+
if error:
|
151
|
+
raise ComponentError(f"Column Info Error {error}")
|
152
|
+
except NoDataFound:
|
153
|
+
pass
|
154
|
+
finally:
|
155
|
+
db = None
|
156
|
+
else:
|
157
|
+
raise ValueError(f"Column Info: Flavor not supported yet: {flavor}")
|
158
|
+
if result:
|
159
|
+
return {item["column_name"]: item["data_type"] for item in result}
|
160
|
+
# getting model from file:
|
161
|
+
model = await open_model(table, schema)
|
162
|
+
if model:
|
163
|
+
fields = model["fields"]
|
164
|
+
return {field: fields[field]["data_type"] for field in fields}
|
165
|
+
else:
|
166
|
+
if self.force_map:
|
167
|
+
self._logger.debug(
|
168
|
+
f"Open Map: Forcing using of Map File {schema}.{table}"
|
169
|
+
)
|
170
|
+
else:
|
171
|
+
self._logger.error(f"Open Map: Table {schema}.{table} doesn't exist")
|
172
|
+
return None
|
173
|
+
|
174
|
+
async def start(self, **kwargs):
|
175
|
+
if self.previous:
|
176
|
+
self.data = self.input
|
177
|
+
# getting model from model or from tablename
|
178
|
+
if self.tablename:
|
179
|
+
try:
|
180
|
+
self._modelinfo = await self.column_info(
|
181
|
+
table=self.tablename, schema=self.schema, flavor=self._flavor
|
182
|
+
)
|
183
|
+
except Exception as exc:
|
184
|
+
self._logger.warning(
|
185
|
+
f"Error getting Table Model for {self.tablename}.{self.schema} : {exc}"
|
186
|
+
)
|
187
|
+
if hasattr(self, "automap"):
|
188
|
+
# Create a Mapping converting columns:
|
189
|
+
mapping = {}
|
190
|
+
columns = self.data.columns.tolist()
|
191
|
+
for col in columns:
|
192
|
+
if is_snakecase(col):
|
193
|
+
new_name = col.strip().lower()
|
194
|
+
elif is_camelcase(col):
|
195
|
+
new_name = "_".join(
|
196
|
+
[x.lower().strip() for x in camelCase_split(col)]
|
197
|
+
)
|
198
|
+
else:
|
199
|
+
new_col = col.replace("(", "").replace(')', '').replace('-', '_').strip()
|
200
|
+
if is_camelcase(new_col):
|
201
|
+
new_name = "_".join(
|
202
|
+
[x.lower().strip() for x in camelCase_split(new_col)]
|
203
|
+
)
|
204
|
+
elif is_titlecase(new_col):
|
205
|
+
new_name = "_".join(
|
206
|
+
[x.lower().strip() for x in new_col.split(" ")]
|
207
|
+
)
|
208
|
+
else:
|
209
|
+
new_name = col.strip()
|
210
|
+
mapping[new_name] = col
|
211
|
+
self._mapping = mapping
|
212
|
+
else:
|
213
|
+
try:
|
214
|
+
# open a map file:
|
215
|
+
self._mapping = await open_map(
|
216
|
+
filename=str(self.map), program=self._program
|
217
|
+
)
|
218
|
+
except Exception as err:
|
219
|
+
raise ComponentError(f"TableMap: Error open Map File: {err}") from err
|
220
|
+
|
221
|
+
async def close(self):
|
222
|
+
"""
|
223
|
+
close.
|
224
|
+
|
225
|
+
close method
|
226
|
+
"""
|
227
|
+
|
228
|
+
def is_dataframe(self, df) -> bool:
|
229
|
+
return isinstance(df, pd.DataFrame)
|
230
|
+
|
231
|
+
async def run(self):
|
232
|
+
"""
|
233
|
+
run.
|
234
|
+
|
235
|
+
Iteration over all dataframes.
|
236
|
+
"""
|
237
|
+
if isinstance(self.data, list): # a list of dataframes
|
238
|
+
pass
|
239
|
+
elif isinstance(self.data, dict): # named queries
|
240
|
+
pass
|
241
|
+
else:
|
242
|
+
# one single dataframe
|
243
|
+
if not self.is_dataframe(self.data):
|
244
|
+
raise ComponentError(
|
245
|
+
"tMap Error: we're expecting a Pandas Dataframe as source."
|
246
|
+
)
|
247
|
+
# adding first metrics:
|
248
|
+
self.add_metric("started_rows", self.data.shape[0])
|
249
|
+
self.add_metric("started_columns", self.data.shape[1])
|
250
|
+
df = await self.transform(self.data, copy.deepcopy(self._mapping))
|
251
|
+
# check if a column is missing:
|
252
|
+
if self.drop_missing is True:
|
253
|
+
for column in df.columns:
|
254
|
+
if column not in self._mapping: # Dropping unused columns
|
255
|
+
df.drop(column, axis="columns", inplace=True)
|
256
|
+
self._result = df
|
257
|
+
# avoid threat the Dataframe as a Copy
|
258
|
+
self._result.is_copy = None
|
259
|
+
return self._result
|
260
|
+
|
261
|
+
async def transform(self, df: pd.DataFrame, mapping: dict) -> pd.DataFrame:
|
262
|
+
it = {}
|
263
|
+
for column, field in mapping.items():
|
264
|
+
logging.debug(f"tMap: CALLING {column} for {field}:{type(field)}")
|
265
|
+
if isinstance(field, str): # making a column replacement
|
266
|
+
try:
|
267
|
+
if column != field:
|
268
|
+
it[column] = pd.Series(df[field])
|
269
|
+
df.drop(field, axis="columns", inplace=True)
|
270
|
+
else:
|
271
|
+
it[column] = pd.Series(df[column])
|
272
|
+
df.drop(field, axis="columns", inplace=True)
|
273
|
+
continue
|
274
|
+
except KeyError:
|
275
|
+
self._logger.error(f"Column doesn't exists: {field}")
|
276
|
+
continue
|
277
|
+
elif isinstance(field, list):
|
278
|
+
col = field.pop(0)
|
279
|
+
if isinstance(col, list):
|
280
|
+
### combine several columns into one
|
281
|
+
df[column] = df[col].apply("|".join, axis=1)
|
282
|
+
# is a list of columns:
|
283
|
+
try:
|
284
|
+
fname = field.pop(0)
|
285
|
+
try:
|
286
|
+
kwargs = field[0]
|
287
|
+
except IndexError:
|
288
|
+
kwargs = {}
|
289
|
+
try:
|
290
|
+
result = await self.call_function(
|
291
|
+
fname, df, df, column, args=kwargs
|
292
|
+
)
|
293
|
+
it[column] = df[column]
|
294
|
+
if self.replace_columns is True:
|
295
|
+
df.drop(column, axis="columns", inplace=True)
|
296
|
+
continue
|
297
|
+
except Exception:
|
298
|
+
pass
|
299
|
+
except IndexError:
|
300
|
+
# No other changes to made:
|
301
|
+
it[column] = df[column]
|
302
|
+
if self.replace_columns is True:
|
303
|
+
for c in col:
|
304
|
+
df.drop(c, axis="columns", inplace=True)
|
305
|
+
df.drop(column, axis="columns", inplace=True)
|
306
|
+
continue
|
307
|
+
if len(field) == 0:
|
308
|
+
if col in df.columns:
|
309
|
+
# there is no change to made:
|
310
|
+
# simple field replacement
|
311
|
+
it[column] = it[col]
|
312
|
+
else:
|
313
|
+
# calling an scalar function:
|
314
|
+
it[column] = await self.call_function(col, None, df, col)
|
315
|
+
continue
|
316
|
+
if len(field) > 0:
|
317
|
+
### Calling a Function with(out) parameters
|
318
|
+
fname = field.pop(0)
|
319
|
+
try:
|
320
|
+
kwargs = field[0]
|
321
|
+
except IndexError:
|
322
|
+
kwargs = {}
|
323
|
+
# Call a Transformation Function on Dataframe:
|
324
|
+
self._logger.debug(
|
325
|
+
f"Calling {fname} with parameters: {kwargs}"
|
326
|
+
)
|
327
|
+
if col in df:
|
328
|
+
result = await self.call_function(fname, df, df, col, args=kwargs)
|
329
|
+
if col in result:
|
330
|
+
it[column] = result[col]
|
331
|
+
if self.replace_columns is True:
|
332
|
+
df.drop(col, axis="columns", inplace=True)
|
333
|
+
elif isinstance(field, dict):
|
334
|
+
# direct calling of Transform Function
|
335
|
+
val = list(field.keys())[0]
|
336
|
+
operation = field[val]
|
337
|
+
if val != "value":
|
338
|
+
fname = val
|
339
|
+
args = {}
|
340
|
+
if isinstance(operation[0], dict):
|
341
|
+
## Operation doesn't have a column involved:
|
342
|
+
## Or columns comes in arguments:
|
343
|
+
args = operation[0]
|
344
|
+
result = await self.call_function(
|
345
|
+
fname, df, df, column, args=args
|
346
|
+
)
|
347
|
+
it[column] = result[column]
|
348
|
+
df.drop(column, axis="columns", inplace=True)
|
349
|
+
continue
|
350
|
+
elif isinstance(operation[-1], dict):
|
351
|
+
args = operation.pop()
|
352
|
+
# all operation are arguments to fname:
|
353
|
+
# print('CALLING > ', fname, operation, args)
|
354
|
+
it[column] = await self.call_function(
|
355
|
+
fname, operation, df, column, args=args
|
356
|
+
)
|
357
|
+
else:
|
358
|
+
col = operation.pop(0) # name of column
|
359
|
+
try:
|
360
|
+
fname = operation.pop(0)
|
361
|
+
except IndexError:
|
362
|
+
### there is not function to apply:
|
363
|
+
it[column] = result[col]
|
364
|
+
continue
|
365
|
+
try:
|
366
|
+
kwargs = operation[0]
|
367
|
+
except IndexError:
|
368
|
+
kwargs = {}
|
369
|
+
result = await self.call_function(fname, df, df, col, args=kwargs)
|
370
|
+
it[column] = result[col]
|
371
|
+
if self.replace_columns is True:
|
372
|
+
df.drop(col, axis="columns", inplace=True)
|
373
|
+
# Join the original DataFrame with the new columns
|
374
|
+
df = pd.concat([df, pd.DataFrame(it)], axis=1)
|
375
|
+
# Set the index of the new DataFrame
|
376
|
+
df.set_index(df.index, inplace=True)
|
377
|
+
if self._debug is True:
|
378
|
+
columns = list(df.columns)
|
379
|
+
print("=== tMap Columns ===")
|
380
|
+
for column in columns:
|
381
|
+
try:
|
382
|
+
t = df[column].dtype
|
383
|
+
except AttributeError:
|
384
|
+
raise ComponentError(f"Error Parsing Column {column}")
|
385
|
+
print(column, "->", t, "->", df[column].iloc[0])
|
386
|
+
print("===")
|
387
|
+
print(df)
|
388
|
+
# avoid threat the Dataframe as a Copy
|
389
|
+
df.is_copy = None
|
390
|
+
try:
|
391
|
+
self.add_metric("mapped_rows", df.shape[0])
|
392
|
+
self.add_metric("mapped_columns", df.shape[1])
|
393
|
+
except Exception as err: # pylint: disable=W0703
|
394
|
+
logging.error(f"TransformRows: Error setting Metrics: {err}")
|
395
|
+
return df
|
396
|
+
|
397
|
+
async def call_function(
|
398
|
+
self,
|
399
|
+
fname: str,
|
400
|
+
df: Union[pd.DataFrame, pd.Series, List[str]],
|
401
|
+
old_df: pd.DataFrame,
|
402
|
+
column: str,
|
403
|
+
args: Dict = None,
|
404
|
+
**kwargs,
|
405
|
+
) -> Union[pd.DataFrame, pd.Series, None]:
|
406
|
+
logging.debug(
|
407
|
+
f"tMap: Calling {fname!s} for {column} with args: {args}/{kwargs}"
|
408
|
+
)
|
409
|
+
if isinstance(df, pd.Series):
|
410
|
+
try:
|
411
|
+
func = getattr(tmapfn, fname)
|
412
|
+
except AttributeError:
|
413
|
+
func = getFunction(fname)
|
414
|
+
elif isinstance(df, pd.DataFrame):
|
415
|
+
try:
|
416
|
+
func = self._get_df_function(fname)
|
417
|
+
except TypeError as exc:
|
418
|
+
raise ComponentError(f"Error on Function name: {fname}, {exc}") from exc
|
419
|
+
except AttributeError:
|
420
|
+
func = getFunction(fname)
|
421
|
+
elif isinstance(df, list):
|
422
|
+
try:
|
423
|
+
func = getattr(tmapfn, fname)
|
424
|
+
except AttributeError:
|
425
|
+
func = getFunction(fname)
|
426
|
+
else:
|
427
|
+
func = getFunction(fname)
|
428
|
+
if fname == "fill_column":
|
429
|
+
args["variables"] = self._variables
|
430
|
+
elif args is None:
|
431
|
+
args = {}
|
432
|
+
new_args = {**args, **kwargs}
|
433
|
+
if callable(func):
|
434
|
+
try:
|
435
|
+
if isinstance(df, pd.Series):
|
436
|
+
it = func(series=df, field=column, **new_args)
|
437
|
+
elif isinstance(df, pd.DataFrame):
|
438
|
+
it = func(df=df, field=column, **new_args)
|
439
|
+
elif isinstance(df, list):
|
440
|
+
it = func(old_df, df, **new_args)
|
441
|
+
else:
|
442
|
+
it = func(**new_args)
|
443
|
+
if np.isscalar(it):
|
444
|
+
it = pd.Series(it, index=old_df.index)
|
445
|
+
return it
|
446
|
+
except (ValueError, TypeError) as exc:
|
447
|
+
logging.warning(f"tMap: Error Calling function {func}: {exc}")
|
448
|
+
else:
|
449
|
+
logging.warning(f"tMap: Function {func} is not callable.")
|
450
|
+
return df
|
@@ -0,0 +1,112 @@
|
|
1
|
+
import asyncio
|
2
|
+
from typing import Any
|
3
|
+
from collections.abc import Callable
|
4
|
+
import pandas as pd
|
5
|
+
from querysource.exceptions import DriverError, QueryException
|
6
|
+
from ..exceptions import ComponentError
|
7
|
+
from .flow import FlowComponent
|
8
|
+
|
9
|
+
|
10
|
+
class tMelt(FlowComponent):
|
11
|
+
"""
|
12
|
+
tMelt
|
13
|
+
|
14
|
+
Overview
|
15
|
+
|
16
|
+
The tMelt class is a component for transforming a DataFrame from a wide format to a long format using the
|
17
|
+
Pandas `melt` function. It reshapes data by unpivoting columns, making it easier to analyze or process data
|
18
|
+
with a simpler, long-form structure.
|
19
|
+
|
20
|
+
.. table:: Properties
|
21
|
+
:widths: auto
|
22
|
+
|
23
|
+
+----------------+----------+-----------+---------------------------------------------------------------+
|
24
|
+
| Name | Required | Summary |
|
25
|
+
+----------------+----------+-----------+---------------------------------------------------------------+
|
26
|
+
| index | Yes | Column(s) to use as identifier variables for melting. |
|
27
|
+
+----------------+----------+-----------+---------------------------------------------------------------+
|
28
|
+
| name | No | Name to use for the "variable" column in the result DataFrame. |
|
29
|
+
| | | Defaults to "name". |
|
30
|
+
+----------------+----------+-----------+---------------------------------------------------------------+
|
31
|
+
| value | No | Name to use for the "value" column in the result DataFrame. |
|
32
|
+
| | | Defaults to "value". |
|
33
|
+
+----------------+----------+-----------+---------------------------------------------------------------+
|
34
|
+
| values | No | List of columns to unpivot. If None, all remaining columns are used. |
|
35
|
+
+----------------+----------+-----------+---------------------------------------------------------------+
|
36
|
+
|
37
|
+
Returns
|
38
|
+
|
39
|
+
This component returns a DataFrame in long format where specified columns are unpivoted to create two
|
40
|
+
new columns: one for variable names (`name`) and one for values (`value`). Metrics on the row and column
|
41
|
+
counts of the transformed DataFrame are recorded. Any errors during transformation are logged and raised
|
42
|
+
with descriptive error messages.
|
43
|
+
|
44
|
+
|
45
|
+
Example:
|
46
|
+
|
47
|
+
```yaml
|
48
|
+
tMelt:
|
49
|
+
index:
|
50
|
+
- AL No.
|
51
|
+
- Store Format
|
52
|
+
name: product_name
|
53
|
+
value: displays_quantity
|
54
|
+
```
|
55
|
+
|
56
|
+
""" #noqa
|
57
|
+
|
58
|
+
def __init__(
|
59
|
+
self,
|
60
|
+
loop: asyncio.AbstractEventLoop = None,
|
61
|
+
job: Callable = None,
|
62
|
+
stat: Callable = None,
|
63
|
+
**kwargs,
|
64
|
+
):
|
65
|
+
"""Init Method."""
|
66
|
+
self.df1: Any = None
|
67
|
+
self.df2: Any = None
|
68
|
+
self.type = None
|
69
|
+
super(tMelt, self).__init__(loop=loop, job=job, stat=stat, **kwargs)
|
70
|
+
|
71
|
+
async def start(self, **kwargs):
|
72
|
+
if self.previous:
|
73
|
+
self.data = self.input
|
74
|
+
else:
|
75
|
+
raise ComponentError("Data Not Found", status=404)
|
76
|
+
if not isinstance(self.data, pd.DataFrame):
|
77
|
+
raise ComponentError("Incompatible Pandas Dataframe", status=404)
|
78
|
+
if not hasattr(self, "index"):
|
79
|
+
raise DriverError("Crosstab Transform: Missing Index on definition")
|
80
|
+
if not hasattr(self, "name"):
|
81
|
+
self.name = "name"
|
82
|
+
if not hasattr(self, "value"):
|
83
|
+
self.name = "value"
|
84
|
+
|
85
|
+
if not hasattr(self, "values"):
|
86
|
+
self.values = None
|
87
|
+
|
88
|
+
return True
|
89
|
+
|
90
|
+
async def close(self):
|
91
|
+
pass
|
92
|
+
|
93
|
+
async def run(self):
|
94
|
+
try:
|
95
|
+
df = pd.melt(
|
96
|
+
self.data, id_vars=self.index, var_name=self.name, value_name=self.value
|
97
|
+
)
|
98
|
+
self._result = df
|
99
|
+
self.add_metric("NUM_ROWS", self._result.shape[0])
|
100
|
+
self.add_metric("NUM_COLUMNS", self._result.shape[1])
|
101
|
+
if self._debug:
|
102
|
+
print("Debugging: tCrosstab ===")
|
103
|
+
print(self._result)
|
104
|
+
columns = list(self._result.columns)
|
105
|
+
for column in columns:
|
106
|
+
t = self._result[column].dtype
|
107
|
+
print(column, "->", t, "->", self._result[column].iloc[0])
|
108
|
+
return self._result
|
109
|
+
except (ValueError, KeyError) as err:
|
110
|
+
raise QueryException(f"Crosstab Error: {err!s}") from err
|
111
|
+
except Exception as err:
|
112
|
+
raise QueryException(f"Unknown error {err!s}") from err
|
@@ -0,0 +1,114 @@
|
|
1
|
+
import asyncio
|
2
|
+
import pandas as pd
|
3
|
+
from typing import Any
|
4
|
+
from collections.abc import Callable
|
5
|
+
from querysource.exceptions import QueryException
|
6
|
+
from ..exceptions import ComponentError
|
7
|
+
from .flow import FlowComponent
|
8
|
+
|
9
|
+
|
10
|
+
class tMerge(FlowComponent):
|
11
|
+
"""
|
12
|
+
tMerge
|
13
|
+
|
14
|
+
Overview
|
15
|
+
|
16
|
+
The tMerge class is a component for merging two DataFrames (or named Series objects) using a database-style join.
|
17
|
+
It supports different join types such as 'inner', 'outer', 'left', 'right', and 'cross', allowing flexible merging
|
18
|
+
configurations for complex data workflows.
|
19
|
+
|
20
|
+
.. table:: Properties
|
21
|
+
:widths: auto
|
22
|
+
|
23
|
+
+------------------+----------+-----------+---------------------------------------------------------------+
|
24
|
+
| Name | Required | Summary |
|
25
|
+
+------------------+----------+-----------+---------------------------------------------------------------+
|
26
|
+
| df1 | Yes | The left DataFrame to join. |
|
27
|
+
+------------------+----------+-----------+---------------------------------------------------------------+
|
28
|
+
| df2 | Yes | The right DataFrame to join. |
|
29
|
+
+------------------+----------+-----------+---------------------------------------------------------------+
|
30
|
+
| type | No | The type of join to perform (e.g., 'inner', 'outer'). Defaults to 'cross'.|
|
31
|
+
+------------------+----------+-----------+---------------------------------------------------------------+
|
32
|
+
| pd_args | No | Additional arguments for the Pandas merge function, if any. |
|
33
|
+
+------------------+----------+-----------+---------------------------------------------------------------+
|
34
|
+
|
35
|
+
Returns
|
36
|
+
|
37
|
+
This component returns a DataFrame created by merging `df1` and `df2` based on the specified join type and arguments.
|
38
|
+
It records metrics for the resulting DataFrame’s row and column counts. Any errors during merging are raised
|
39
|
+
with detailed error messages, and additional debug information is available if debugging mode is enabled.
|
40
|
+
|
41
|
+
|
42
|
+
Example:
|
43
|
+
|
44
|
+
```yaml
|
45
|
+
tMerge:
|
46
|
+
depends:
|
47
|
+
- QueryToPandas_1
|
48
|
+
- QueryToPandas_2
|
49
|
+
type: cross
|
50
|
+
```
|
51
|
+
|
52
|
+
""" #noqa
|
53
|
+
|
54
|
+
def __init__(
|
55
|
+
self,
|
56
|
+
loop: asyncio.AbstractEventLoop = None,
|
57
|
+
job: Callable = None,
|
58
|
+
stat: Callable = None,
|
59
|
+
**kwargs,
|
60
|
+
):
|
61
|
+
"""Init Method."""
|
62
|
+
self.df1: Any = None
|
63
|
+
self.df2: Any = None
|
64
|
+
self.type = kwargs.pop('type', 'cross')
|
65
|
+
super(tMerge, self).__init__(loop=loop, job=job, stat=stat, **kwargs)
|
66
|
+
|
67
|
+
async def start(self, **kwargs):
|
68
|
+
if self.previous:
|
69
|
+
self.data = self.input
|
70
|
+
else:
|
71
|
+
raise ComponentError("Data Not Found")
|
72
|
+
try:
|
73
|
+
self.df1 = self.previous[0].output()
|
74
|
+
except IndexError as ex:
|
75
|
+
name = self.depends[0]
|
76
|
+
raise ComponentError(
|
77
|
+
f"Missing LEFT Dataframe: {name}"
|
78
|
+
) from ex
|
79
|
+
try:
|
80
|
+
self.df2 = self.previous[1].output()
|
81
|
+
except IndexError as ex:
|
82
|
+
name = self.depends[1]
|
83
|
+
raise ComponentError(
|
84
|
+
"Missing RIGHT Dataframe"
|
85
|
+
) from ex
|
86
|
+
return True
|
87
|
+
|
88
|
+
async def close(self):
|
89
|
+
pass
|
90
|
+
|
91
|
+
async def run(self):
|
92
|
+
try:
|
93
|
+
if hasattr(self, "pd_args"):
|
94
|
+
args = self.pd_args
|
95
|
+
else:
|
96
|
+
args = {}
|
97
|
+
df = pd.merge(self.df1, self.df2, how=self.type, **args)
|
98
|
+
self._result = df
|
99
|
+
self.add_metric("NUM_ROWS", self._result.shape[0])
|
100
|
+
self.add_metric("NUM_COLUMNS", self._result.shape[1])
|
101
|
+
if self._debug:
|
102
|
+
print("Debugging: tMerge ===")
|
103
|
+
print(self._result)
|
104
|
+
columns = list(self._result.columns)
|
105
|
+
for column in columns:
|
106
|
+
t = self._result[column].dtype
|
107
|
+
print(
|
108
|
+
column, "->", t, "->", self._result[column].iloc[0]
|
109
|
+
)
|
110
|
+
return self._result
|
111
|
+
except (ValueError, KeyError) as err:
|
112
|
+
raise ComponentError(f"tMerge Error: {err!s}") from err
|
113
|
+
except Exception as err:
|
114
|
+
raise ComponentError(f"tMerge error {err!s}") from err
|