flowtask 5.8.4__cp310-cp310-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-310-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-310-x86_64-linux-gnu.so +0 -0
- flowtask/parsers/argparser.py +235 -0
- flowtask/parsers/base.c +15155 -0
- flowtask/parsers/base.cpython-310-x86_64-linux-gnu.so +0 -0
- flowtask/parsers/json.c +11968 -0
- flowtask/parsers/json.cpython-310-x86_64-linux-gnu.so +0 -0
- flowtask/parsers/maps.py +49 -0
- flowtask/parsers/toml.c +11968 -0
- flowtask/parsers/toml.cpython-310-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-310-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-310-x86_64-linux-gnu.so +0 -0
- flowtask/utils/json.cpp +13349 -0
- flowtask/utils/json.cpython-310-x86_64-linux-gnu.so +0 -0
- flowtask/utils/mail.py +63 -0
- flowtask/utils/parseqs.c +13324 -0
- flowtask/utils/parserqs.cpython-310-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,534 @@
|
|
1
|
+
import asyncio
|
2
|
+
from typing import Dict, Any
|
3
|
+
from collections.abc import Callable
|
4
|
+
from pathlib import PosixPath, Path
|
5
|
+
import re
|
6
|
+
from decimal import Decimal
|
7
|
+
import datetime
|
8
|
+
import numpy as np
|
9
|
+
import pandas as pd
|
10
|
+
import dask.dataframe as dd
|
11
|
+
from asyncdb.models import Model
|
12
|
+
import dateparser
|
13
|
+
from navconfig.logging import logging
|
14
|
+
from ..exceptions import FileError, ComponentError, DataNotFound
|
15
|
+
from .flow import FlowComponent
|
16
|
+
from ..interfaces.qs import QSSupport
|
17
|
+
from ..utils.transformations import (
|
18
|
+
is_camelcase,
|
19
|
+
is_snakecase,
|
20
|
+
remove_illegal_chars,
|
21
|
+
camelcase_split
|
22
|
+
)
|
23
|
+
from ..utils.constants import excel_based
|
24
|
+
|
25
|
+
|
26
|
+
logging.getLogger("fsspec").setLevel(logging.CRITICAL)
|
27
|
+
|
28
|
+
|
29
|
+
dtypes = {
|
30
|
+
"varchar": str,
|
31
|
+
"character varying": str,
|
32
|
+
"string": str,
|
33
|
+
"object": str,
|
34
|
+
"int": int,
|
35
|
+
"int4": int,
|
36
|
+
"integer": int,
|
37
|
+
"bigint": np.int64,
|
38
|
+
"int64": np.int64,
|
39
|
+
"uint64": np.int64,
|
40
|
+
"Int8": int,
|
41
|
+
"float64": Decimal,
|
42
|
+
"float": Decimal,
|
43
|
+
"bool": bool,
|
44
|
+
"datetime64[ns]": datetime.datetime,
|
45
|
+
"date": datetime.date,
|
46
|
+
}
|
47
|
+
|
48
|
+
|
49
|
+
# adding support for primary keys on raw tables
|
50
|
+
pk_sentence = """ALTER TABLE {schema}.{table}
|
51
|
+
ADD CONSTRAINT {schema}_{table}_pkey PRIMARY KEY({fields});
|
52
|
+
|
53
|
+
Example:
|
54
|
+
|
55
|
+
```yaml
|
56
|
+
TableSchema:
|
57
|
+
normalize_names: true
|
58
|
+
tablename: photos_raw
|
59
|
+
schema: banco_chile
|
60
|
+
pk:
|
61
|
+
- photo_id
|
62
|
+
replace_names:
|
63
|
+
url: url_thumbnail
|
64
|
+
full_size_url: photo_path
|
65
|
+
categories: categories_names
|
66
|
+
form_visit_id: form_id
|
67
|
+
inserted: inserted_at
|
68
|
+
```
|
69
|
+
|
70
|
+
"""
|
71
|
+
|
72
|
+
|
73
|
+
def datetime_to_name(value: datetime.datetime, mask: str):
|
74
|
+
return value.strftime(mask)
|
75
|
+
|
76
|
+
|
77
|
+
# Lista de palabras reservadas comunes en SQL
|
78
|
+
SQL_RESERVED_WORDS = [
|
79
|
+
"all", "analyse", "analyze", "and", "any", "array", "as", "asc",
|
80
|
+
"asymmetric", "authorization", "binary", "both", "case", "cast",
|
81
|
+
"check", "collate", "collation", "column", "constraint", "create",
|
82
|
+
"cross", "current_catalog", "current_date", "current_role",
|
83
|
+
"current_time", "current_timestamp", "current_user", "default",
|
84
|
+
"deferrable", "desc", "distinct", "do", "else", "end", "except",
|
85
|
+
"false", "fetch", "for", "foreign", "freeze", "from", "full",
|
86
|
+
"grant", "group", "having", "ilike", "in", "initially", "inner",
|
87
|
+
"intersect", "into", "is", "isnull", "join", "lateral", "leading",
|
88
|
+
"left", "like", "limit", "localtime", "localtimestamp", "natural",
|
89
|
+
"not", "notnull", "null", "offset", "on", "only", "or", "order",
|
90
|
+
"outer", "overlaps", "placing", "primary", "references", "returning",
|
91
|
+
"right", "select", "session_user", "similar", "some", "symmetric",
|
92
|
+
"table", "tablesample", "then", "to", "trailing", "true", "union",
|
93
|
+
"unique", "user", "using", "variadic", "verbose", "when", "where",
|
94
|
+
"window", "with"
|
95
|
+
]
|
96
|
+
|
97
|
+
|
98
|
+
class TableSchema(QSSupport, FlowComponent):
|
99
|
+
"""
|
100
|
+
TableSchema
|
101
|
+
|
102
|
+
Overview
|
103
|
+
|
104
|
+
The TableSchema class is a component for reading a CSV file or DataFrame and creating a table schema based
|
105
|
+
on data models. It supports various formatting and normalization options for column names, datatype inference,
|
106
|
+
and automatic handling of primary keys. This component also supports normalization settings for column names,
|
107
|
+
such as camelCase to snake_case conversion, illegal character removal, and customizable name replacements.
|
108
|
+
|
109
|
+
.. table:: Properties
|
110
|
+
:widths: auto
|
111
|
+
|
112
|
+
+-------------------+----------+-----------+------------------------------------------------------------------+
|
113
|
+
| Name | Required | Summary |
|
114
|
+
+-------------------+----------+-----------+------------------------------------------------------------------+
|
115
|
+
| filename | Yes | The CSV file or DataFrame input to read and infer schema from. |
|
116
|
+
+-------------------+----------+-----------+------------------------------------------------------------------+
|
117
|
+
| schema | No | The database schema for the table. |
|
118
|
+
+-------------------+----------+-----------+------------------------------------------------------------------+
|
119
|
+
| tablename | Yes | The name of the table to be created based on the data model. |
|
120
|
+
+-------------------+----------+-----------+------------------------------------------------------------------+
|
121
|
+
| drop | No | Boolean specifying if an existing table with the same name should be dropped.|
|
122
|
+
+-------------------+----------+-----------+------------------------------------------------------------------+
|
123
|
+
| normalize_names | No | Dictionary with options for column name normalization. |
|
124
|
+
+-------------------+----------+-----------+------------------------------------------------------------------+
|
125
|
+
| pk | No | List of columns to define as primary keys. |
|
126
|
+
+-------------------+----------+-----------+------------------------------------------------------------------+
|
127
|
+
| replace_names | No | Dictionary of column name replacements for renaming specific columns. |
|
128
|
+
+-------------------+----------+-----------+------------------------------------------------------------------+
|
129
|
+
|
130
|
+
Returns
|
131
|
+
|
132
|
+
This component returns the input data after creating a database table schema based on the data's inferred or
|
133
|
+
specified structure. If the input is a file, it reads and processes the file; if a DataFrame, it directly
|
134
|
+
processes the DataFrame. The component provides detailed metrics on column structure and row counts, as well as
|
135
|
+
logging for SQL execution status and any schema creation errors.
|
136
|
+
""" # noqa
|
137
|
+
|
138
|
+
def __init__(
|
139
|
+
self,
|
140
|
+
loop: asyncio.AbstractEventLoop = None,
|
141
|
+
job: Callable = None,
|
142
|
+
stat: Callable = None,
|
143
|
+
**kwargs,
|
144
|
+
) -> None:
|
145
|
+
"""Init Method."""
|
146
|
+
self.separator: str = ","
|
147
|
+
self.params: Dict = {}
|
148
|
+
self.fields: Dict = {}
|
149
|
+
self.replace_names: Dict = {}
|
150
|
+
self.drop: bool = False
|
151
|
+
self.data: Any = None
|
152
|
+
self.filename: str = None
|
153
|
+
# info about table:
|
154
|
+
self.tablename: str = None
|
155
|
+
self.schema: str = None
|
156
|
+
self.credentials = kwargs.pop('credentials', None)
|
157
|
+
self._driver: str = kwargs.pop('driver', 'pg')
|
158
|
+
super(TableSchema, self).__init__(
|
159
|
+
loop=loop,
|
160
|
+
job=job,
|
161
|
+
stat=stat,
|
162
|
+
**kwargs
|
163
|
+
)
|
164
|
+
|
165
|
+
async def start(self, **kwargs):
|
166
|
+
if self.previous:
|
167
|
+
if isinstance(self.input, PosixPath):
|
168
|
+
self.filename = self.input
|
169
|
+
elif isinstance(self.input, list):
|
170
|
+
self.filename = PosixPath(self.input[0])
|
171
|
+
elif isinstance(self.input, str):
|
172
|
+
self.filename = PosixPath(self.input)
|
173
|
+
elif isinstance(self.input, dict):
|
174
|
+
filenames = list(self.input.keys())
|
175
|
+
if filenames:
|
176
|
+
try:
|
177
|
+
self.filename = PosixPath(filenames[0])
|
178
|
+
except IndexError as err:
|
179
|
+
raise FileError(f"File doesnt exists: {filenames}") from err
|
180
|
+
elif isinstance(self.input, dd.DataFrame) or isinstance(
|
181
|
+
self.input, pd.DataFrame
|
182
|
+
):
|
183
|
+
self.filename = None
|
184
|
+
self.data = self.input
|
185
|
+
else:
|
186
|
+
raise FileError(f"File doesnt exists: {self.input}")
|
187
|
+
elif hasattr(self, "filename"):
|
188
|
+
self.filename = Path(self.filename)
|
189
|
+
else:
|
190
|
+
raise ComponentError(
|
191
|
+
"TableSchema: This Component requires a File or Dataframe from input."
|
192
|
+
)
|
193
|
+
if hasattr(self, "replace_names") and self.replace_names:
|
194
|
+
for col, replace in self.replace_names.items():
|
195
|
+
if not isinstance(replace, (str, dict)):
|
196
|
+
self._logger.warning(
|
197
|
+
f"Invalid replace_names value for '{col}': expected string or dict, got {type(replace).__name__}"
|
198
|
+
)
|
199
|
+
elif isinstance(replace, dict) and "type" in replace and replace["type"] not in dtypes:
|
200
|
+
self._logger.warning(
|
201
|
+
f"Type '{replace['type']}' in replace_names for column '{col}' is not valid. Valid types: {list(dtypes.keys())}"
|
202
|
+
)
|
203
|
+
|
204
|
+
await super().start(**kwargs)
|
205
|
+
self.processing_credentials()
|
206
|
+
|
207
|
+
async def close(self):
|
208
|
+
pass
|
209
|
+
|
210
|
+
def rename_repeated_col(self, col, cols):
|
211
|
+
renamed = False
|
212
|
+
count = 1
|
213
|
+
for c, t in cols:
|
214
|
+
if c == col:
|
215
|
+
if not renamed:
|
216
|
+
col = f"{col}_{count}"
|
217
|
+
count += 1
|
218
|
+
renamed = True
|
219
|
+
else:
|
220
|
+
col = col.split("_", 1)[0]
|
221
|
+
col = f"{col}_{count}"
|
222
|
+
count += 1
|
223
|
+
return col
|
224
|
+
|
225
|
+
def handle_sql_reserved_word(self, column_name):
|
226
|
+
"""
|
227
|
+
Verify if the column name is a SQL reserved word
|
228
|
+
and raise an error if it is.
|
229
|
+
|
230
|
+
Args:
|
231
|
+
column_name (str): Column name to verify
|
232
|
+
|
233
|
+
Returns:
|
234
|
+
str: The same column name if it is not a reserved word
|
235
|
+
|
236
|
+
Raises:
|
237
|
+
ComponentError: If the column name is a SQL reserved word
|
238
|
+
"""
|
239
|
+
if column_name.lower() in SQL_RESERVED_WORDS:
|
240
|
+
error_msg = (f"Column name '{column_name}' is a SQL reserved word. "
|
241
|
+
f"Please use 'replace_names' to change this column name.")
|
242
|
+
self._logger.error(error_msg)
|
243
|
+
raise ComponentError(error_msg)
|
244
|
+
return column_name
|
245
|
+
|
246
|
+
async def run(self):
|
247
|
+
self.result = None
|
248
|
+
if not hasattr(self, "mime"):
|
249
|
+
self.mime = "text/csv"
|
250
|
+
if self.filename:
|
251
|
+
if self.mime in excel_based:
|
252
|
+
if (
|
253
|
+
self.mime == "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
|
254
|
+
):
|
255
|
+
# xlsx or any openxml based document
|
256
|
+
file_engine = self.params.get("file_engine", "openpyxl")
|
257
|
+
elif (
|
258
|
+
self.mime == "application/vnd.ms-excel.sheet.binary.macroEnabled.12"
|
259
|
+
):
|
260
|
+
file_engine = self.params.get("file_engine", "pyxlsb")
|
261
|
+
else:
|
262
|
+
try:
|
263
|
+
ext = self.filename.suffix
|
264
|
+
except (AttributeError, ValueError):
|
265
|
+
ext = ".xls"
|
266
|
+
if ext == ".xls":
|
267
|
+
file_engine = self.params.get("file_engine", "xlrd")
|
268
|
+
else:
|
269
|
+
file_engine = self.params.get("file_engine", "openpyxl")
|
270
|
+
# passed arguments to Pandas directly
|
271
|
+
arguments = {**self.params}
|
272
|
+
if hasattr(self, "pd_args") and isinstance(self.pd_args, dict):
|
273
|
+
arguments = {**self.params, **self.pd_args}
|
274
|
+
df = pd.read_excel(
|
275
|
+
self.filename,
|
276
|
+
engine=file_engine,
|
277
|
+
keep_default_na=True,
|
278
|
+
na_filter=False,
|
279
|
+
**arguments,
|
280
|
+
)
|
281
|
+
else:
|
282
|
+
self.params = {"infer_datetime_format": True}
|
283
|
+
arguments = {**self.params}
|
284
|
+
if hasattr(self, "pd_args") and isinstance(self.pd_args, dict):
|
285
|
+
arguments = {**self.params, **self.pd_args}
|
286
|
+
try:
|
287
|
+
# can we use pyarrow.
|
288
|
+
engine = arguments["engine"]
|
289
|
+
del arguments["engine"]
|
290
|
+
except KeyError:
|
291
|
+
engine = "c"
|
292
|
+
tp = pd.read_csv(
|
293
|
+
self.filename,
|
294
|
+
sep=self.separator,
|
295
|
+
decimal=",",
|
296
|
+
engine=engine,
|
297
|
+
keep_default_na=False,
|
298
|
+
na_values=["TBD", "NULL", "null"],
|
299
|
+
na_filter=True,
|
300
|
+
skipinitialspace=True,
|
301
|
+
iterator=True,
|
302
|
+
chunksize=1000,
|
303
|
+
**arguments,
|
304
|
+
)
|
305
|
+
df = pd.concat(tp, ignore_index=True)
|
306
|
+
# read filename from self.filename
|
307
|
+
self._result = self.filename
|
308
|
+
elif self.data is not None:
|
309
|
+
# is already a dataframe:
|
310
|
+
df = self.data
|
311
|
+
self._result = self.data
|
312
|
+
else:
|
313
|
+
return False
|
314
|
+
if df is None or df.empty:
|
315
|
+
raise DataNotFound(f"Empty File or Data: {self.filename}")
|
316
|
+
# adding stat from dataframe:
|
317
|
+
pd.set_option("display.float_format", lambda x: "%.3f" % x)
|
318
|
+
self.add_metric("COLUMNS", df.columns)
|
319
|
+
self.add_metric("ROWS", len(df.index))
|
320
|
+
# removing empty cols
|
321
|
+
if hasattr(self, "drop_empty"):
|
322
|
+
df.dropna(axis="columns", how="all", inplace=True)
|
323
|
+
df = df.loc[:, ~df.columns.str.contains("^Unnamed")]
|
324
|
+
if hasattr(self, "dropna"):
|
325
|
+
df.dropna(subset=self.dropna, how="all", inplace=True)
|
326
|
+
if hasattr(self, "trim"):
|
327
|
+
cols = list(df.columns)
|
328
|
+
for col in cols:
|
329
|
+
df[col] = df[col].astype(str).str.strip()
|
330
|
+
if self._debug:
|
331
|
+
print(df)
|
332
|
+
# print('COLS: >> ', df.columns)
|
333
|
+
columns = df.columns
|
334
|
+
cols = []
|
335
|
+
replaced_columns = list(self.replace_names.keys())
|
336
|
+
if hasattr(self, "pre_rename"):
|
337
|
+
### can rename columns PREVIOUS TO normalize
|
338
|
+
for col in columns:
|
339
|
+
datatype = df.dtypes[col]
|
340
|
+
try:
|
341
|
+
t = dtypes[datatype]
|
342
|
+
except KeyError:
|
343
|
+
t = str
|
344
|
+
if col in self.pre_rename:
|
345
|
+
col = self.pre_rename[col]
|
346
|
+
col = self.rename_repeated_col(col, cols)
|
347
|
+
col = self.handle_sql_reserved_word(col)
|
348
|
+
f = (col, t)
|
349
|
+
cols.append(f)
|
350
|
+
elif hasattr(self, "normalize_names"):
|
351
|
+
for col in columns:
|
352
|
+
datatypes = str(df.dtypes[col])
|
353
|
+
t = str
|
354
|
+
tmp_col = col
|
355
|
+
try:
|
356
|
+
t = dtypes[datatypes]
|
357
|
+
data = df[col].iloc[0]
|
358
|
+
if datatypes == "object":
|
359
|
+
# try to infer datatype:
|
360
|
+
if isinstance(data, str) and data != np.nan:
|
361
|
+
if data.isalpha():
|
362
|
+
t = str
|
363
|
+
else:
|
364
|
+
try:
|
365
|
+
dt = dateparser.parse(
|
366
|
+
str(data), settings={"TIMEZONE": "UTC"}
|
367
|
+
)
|
368
|
+
if isinstance(dt, datetime.datetime):
|
369
|
+
t = datetime.datetime
|
370
|
+
except (ValueError, TypeError):
|
371
|
+
pass
|
372
|
+
except KeyError:
|
373
|
+
t = str
|
374
|
+
|
375
|
+
if isinstance(col, (datetime.datetime, datetime.date)):
|
376
|
+
mask = getattr(self, "mask_datetime", "%b_%d_%Y")
|
377
|
+
new_name = datetime_to_name(col, mask)
|
378
|
+
elif is_snakecase(col):
|
379
|
+
new_name = col.strip().lower()
|
380
|
+
elif is_camelcase(col):
|
381
|
+
new_name = "_".join(
|
382
|
+
[x.lower().strip() for x in camelcase_split(col)]
|
383
|
+
)
|
384
|
+
else:
|
385
|
+
new_name = re.sub(r"[^a-zA-Z0-9_]", "", col).strip()
|
386
|
+
if hasattr(self, "normalize"):
|
387
|
+
## making some changes on col_name:
|
388
|
+
if (
|
389
|
+
"remove_prefix" in self.normalize and self.normalize["remove_prefix"]
|
390
|
+
):
|
391
|
+
prefix = self.normalize["remove_prefix"]
|
392
|
+
new_name = new_name.removeprefix(prefix)
|
393
|
+
if "trim" in self.normalize and self.normalize["trim"] is True:
|
394
|
+
new_name = new_name.strip()
|
395
|
+
### remove any illegal character
|
396
|
+
new_name = remove_illegal_chars(new_name)
|
397
|
+
# re-covert again from camelCase:
|
398
|
+
if (
|
399
|
+
"camelcase" in self.normalize and self.normalize["camelcase"] is True
|
400
|
+
):
|
401
|
+
new_name = new_name.replace(" ", "").translate(
|
402
|
+
str.maketrans("", "", "/:.")
|
403
|
+
)
|
404
|
+
new_name = re.sub(r"\([^)]*\)", "", new_name)
|
405
|
+
else:
|
406
|
+
new_name = "_".join(
|
407
|
+
[x.lower().strip() for x in camelcase_split(new_name)]
|
408
|
+
)
|
409
|
+
|
410
|
+
# Log names after basic normalization but before replace_names
|
411
|
+
if self._debug:
|
412
|
+
# Store initial normalizations for later display
|
413
|
+
if not hasattr(self, '_initial_normalizations'):
|
414
|
+
self._initial_normalizations = []
|
415
|
+
|
416
|
+
# Get type as string
|
417
|
+
type_str = getattr(t, "__name__", str(t))
|
418
|
+
|
419
|
+
# Get a sample value from the original column
|
420
|
+
sample_value = "N/A"
|
421
|
+
try:
|
422
|
+
if len(df) > 0 and col in df.columns:
|
423
|
+
sample_value = df[col].iloc[0]
|
424
|
+
except:
|
425
|
+
pass
|
426
|
+
|
427
|
+
# Store information for later display
|
428
|
+
self._initial_normalizations.append((new_name, type_str, sample_value))
|
429
|
+
|
430
|
+
# RENAMING THE COLUMN WITH A NEW NAME:
|
431
|
+
if new_name in replaced_columns:
|
432
|
+
replace = self.replace_names[new_name]
|
433
|
+
if isinstance(replace, str):
|
434
|
+
new_name = self.replace_names[new_name]
|
435
|
+
elif isinstance(replace, dict):
|
436
|
+
if "name" in replace:
|
437
|
+
new_name = replace["name"]
|
438
|
+
if "type" in replace:
|
439
|
+
try:
|
440
|
+
t = dtypes[replace["type"]]
|
441
|
+
except KeyError:
|
442
|
+
self._logger.warning(
|
443
|
+
f"Type '{replace['type']}' not found in dtypes for column '{new_name}', using default type."
|
444
|
+
)
|
445
|
+
else:
|
446
|
+
self._logger.warning(
|
447
|
+
f"Invalid replace_names value for '{new_name}': expected string or dict, got {type(replace).__name__}"
|
448
|
+
)
|
449
|
+
if new_name in self.fields:
|
450
|
+
t = dtypes[self.fields[new_name]]
|
451
|
+
new_name = self.rename_repeated_col(new_name, cols)
|
452
|
+
f = (new_name, t)
|
453
|
+
cols.append(f)
|
454
|
+
if tmp_col == new_name:
|
455
|
+
self._logger.warning(
|
456
|
+
f"The Column '{new_name}' has not normalized"
|
457
|
+
)
|
458
|
+
else:
|
459
|
+
self._logger.debug(
|
460
|
+
f" - Normalized Name: {new_name}"
|
461
|
+
)
|
462
|
+
else:
|
463
|
+
for col in columns:
|
464
|
+
datatype = df.dtypes[col]
|
465
|
+
try:
|
466
|
+
t = dtypes[datatype]
|
467
|
+
except KeyError:
|
468
|
+
t = str
|
469
|
+
col = self.rename_repeated_col(col, cols)
|
470
|
+
f = (col, t)
|
471
|
+
cols.append(f)
|
472
|
+
try:
|
473
|
+
cls = Model.make_model(
|
474
|
+
name=self.tablename,
|
475
|
+
schema=self.schema,
|
476
|
+
fields=cols
|
477
|
+
)
|
478
|
+
# Show all collected information in clean format
|
479
|
+
if hasattr(self, '_debug') and self._debug and hasattr(self, '_initial_normalizations'):
|
480
|
+
print("\n::: First Normalization columns === ")
|
481
|
+
for name, type_str, value in self._initial_normalizations:
|
482
|
+
print(f"{name} -> {type_str} -> {value}")
|
483
|
+
print("=== End :::\n")
|
484
|
+
except Exception as err:
|
485
|
+
print("ERROR:", err)
|
486
|
+
raise ComponentError(str(err)) from err
|
487
|
+
if cls:
|
488
|
+
mdl = cls() # empty model, I only need the schema
|
489
|
+
# TODO: open the metadata table and compare with model
|
490
|
+
if sql := mdl.model(dialect="sql"):
|
491
|
+
print("SQL IS ", sql)
|
492
|
+
|
493
|
+
try:
|
494
|
+
connection = await self.create_connection(driver=self._driver)
|
495
|
+
|
496
|
+
async with await connection.connection() as conn:
|
497
|
+
|
498
|
+
if self.drop is True:
|
499
|
+
self._logger.info(f"Dropping table {self.schema}.{self.tablename}")
|
500
|
+
result, error = await conn.execute(
|
501
|
+
sentence=f"DROP TABLE IF EXISTS {self.schema}.{self.tablename};"
|
502
|
+
)
|
503
|
+
|
504
|
+
self._logger.info(f"Creating table {self.schema}.{self.tablename}")
|
505
|
+
result, error = await conn.execute(sentence=sql)
|
506
|
+
if error:
|
507
|
+
self._logger.error(f"Error creating table: {error}")
|
508
|
+
raise ComponentError(f"Error on Table creation: {error}")
|
509
|
+
else:
|
510
|
+
self.add_metric("Table", result)
|
511
|
+
self._logger.info(f"Table {self.schema}.{self.tablename} created successfully")
|
512
|
+
if self._debug is True:
|
513
|
+
logging.debug(f"TableSchema: {result!s}")
|
514
|
+
|
515
|
+
# add Primary Key to table:
|
516
|
+
if hasattr(self, "pk"):
|
517
|
+
pk = pk_sentence.format(
|
518
|
+
schema=self.schema,
|
519
|
+
table=self.tablename,
|
520
|
+
fields=",".join(self.pk),
|
521
|
+
)
|
522
|
+
self._logger.info(f"Adding primary key on columns: {self.pk}")
|
523
|
+
_primary, error = await conn.execute(sentence=pk)
|
524
|
+
if error:
|
525
|
+
self._logger.warning(f"Error adding primary key: {error}")
|
526
|
+
else:
|
527
|
+
self._logger.info("Primary key added successfully")
|
528
|
+
logging.debug(f"TableSchema: PK creation: {_primary}, {error}")
|
529
|
+
except Exception as err:
|
530
|
+
self._logger.error(f"Error connecting to database: {err}")
|
531
|
+
raise ComponentError(f"Error on database connection: {err}") from err
|
532
|
+
# passthrough the previous component value:
|
533
|
+
self._result = self.input
|
534
|
+
return self.input
|