flowtask 5.8.4__cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- flowtask/__init__.py +93 -0
- flowtask/__main__.py +38 -0
- flowtask/bots/__init__.py +6 -0
- flowtask/bots/check.py +93 -0
- flowtask/bots/codebot.py +51 -0
- flowtask/components/ASPX.py +148 -0
- flowtask/components/AddDataset.py +352 -0
- flowtask/components/Amazon.py +523 -0
- flowtask/components/AutoTask.py +314 -0
- flowtask/components/Azure.py +80 -0
- flowtask/components/AzureUsers.py +106 -0
- flowtask/components/BaseAction.py +91 -0
- flowtask/components/BaseLoop.py +198 -0
- flowtask/components/BestBuy.py +800 -0
- flowtask/components/CSVToGCS.py +120 -0
- flowtask/components/CompanyScraper/__init__.py +1 -0
- flowtask/components/CompanyScraper/parsers/__init__.py +6 -0
- flowtask/components/CompanyScraper/parsers/base.py +102 -0
- flowtask/components/CompanyScraper/parsers/explorium.py +192 -0
- flowtask/components/CompanyScraper/parsers/leadiq.py +206 -0
- flowtask/components/CompanyScraper/parsers/rocket.py +133 -0
- flowtask/components/CompanyScraper/parsers/siccode.py +109 -0
- flowtask/components/CompanyScraper/parsers/visualvisitor.py +130 -0
- flowtask/components/CompanyScraper/parsers/zoominfo.py +118 -0
- flowtask/components/CompanyScraper/scrapper.py +1054 -0
- flowtask/components/CopyTo.py +177 -0
- flowtask/components/CopyToBigQuery.py +243 -0
- flowtask/components/CopyToMongoDB.py +291 -0
- flowtask/components/CopyToPg.py +609 -0
- flowtask/components/CopyToRethink.py +207 -0
- flowtask/components/CreateGCSBucket.py +102 -0
- flowtask/components/CreateReport/CreateReport.py +228 -0
- flowtask/components/CreateReport/__init__.py +9 -0
- flowtask/components/CreateReport/charts/__init__.py +15 -0
- flowtask/components/CreateReport/charts/bar.py +51 -0
- flowtask/components/CreateReport/charts/base.py +66 -0
- flowtask/components/CreateReport/charts/pie.py +64 -0
- flowtask/components/CreateReport/utils.py +9 -0
- flowtask/components/CustomerSatisfaction.py +196 -0
- flowtask/components/DataInput.py +200 -0
- flowtask/components/DateList.py +255 -0
- flowtask/components/DbClient.py +163 -0
- flowtask/components/DialPad.py +146 -0
- flowtask/components/DocumentDBQuery.py +200 -0
- flowtask/components/DownloadFrom.py +371 -0
- flowtask/components/DownloadFromD2L.py +113 -0
- flowtask/components/DownloadFromFTP.py +181 -0
- flowtask/components/DownloadFromIMAP.py +315 -0
- flowtask/components/DownloadFromS3.py +198 -0
- flowtask/components/DownloadFromSFTP.py +265 -0
- flowtask/components/DownloadFromSharepoint.py +110 -0
- flowtask/components/DownloadFromSmartSheet.py +114 -0
- flowtask/components/DownloadS3File.py +229 -0
- flowtask/components/Dummy.py +59 -0
- flowtask/components/DuplicatePhoto.py +411 -0
- flowtask/components/EmployeeEvaluation.py +237 -0
- flowtask/components/ExecuteSQL.py +323 -0
- flowtask/components/ExtractHTML.py +178 -0
- flowtask/components/FileBase.py +178 -0
- flowtask/components/FileCopy.py +181 -0
- flowtask/components/FileDelete.py +82 -0
- flowtask/components/FileExists.py +146 -0
- flowtask/components/FileIteratorDelete.py +112 -0
- flowtask/components/FileList.py +194 -0
- flowtask/components/FileOpen.py +75 -0
- flowtask/components/FileRead.py +120 -0
- flowtask/components/FileRename.py +106 -0
- flowtask/components/FilterIf.py +284 -0
- flowtask/components/FilterRows/FilterRows.py +200 -0
- flowtask/components/FilterRows/__init__.py +10 -0
- flowtask/components/FilterRows/functions.py +4 -0
- flowtask/components/GCSToBigQuery.py +103 -0
- flowtask/components/GoogleA4.py +150 -0
- flowtask/components/GoogleGeoCoding.py +344 -0
- flowtask/components/GooglePlaces.py +315 -0
- flowtask/components/GoogleSearch.py +539 -0
- flowtask/components/HTTPClient.py +268 -0
- flowtask/components/ICIMS.py +146 -0
- flowtask/components/IF.py +179 -0
- flowtask/components/IcimsFolderCopy.py +173 -0
- flowtask/components/ImageFeatures/__init__.py +5 -0
- flowtask/components/ImageFeatures/process.py +233 -0
- flowtask/components/IteratorBase.py +251 -0
- flowtask/components/LangchainLoader/__init__.py +5 -0
- flowtask/components/LangchainLoader/loader.py +194 -0
- flowtask/components/LangchainLoader/loaders/__init__.py +22 -0
- flowtask/components/LangchainLoader/loaders/abstract.py +362 -0
- flowtask/components/LangchainLoader/loaders/basepdf.py +50 -0
- flowtask/components/LangchainLoader/loaders/docx.py +91 -0
- flowtask/components/LangchainLoader/loaders/html.py +119 -0
- flowtask/components/LangchainLoader/loaders/pdfblocks.py +146 -0
- flowtask/components/LangchainLoader/loaders/pdfmark.py +79 -0
- flowtask/components/LangchainLoader/loaders/pdftables.py +135 -0
- flowtask/components/LangchainLoader/loaders/qa.py +67 -0
- flowtask/components/LangchainLoader/loaders/txt.py +55 -0
- flowtask/components/LeadIQ.py +650 -0
- flowtask/components/Loop.py +253 -0
- flowtask/components/Lowes.py +334 -0
- flowtask/components/MS365Usage.py +156 -0
- flowtask/components/MSTeamsMessages.py +320 -0
- flowtask/components/MarketClustering.py +1051 -0
- flowtask/components/MergeFiles.py +362 -0
- flowtask/components/MilvusOutput.py +87 -0
- flowtask/components/NearByStores.py +175 -0
- flowtask/components/NetworkNinja/__init__.py +6 -0
- flowtask/components/NetworkNinja/models/__init__.py +52 -0
- flowtask/components/NetworkNinja/models/abstract.py +177 -0
- flowtask/components/NetworkNinja/models/account.py +39 -0
- flowtask/components/NetworkNinja/models/client.py +19 -0
- flowtask/components/NetworkNinja/models/district.py +14 -0
- flowtask/components/NetworkNinja/models/events.py +101 -0
- flowtask/components/NetworkNinja/models/forms.py +499 -0
- flowtask/components/NetworkNinja/models/market.py +16 -0
- flowtask/components/NetworkNinja/models/organization.py +34 -0
- flowtask/components/NetworkNinja/models/photos.py +125 -0
- flowtask/components/NetworkNinja/models/project.py +44 -0
- flowtask/components/NetworkNinja/models/region.py +28 -0
- flowtask/components/NetworkNinja/models/store.py +203 -0
- flowtask/components/NetworkNinja/models/user.py +151 -0
- flowtask/components/NetworkNinja/router.py +854 -0
- flowtask/components/Odoo.py +175 -0
- flowtask/components/OdooInjector.py +192 -0
- flowtask/components/OpenFromXML.py +126 -0
- flowtask/components/OpenWeather.py +41 -0
- flowtask/components/OpenWithBase.py +616 -0
- flowtask/components/OpenWithPandas.py +715 -0
- flowtask/components/PGPDecrypt.py +199 -0
- flowtask/components/PandasIterator.py +187 -0
- flowtask/components/PandasToFile.py +189 -0
- flowtask/components/Paradox.py +339 -0
- flowtask/components/ParamIterator.py +117 -0
- flowtask/components/ParseHTML.py +84 -0
- flowtask/components/PlacerStores.py +249 -0
- flowtask/components/Pokemon.py +507 -0
- flowtask/components/PositiveBot.py +62 -0
- flowtask/components/PowerPointSlide.py +400 -0
- flowtask/components/PrintMessage.py +127 -0
- flowtask/components/ProductCompetitors/__init__.py +5 -0
- flowtask/components/ProductCompetitors/parsers/__init__.py +7 -0
- flowtask/components/ProductCompetitors/parsers/base.py +72 -0
- flowtask/components/ProductCompetitors/parsers/bestbuy.py +86 -0
- flowtask/components/ProductCompetitors/parsers/lowes.py +103 -0
- flowtask/components/ProductCompetitors/scrapper.py +155 -0
- flowtask/components/ProductCompliant.py +169 -0
- flowtask/components/ProductInfo/__init__.py +1 -0
- flowtask/components/ProductInfo/parsers/__init__.py +5 -0
- flowtask/components/ProductInfo/parsers/base.py +83 -0
- flowtask/components/ProductInfo/parsers/brother.py +97 -0
- flowtask/components/ProductInfo/parsers/canon.py +167 -0
- flowtask/components/ProductInfo/parsers/epson.py +118 -0
- flowtask/components/ProductInfo/parsers/hp.py +131 -0
- flowtask/components/ProductInfo/parsers/samsung.py +97 -0
- flowtask/components/ProductInfo/scraper.py +319 -0
- flowtask/components/ProductPricing.py +118 -0
- flowtask/components/QS.py +261 -0
- flowtask/components/QSBase.py +201 -0
- flowtask/components/QueryIterator.py +273 -0
- flowtask/components/QueryToInsert.py +327 -0
- flowtask/components/QueryToPandas.py +432 -0
- flowtask/components/RESTClient.py +195 -0
- flowtask/components/RethinkDBQuery.py +189 -0
- flowtask/components/Rsync.py +74 -0
- flowtask/components/RunSSH.py +59 -0
- flowtask/components/RunShell.py +71 -0
- flowtask/components/SalesForce.py +20 -0
- flowtask/components/SaveImageBank/__init__.py +257 -0
- flowtask/components/SchedulingVisits.py +592 -0
- flowtask/components/ScrapPage.py +216 -0
- flowtask/components/ScrapSearch.py +79 -0
- flowtask/components/SendNotify.py +257 -0
- flowtask/components/SentimentAnalysis.py +694 -0
- flowtask/components/ServiceScrapper/__init__.py +5 -0
- flowtask/components/ServiceScrapper/parsers/__init__.py +1 -0
- flowtask/components/ServiceScrapper/parsers/base.py +94 -0
- flowtask/components/ServiceScrapper/parsers/costco.py +93 -0
- flowtask/components/ServiceScrapper/scrapper.py +199 -0
- flowtask/components/SetVariables.py +156 -0
- flowtask/components/SubTask.py +182 -0
- flowtask/components/SuiteCRM.py +48 -0
- flowtask/components/Switch.py +175 -0
- flowtask/components/TableBase.py +148 -0
- flowtask/components/TableDelete.py +312 -0
- flowtask/components/TableInput.py +143 -0
- flowtask/components/TableOutput/TableOutput.py +384 -0
- flowtask/components/TableOutput/__init__.py +3 -0
- flowtask/components/TableSchema.py +534 -0
- flowtask/components/Target.py +223 -0
- flowtask/components/ThumbnailGenerator.py +156 -0
- flowtask/components/ToPandas.py +67 -0
- flowtask/components/TransformRows/TransformRows.py +507 -0
- flowtask/components/TransformRows/__init__.py +9 -0
- flowtask/components/TransformRows/functions.py +559 -0
- flowtask/components/TransposeRows.py +176 -0
- flowtask/components/UPCDatabase.py +86 -0
- flowtask/components/UnGzip.py +171 -0
- flowtask/components/Uncompress.py +172 -0
- flowtask/components/UniqueRows.py +126 -0
- flowtask/components/Unzip.py +107 -0
- flowtask/components/UpdateOperationalVars.py +147 -0
- flowtask/components/UploadTo.py +299 -0
- flowtask/components/UploadToS3.py +136 -0
- flowtask/components/UploadToSFTP.py +160 -0
- flowtask/components/UploadToSharepoint.py +205 -0
- flowtask/components/UserFunc.py +122 -0
- flowtask/components/VivaTracker.py +140 -0
- flowtask/components/WSDLClient.py +123 -0
- flowtask/components/Wait.py +18 -0
- flowtask/components/Walmart.py +199 -0
- flowtask/components/Workplace.py +134 -0
- flowtask/components/XMLToPandas.py +267 -0
- flowtask/components/Zammad/__init__.py +41 -0
- flowtask/components/Zammad/models.py +0 -0
- flowtask/components/ZoomInfoScraper.py +409 -0
- flowtask/components/__init__.py +104 -0
- flowtask/components/abstract.py +18 -0
- flowtask/components/flow.py +530 -0
- flowtask/components/google.py +335 -0
- flowtask/components/group.py +221 -0
- flowtask/components/py.typed +0 -0
- flowtask/components/reviewscrap.py +132 -0
- flowtask/components/tAutoincrement.py +117 -0
- flowtask/components/tConcat.py +109 -0
- flowtask/components/tExplode.py +119 -0
- flowtask/components/tFilter.py +184 -0
- flowtask/components/tGroup.py +236 -0
- flowtask/components/tJoin.py +270 -0
- flowtask/components/tMap/__init__.py +9 -0
- flowtask/components/tMap/functions.py +54 -0
- flowtask/components/tMap/tMap.py +450 -0
- flowtask/components/tMelt.py +112 -0
- flowtask/components/tMerge.py +114 -0
- flowtask/components/tOrder.py +93 -0
- flowtask/components/tPandas.py +94 -0
- flowtask/components/tPivot.py +71 -0
- flowtask/components/tPluckCols.py +76 -0
- flowtask/components/tUnnest.py +82 -0
- flowtask/components/user.py +401 -0
- flowtask/conf.py +457 -0
- flowtask/download.py +102 -0
- flowtask/events/__init__.py +11 -0
- flowtask/events/events/__init__.py +20 -0
- flowtask/events/events/abstract.py +95 -0
- flowtask/events/events/alerts/__init__.py +362 -0
- flowtask/events/events/alerts/colfunctions.py +131 -0
- flowtask/events/events/alerts/functions.py +158 -0
- flowtask/events/events/dummy.py +12 -0
- flowtask/events/events/exec.py +124 -0
- flowtask/events/events/file/__init__.py +7 -0
- flowtask/events/events/file/base.py +51 -0
- flowtask/events/events/file/copy.py +23 -0
- flowtask/events/events/file/delete.py +16 -0
- flowtask/events/events/interfaces/__init__.py +9 -0
- flowtask/events/events/interfaces/client.py +67 -0
- flowtask/events/events/interfaces/credentials.py +28 -0
- flowtask/events/events/interfaces/notifications.py +58 -0
- flowtask/events/events/jira.py +122 -0
- flowtask/events/events/log.py +26 -0
- flowtask/events/events/logerr.py +52 -0
- flowtask/events/events/notify.py +59 -0
- flowtask/events/events/notify_event.py +160 -0
- flowtask/events/events/publish.py +54 -0
- flowtask/events/events/sendfile.py +104 -0
- flowtask/events/events/task.py +97 -0
- flowtask/events/events/teams.py +98 -0
- flowtask/events/events/webhook.py +58 -0
- flowtask/events/manager.py +287 -0
- flowtask/exceptions.c +39393 -0
- flowtask/exceptions.cpython-312-x86_64-linux-gnu.so +0 -0
- flowtask/extensions/__init__.py +3 -0
- flowtask/extensions/abstract.py +82 -0
- flowtask/extensions/logging/__init__.py +65 -0
- flowtask/hooks/__init__.py +9 -0
- flowtask/hooks/actions/__init__.py +22 -0
- flowtask/hooks/actions/abstract.py +66 -0
- flowtask/hooks/actions/dummy.py +23 -0
- flowtask/hooks/actions/jira.py +74 -0
- flowtask/hooks/actions/rest.py +320 -0
- flowtask/hooks/actions/sampledata.py +37 -0
- flowtask/hooks/actions/sensor.py +23 -0
- flowtask/hooks/actions/task.py +9 -0
- flowtask/hooks/actions/ticket.py +37 -0
- flowtask/hooks/actions/zammad.py +55 -0
- flowtask/hooks/hook.py +62 -0
- flowtask/hooks/models.py +17 -0
- flowtask/hooks/service.py +187 -0
- flowtask/hooks/step.py +91 -0
- flowtask/hooks/types/__init__.py +23 -0
- flowtask/hooks/types/base.py +129 -0
- flowtask/hooks/types/brokers/__init__.py +11 -0
- flowtask/hooks/types/brokers/base.py +54 -0
- flowtask/hooks/types/brokers/mqtt.py +35 -0
- flowtask/hooks/types/brokers/rabbitmq.py +82 -0
- flowtask/hooks/types/brokers/redis.py +83 -0
- flowtask/hooks/types/brokers/sqs.py +44 -0
- flowtask/hooks/types/fs.py +232 -0
- flowtask/hooks/types/http.py +49 -0
- flowtask/hooks/types/imap.py +200 -0
- flowtask/hooks/types/jira.py +279 -0
- flowtask/hooks/types/mail.py +205 -0
- flowtask/hooks/types/postgres.py +98 -0
- flowtask/hooks/types/responses/__init__.py +8 -0
- flowtask/hooks/types/responses/base.py +5 -0
- flowtask/hooks/types/sharepoint.py +288 -0
- flowtask/hooks/types/ssh.py +141 -0
- flowtask/hooks/types/tagged.py +59 -0
- flowtask/hooks/types/upload.py +85 -0
- flowtask/hooks/types/watch.py +71 -0
- flowtask/hooks/types/web.py +36 -0
- flowtask/interfaces/AzureClient.py +137 -0
- flowtask/interfaces/AzureGraph.py +839 -0
- flowtask/interfaces/Boto3Client.py +326 -0
- flowtask/interfaces/DropboxClient.py +173 -0
- flowtask/interfaces/ExcelHandler.py +94 -0
- flowtask/interfaces/FTPClient.py +131 -0
- flowtask/interfaces/GoogleCalendar.py +201 -0
- flowtask/interfaces/GoogleClient.py +133 -0
- flowtask/interfaces/GoogleDrive.py +127 -0
- flowtask/interfaces/GoogleGCS.py +89 -0
- flowtask/interfaces/GoogleGeocoding.py +93 -0
- flowtask/interfaces/GoogleLang.py +114 -0
- flowtask/interfaces/GooglePub.py +61 -0
- flowtask/interfaces/GoogleSheet.py +68 -0
- flowtask/interfaces/IMAPClient.py +137 -0
- flowtask/interfaces/O365Calendar.py +113 -0
- flowtask/interfaces/O365Client.py +220 -0
- flowtask/interfaces/OneDrive.py +284 -0
- flowtask/interfaces/Outlook.py +155 -0
- flowtask/interfaces/ParrotBot.py +130 -0
- flowtask/interfaces/SSHClient.py +378 -0
- flowtask/interfaces/Sharepoint.py +496 -0
- flowtask/interfaces/__init__.py +36 -0
- flowtask/interfaces/azureauth.py +119 -0
- flowtask/interfaces/cache.py +201 -0
- flowtask/interfaces/client.py +82 -0
- flowtask/interfaces/compress.py +525 -0
- flowtask/interfaces/credentials.py +124 -0
- flowtask/interfaces/d2l.py +239 -0
- flowtask/interfaces/databases/__init__.py +5 -0
- flowtask/interfaces/databases/db.py +223 -0
- flowtask/interfaces/databases/documentdb.py +55 -0
- flowtask/interfaces/databases/rethink.py +39 -0
- flowtask/interfaces/dataframes/__init__.py +11 -0
- flowtask/interfaces/dataframes/abstract.py +21 -0
- flowtask/interfaces/dataframes/arrow.py +71 -0
- flowtask/interfaces/dataframes/dt.py +69 -0
- flowtask/interfaces/dataframes/pandas.py +167 -0
- flowtask/interfaces/dataframes/polars.py +60 -0
- flowtask/interfaces/db.py +263 -0
- flowtask/interfaces/env.py +46 -0
- flowtask/interfaces/func.py +137 -0
- flowtask/interfaces/http.py +1780 -0
- flowtask/interfaces/locale.py +40 -0
- flowtask/interfaces/log.py +75 -0
- flowtask/interfaces/mask.py +143 -0
- flowtask/interfaces/notification.py +154 -0
- flowtask/interfaces/playwright.py +339 -0
- flowtask/interfaces/powerpoint.py +368 -0
- flowtask/interfaces/py.typed +0 -0
- flowtask/interfaces/qs.py +376 -0
- flowtask/interfaces/result.py +87 -0
- flowtask/interfaces/selenium_service.py +779 -0
- flowtask/interfaces/smartsheet.py +154 -0
- flowtask/interfaces/stat.py +39 -0
- flowtask/interfaces/task.py +96 -0
- flowtask/interfaces/template.py +118 -0
- flowtask/interfaces/vectorstores/__init__.py +1 -0
- flowtask/interfaces/vectorstores/abstract.py +133 -0
- flowtask/interfaces/vectorstores/milvus.py +669 -0
- flowtask/interfaces/zammad.py +107 -0
- flowtask/models.py +193 -0
- flowtask/parsers/__init__.py +15 -0
- flowtask/parsers/_yaml.c +11978 -0
- flowtask/parsers/_yaml.cpython-312-x86_64-linux-gnu.so +0 -0
- flowtask/parsers/argparser.py +235 -0
- flowtask/parsers/base.c +15155 -0
- flowtask/parsers/base.cpython-312-x86_64-linux-gnu.so +0 -0
- flowtask/parsers/json.c +11968 -0
- flowtask/parsers/json.cpython-312-x86_64-linux-gnu.so +0 -0
- flowtask/parsers/maps.py +49 -0
- flowtask/parsers/toml.c +11968 -0
- flowtask/parsers/toml.cpython-312-x86_64-linux-gnu.so +0 -0
- flowtask/plugins/__init__.py +16 -0
- flowtask/plugins/components/__init__.py +0 -0
- flowtask/plugins/handler/__init__.py +45 -0
- flowtask/plugins/importer.py +31 -0
- flowtask/plugins/sources/__init__.py +0 -0
- flowtask/runner.py +283 -0
- flowtask/scheduler/__init__.py +9 -0
- flowtask/scheduler/functions.py +493 -0
- flowtask/scheduler/handlers/__init__.py +8 -0
- flowtask/scheduler/handlers/manager.py +504 -0
- flowtask/scheduler/handlers/models.py +58 -0
- flowtask/scheduler/handlers/service.py +72 -0
- flowtask/scheduler/notifications.py +65 -0
- flowtask/scheduler/scheduler.py +993 -0
- flowtask/services/__init__.py +0 -0
- flowtask/services/bots/__init__.py +0 -0
- flowtask/services/bots/telegram.py +264 -0
- flowtask/services/files/__init__.py +11 -0
- flowtask/services/files/manager.py +522 -0
- flowtask/services/files/model.py +37 -0
- flowtask/services/files/service.py +767 -0
- flowtask/services/jira/__init__.py +3 -0
- flowtask/services/jira/jira_actions.py +191 -0
- flowtask/services/tasks/__init__.py +13 -0
- flowtask/services/tasks/launcher.py +213 -0
- flowtask/services/tasks/manager.py +323 -0
- flowtask/services/tasks/service.py +275 -0
- flowtask/services/tasks/task_manager.py +376 -0
- flowtask/services/tasks/tasks.py +155 -0
- flowtask/storages/__init__.py +16 -0
- flowtask/storages/exceptions.py +12 -0
- flowtask/storages/files/__init__.py +8 -0
- flowtask/storages/files/abstract.py +29 -0
- flowtask/storages/files/filesystem.py +66 -0
- flowtask/storages/tasks/__init__.py +19 -0
- flowtask/storages/tasks/abstract.py +26 -0
- flowtask/storages/tasks/database.py +33 -0
- flowtask/storages/tasks/filesystem.py +108 -0
- flowtask/storages/tasks/github.py +119 -0
- flowtask/storages/tasks/memory.py +45 -0
- flowtask/storages/tasks/row.py +25 -0
- flowtask/tasks/__init__.py +0 -0
- flowtask/tasks/abstract.py +526 -0
- flowtask/tasks/command.py +118 -0
- flowtask/tasks/pile.py +486 -0
- flowtask/tasks/py.typed +0 -0
- flowtask/tasks/task.py +778 -0
- flowtask/template/__init__.py +161 -0
- flowtask/tests.py +257 -0
- flowtask/types/__init__.py +8 -0
- flowtask/types/typedefs.c +11347 -0
- flowtask/types/typedefs.cpython-312-x86_64-linux-gnu.so +0 -0
- flowtask/utils/__init__.py +24 -0
- flowtask/utils/constants.py +117 -0
- flowtask/utils/encoders.py +21 -0
- flowtask/utils/executor.py +112 -0
- flowtask/utils/functions.cpp +14280 -0
- flowtask/utils/functions.cpython-312-x86_64-linux-gnu.so +0 -0
- flowtask/utils/json.cpp +13349 -0
- flowtask/utils/json.cpython-312-x86_64-linux-gnu.so +0 -0
- flowtask/utils/mail.py +63 -0
- flowtask/utils/parseqs.c +13324 -0
- flowtask/utils/parserqs.cpython-312-x86_64-linux-gnu.so +0 -0
- flowtask/utils/stats.py +308 -0
- flowtask/utils/transformations.py +74 -0
- flowtask/utils/uv.py +12 -0
- flowtask/utils/validators.py +97 -0
- flowtask/version.py +11 -0
- flowtask-5.8.4.dist-info/LICENSE +201 -0
- flowtask-5.8.4.dist-info/METADATA +209 -0
- flowtask-5.8.4.dist-info/RECORD +470 -0
- flowtask-5.8.4.dist-info/WHEEL +6 -0
- flowtask-5.8.4.dist-info/entry_points.txt +3 -0
- flowtask-5.8.4.dist-info/top_level.txt +2 -0
- plugins/components/CreateQR.py +39 -0
- plugins/components/TestComponent.py +28 -0
- plugins/components/Use1.py +13 -0
- plugins/components/Workplace.py +117 -0
- plugins/components/__init__.py +3 -0
- plugins/sources/__init__.py +0 -0
- plugins/sources/get_populartimes.py +78 -0
- plugins/sources/google.py +150 -0
- plugins/sources/hubspot.py +679 -0
- plugins/sources/icims.py +679 -0
- plugins/sources/mobileinsight.py +501 -0
- plugins/sources/newrelic.py +262 -0
- plugins/sources/uap.py +268 -0
- plugins/sources/venu.py +244 -0
- plugins/sources/vocinity.py +314 -0
@@ -0,0 +1,362 @@
|
|
1
|
+
import os
|
2
|
+
import logging
|
3
|
+
import asyncio
|
4
|
+
from collections.abc import Callable
|
5
|
+
import types
|
6
|
+
from functools import reduce
|
7
|
+
import pandas as pd
|
8
|
+
import numpy as np
|
9
|
+
import cchardet as chardet
|
10
|
+
from ..exceptions import ComponentError
|
11
|
+
from ..parsers.maps import open_model
|
12
|
+
from .flow import FlowComponent
|
13
|
+
from .OpenWithBase import detect_encoding, excel_based
|
14
|
+
|
15
|
+
|
16
|
+
class MergeFiles(FlowComponent):
|
17
|
+
"""
|
18
|
+
MergeFiles
|
19
|
+
|
20
|
+
Overview
|
21
|
+
|
22
|
+
The MergeFiles class is a component for merging multiple files into a single file or dataframe. It supports various
|
23
|
+
file formats, including CSV, Excel, and HTML, and handles encoding detection and conversion as needed.
|
24
|
+
|
25
|
+
.. table:: Properties
|
26
|
+
:widths: auto
|
27
|
+
|
28
|
+
+------------------+----------+--------------------------------------------------------------------------------------------------+
|
29
|
+
| Name | Required | Description |
|
30
|
+
+------------------+----------+--------------------------------------------------------------------------------------------------+
|
31
|
+
| filename | No | The name of the merged output file. |
|
32
|
+
+------------------+----------+--------------------------------------------------------------------------------------------------+
|
33
|
+
| file | No | The file object to be merged. |
|
34
|
+
+------------------+----------+--------------------------------------------------------------------------------------------------+
|
35
|
+
| filepath | No | The directory path for the merged output file. |
|
36
|
+
+------------------+----------+--------------------------------------------------------------------------------------------------+
|
37
|
+
| ContentType | No | The content type of the files being merged, defaults to "text/csv". |
|
38
|
+
+------------------+----------+--------------------------------------------------------------------------------------------------+
|
39
|
+
| as_dataframe | No | Boolean flag indicating if the result should be returned as a dataframe, defaults to False. |
|
40
|
+
+------------------+----------+--------------------------------------------------------------------------------------------------+
|
41
|
+
|
42
|
+
Return
|
43
|
+
|
44
|
+
The methods in this class manage the merging of files, including initialization, execution, and result handling.
|
45
|
+
|
46
|
+
|
47
|
+
|
48
|
+
Example:
|
49
|
+
|
50
|
+
```yaml
|
51
|
+
MergeFiles:
|
52
|
+
ContentType: application/vnd.ms-excel
|
53
|
+
model: worked_hours
|
54
|
+
pd_args:
|
55
|
+
skiprows: 6
|
56
|
+
as_dataframe: true
|
57
|
+
```
|
58
|
+
|
59
|
+
""" # noqa
|
60
|
+
|
61
|
+
def __init__(
|
62
|
+
self,
|
63
|
+
loop: asyncio.AbstractEventLoop = None,
|
64
|
+
job: Callable = None,
|
65
|
+
stat: Callable = None,
|
66
|
+
**kwargs,
|
67
|
+
) -> None:
|
68
|
+
"""Init Method."""
|
69
|
+
self.filename = ""
|
70
|
+
self.file = None
|
71
|
+
self.filepath = ""
|
72
|
+
self.ContentType: str = "text/csv"
|
73
|
+
self.as_dataframe: bool = False
|
74
|
+
super(MergeFiles, self).__init__(loop=loop, job=job, stat=stat, **kwargs)
|
75
|
+
|
76
|
+
async def start(self, **kwargs):
|
77
|
+
"""
|
78
|
+
start.
|
79
|
+
Start connection.
|
80
|
+
"""
|
81
|
+
if self.previous:
|
82
|
+
try:
|
83
|
+
if isinstance(self.input, list):
|
84
|
+
# is a list of files
|
85
|
+
self.data = self.input
|
86
|
+
elif isinstance(self.input, dict):
|
87
|
+
if "files" in self.input:
|
88
|
+
self.data = self.input["files"]
|
89
|
+
else:
|
90
|
+
self.data = {k: v for k, v in self.input.items()}
|
91
|
+
elif isinstance(self.input, types.GeneratorType):
|
92
|
+
# is a generator:
|
93
|
+
self.data = list(self.input)
|
94
|
+
else:
|
95
|
+
raise ComponentError(
|
96
|
+
"MergeFiles Error: incompatible kind of previous Object."
|
97
|
+
)
|
98
|
+
except Exception as err:
|
99
|
+
raise ComponentError(f"Error Filtering Data {err}") from err
|
100
|
+
self._logger.debug(f"List of Files: {self.data!r}")
|
101
|
+
if hasattr(self, "destination"):
|
102
|
+
# we need to calculated the result filename of this component
|
103
|
+
filename = self.destination["filename"]
|
104
|
+
self.filepath = self.destination["directory"]
|
105
|
+
if hasattr(self, "masks"):
|
106
|
+
for mask, replace in self._mask.items():
|
107
|
+
filename = str(filename).replace(mask, replace)
|
108
|
+
if self._variables:
|
109
|
+
filename = filename.format(**self._variables)
|
110
|
+
self.filename = os.path.join(self.filepath, filename)
|
111
|
+
self.add_metric("MERGED_FILENAME", self.filename)
|
112
|
+
return True
|
113
|
+
|
114
|
+
async def close(self):
|
115
|
+
"""
|
116
|
+
close.
|
117
|
+
|
118
|
+
close method
|
119
|
+
"""
|
120
|
+
|
121
|
+
def _merge_dataframe(self, dfs: list):
|
122
|
+
"""
|
123
|
+
Merges a list of DataFrames based on their common columns.
|
124
|
+
|
125
|
+
Args:
|
126
|
+
dfs: A list of pandas DataFrames.
|
127
|
+
|
128
|
+
Returns:
|
129
|
+
A single merged DataFrame.
|
130
|
+
"""
|
131
|
+
if not hasattr(self, 'use_merge'):
|
132
|
+
# Concatenate the DataFrames
|
133
|
+
return pd.concat(dfs)
|
134
|
+
# Calculate the common columns in all dataframes
|
135
|
+
common_columns = set(dfs[0].columns)
|
136
|
+
for df in dfs[1:]:
|
137
|
+
common_columns = common_columns.intersection(set(df.columns))
|
138
|
+
if not common_columns:
|
139
|
+
raise ComponentError("MergeFiles Error: No common columns found.")
|
140
|
+
if self.use_merge:
|
141
|
+
# Cast column types based on the first dataframe:
|
142
|
+
for df in dfs[1:]:
|
143
|
+
for col in common_columns:
|
144
|
+
df[col] = df[col].astype(dfs[0][col].dtype)
|
145
|
+
merged_df = reduce(
|
146
|
+
lambda left, right: pd.merge(left, right, how='outer', on=list(common_columns)), dfs
|
147
|
+
)
|
148
|
+
# Drop columns with all missing values (empty)
|
149
|
+
merged_df = merged_df.dropna(axis=1, how='all')
|
150
|
+
return merged_df
|
151
|
+
return pd.concat(dfs)
|
152
|
+
|
153
|
+
async def run(self):
|
154
|
+
"""
|
155
|
+
run.
|
156
|
+
|
157
|
+
Run the connection and merge all the files
|
158
|
+
"""
|
159
|
+
np_array_list = []
|
160
|
+
df = None
|
161
|
+
np_array_list = []
|
162
|
+
if isinstance(self.data, list):
|
163
|
+
# is a list of files
|
164
|
+
if self.ContentType in excel_based:
|
165
|
+
args = self.pd_args if hasattr(self, "pd_args") else {}
|
166
|
+
if self.ContentType == "application/vnd.ms-excel":
|
167
|
+
file_engine = "xlrd"
|
168
|
+
elif (
|
169
|
+
self.ContentType
|
170
|
+
== "application/vnd.ms-excel.sheet.binary.macroEnabled.12"
|
171
|
+
):
|
172
|
+
file_engine = "pyxlsb"
|
173
|
+
else:
|
174
|
+
file_engine = "openpyxl"
|
175
|
+
# get the Model (if any):
|
176
|
+
if hasattr(self, "model"):
|
177
|
+
columns = await open_model(self.model, self._program)
|
178
|
+
fields = []
|
179
|
+
dates = []
|
180
|
+
for field, dtype in columns["fields"].items():
|
181
|
+
fields.append(field)
|
182
|
+
try:
|
183
|
+
t = dtype["data_type"]
|
184
|
+
except KeyError:
|
185
|
+
t = "str"
|
186
|
+
if t in {"date", "datetime", "time"}:
|
187
|
+
dates.append(field)
|
188
|
+
args["names"] = fields
|
189
|
+
if dates:
|
190
|
+
args["parse_dates"] = dates
|
191
|
+
files = []
|
192
|
+
file_stats = {}
|
193
|
+
for file in self.data:
|
194
|
+
if not file:
|
195
|
+
continue
|
196
|
+
try:
|
197
|
+
df = pd.read_excel(
|
198
|
+
file,
|
199
|
+
na_values=["TBD", "NULL", "null", "", "#NA"],
|
200
|
+
engine=file_engine,
|
201
|
+
keep_default_na=True,
|
202
|
+
**args,
|
203
|
+
)
|
204
|
+
file_args = {}
|
205
|
+
if hasattr(self, 'file_stats'):
|
206
|
+
first_row = df.iloc[0][self.file_stats['columns']].to_dict()
|
207
|
+
file_args = first_row
|
208
|
+
file_stats[file.name] = {
|
209
|
+
"numrows": len(df.index),
|
210
|
+
**file_args
|
211
|
+
}
|
212
|
+
except TypeError as ex:
|
213
|
+
self._logger.error(f"Merge Excel Error: {ex}")
|
214
|
+
files.append(df)
|
215
|
+
try:
|
216
|
+
self._result = self._merge_dataframe(files)
|
217
|
+
self.add_metric("FILE_STATS", file_stats)
|
218
|
+
self._print_data_(self._result, 'Merged data')
|
219
|
+
if self._debug is True:
|
220
|
+
print("::: Combined File ::: ")
|
221
|
+
print(self._result)
|
222
|
+
if self.as_dataframe is True:
|
223
|
+
numrows = len(self._result)
|
224
|
+
self.add_metric("NUMROWS", numrows)
|
225
|
+
self.add_metric("COLUMNS", self._result.shape[1])
|
226
|
+
return self._result
|
227
|
+
else:
|
228
|
+
# saved as CSV.
|
229
|
+
self._result.to_csv(
|
230
|
+
self.filename, index=False, encoding="utf-8-sig"
|
231
|
+
)
|
232
|
+
self._result = self.filename
|
233
|
+
self.add_metric("MERGED_FILE", self.filename)
|
234
|
+
return self._result
|
235
|
+
except Exception as err:
|
236
|
+
logging.exception(
|
237
|
+
f"Error Merging Excel Files: {err}", stack_info=True
|
238
|
+
)
|
239
|
+
self._result = None
|
240
|
+
return False
|
241
|
+
elif self.ContentType == "text/html":
|
242
|
+
encoding = "utf-8"
|
243
|
+
try:
|
244
|
+
if len(self.data) == 1:
|
245
|
+
# there is no other files to merge:
|
246
|
+
combined_csv = pd.read_html(self.data[0], encoding=encoding)
|
247
|
+
else:
|
248
|
+
dfs = []
|
249
|
+
for f in self.data:
|
250
|
+
try:
|
251
|
+
dt = pd.read_html(f, encoding=encoding)
|
252
|
+
dfs.append(dt[0])
|
253
|
+
except (TypeError, ValueError):
|
254
|
+
continue
|
255
|
+
# combine all files in the list
|
256
|
+
combined_csv = pd.concat(
|
257
|
+
dfs, sort=False, axis=0, ignore_index=True
|
258
|
+
).reindex(dfs[0].index)
|
259
|
+
except UnicodeDecodeError:
|
260
|
+
combined_csv = pd.concat(
|
261
|
+
[pd.read_html(f, encoding="windows-1252") for f in self.data]
|
262
|
+
)
|
263
|
+
except Exception as err:
|
264
|
+
raise ComponentError(f"{err!s}") from err
|
265
|
+
try:
|
266
|
+
if self.as_dataframe is True:
|
267
|
+
self._result = combined_csv
|
268
|
+
self.add_metric("MERGED_DF", self._result.columns)
|
269
|
+
else:
|
270
|
+
# export to csv
|
271
|
+
combined_csv.to_csv(
|
272
|
+
self.filename, index=False, encoding="utf-8-sig"
|
273
|
+
)
|
274
|
+
self._result = self.filename
|
275
|
+
self.add_metric("MERGED_FILE", self.filename)
|
276
|
+
return self._result
|
277
|
+
except Exception as err:
|
278
|
+
logging.error(err)
|
279
|
+
self._result = None
|
280
|
+
return False
|
281
|
+
elif self.ContentType == "text/csv":
|
282
|
+
args = {}
|
283
|
+
if hasattr(self, "pd_args"):
|
284
|
+
args = self.pd_args
|
285
|
+
if hasattr(self, "encoding"):
|
286
|
+
encoding = self.encoding
|
287
|
+
else:
|
288
|
+
encoding = None
|
289
|
+
for file in self.data:
|
290
|
+
try:
|
291
|
+
buffer = None
|
292
|
+
with open(file, "rb") as f:
|
293
|
+
buffer = f.read(10000)
|
294
|
+
result_charset = chardet.detect(buffer)
|
295
|
+
enc = result_charset["encoding"]
|
296
|
+
if encoding is not None and enc != encoding:
|
297
|
+
logging.warning(
|
298
|
+
"MergeFiles: files has different encoding"
|
299
|
+
)
|
300
|
+
encoding = enc
|
301
|
+
if encoding == "ASCII":
|
302
|
+
encoding = "utf-8-sig"
|
303
|
+
except Exception as err:
|
304
|
+
logging.warning(f"MergeFiles: DECODING ERROR {err}")
|
305
|
+
_, encoding = detect_encoding(file, encoding)
|
306
|
+
if not encoding:
|
307
|
+
encoding = "utf-8-sig"
|
308
|
+
try:
|
309
|
+
if len(self.data) == 1:
|
310
|
+
# there is no other files to merge:
|
311
|
+
combined_csv = pd.read_csv(self.data[0], encoding=encoding)
|
312
|
+
else:
|
313
|
+
dfs = [pd.read_csv(f, encoding=encoding) for f in self.data]
|
314
|
+
# combine all files in the list
|
315
|
+
combined_csv = self._merge_dataframe(dfs)
|
316
|
+
print(f"COMBINED CSV: {combined_csv}")
|
317
|
+
except UnicodeDecodeError:
|
318
|
+
combined_csv = pd.concat(
|
319
|
+
[pd.read_csv(f, encoding="windows-1252") for f in self.data]
|
320
|
+
)
|
321
|
+
except Exception as err:
|
322
|
+
raise ComponentError(f"{err!s}") from err
|
323
|
+
try:
|
324
|
+
if self.as_dataframe is True:
|
325
|
+
self._result = combined_csv
|
326
|
+
self.add_metric("MERGED_DF", self._result.columns)
|
327
|
+
else:
|
328
|
+
# export to csv
|
329
|
+
combined_csv.to_csv(
|
330
|
+
self.filename, index=False, encoding="utf-8-sig"
|
331
|
+
)
|
332
|
+
self._result = self.filename
|
333
|
+
self.add_metric("MERGED_FILE", self.filename)
|
334
|
+
return self._result
|
335
|
+
except Exception as err:
|
336
|
+
self._logger.error(err)
|
337
|
+
self._result = None
|
338
|
+
return False
|
339
|
+
elif isinstance(self.data, dict):
|
340
|
+
for f in self.data:
|
341
|
+
ip = self.data[f]["data"]
|
342
|
+
if self.ContentType == "application/json":
|
343
|
+
if self.data[f]["type"] == "binary/octet-stream":
|
344
|
+
# wrapper = io.TextIOWrapper(input, encoding='utf-8')
|
345
|
+
content = ip.getvalue()
|
346
|
+
else:
|
347
|
+
# convert to string:
|
348
|
+
# wrapper = io.TextIOWrapper(input, encoding='utf-8')
|
349
|
+
content = ip
|
350
|
+
# content = wrapper.read()
|
351
|
+
df = pd.read_json(content, orient="records")
|
352
|
+
columns = list(df.columns)
|
353
|
+
np_array_list.append(df.values)
|
354
|
+
comb_np_array = np.vstack(np_array_list)
|
355
|
+
df = pd.DataFrame(comb_np_array)
|
356
|
+
df.columns = columns
|
357
|
+
self._result = df
|
358
|
+
self._print_data_(df, 'Merged data')
|
359
|
+
return True
|
360
|
+
else:
|
361
|
+
self._result = None
|
362
|
+
return False
|
@@ -0,0 +1,87 @@
|
|
1
|
+
"""
|
2
|
+
Milvus Database Vectorstore Output.
|
3
|
+
|
4
|
+
|
5
|
+
Example:
|
6
|
+
|
7
|
+
```yaml
|
8
|
+
MilvusOutput:
|
9
|
+
credentials:
|
10
|
+
collection_name: lg_products
|
11
|
+
db_name: lg
|
12
|
+
embedding_model:
|
13
|
+
model_name: thenlper/gte-base
|
14
|
+
model_type: transformers
|
15
|
+
vector_field: vector
|
16
|
+
text_field: text
|
17
|
+
pk: source_type
|
18
|
+
consistency_level: Bounded
|
19
|
+
```
|
20
|
+
|
21
|
+
"""
|
22
|
+
from collections.abc import Callable
|
23
|
+
import asyncio
|
24
|
+
from .flow import FlowComponent
|
25
|
+
from ..exceptions import DataNotFound, ComponentError, ConfigError
|
26
|
+
from ..interfaces.vectorstores import MilvusStore
|
27
|
+
|
28
|
+
|
29
|
+
class MilvusOutput(MilvusStore, FlowComponent):
|
30
|
+
def __init__(
|
31
|
+
self,
|
32
|
+
loop: asyncio.AbstractEventLoop = None,
|
33
|
+
job: Callable = None,
|
34
|
+
stat: Callable = None,
|
35
|
+
**kwargs,
|
36
|
+
):
|
37
|
+
self.upsert: bool = kwargs.pop('upsert', True)
|
38
|
+
self.pk: str = kwargs.pop('pk', 'source_type')
|
39
|
+
super().__init__(loop=loop, job=job, stat=stat, **kwargs)
|
40
|
+
|
41
|
+
async def start(self, **kwargs):
|
42
|
+
if self.previous:
|
43
|
+
self.data = self.input
|
44
|
+
await super().start(**kwargs)
|
45
|
+
self.processing_credentials()
|
46
|
+
if not self.credentials:
|
47
|
+
raise ConfigError(
|
48
|
+
"Unable to find valid Credentials for Milvus DB."
|
49
|
+
)
|
50
|
+
if not self.data:
|
51
|
+
raise DataNotFound(
|
52
|
+
"List of Documents is Empty."
|
53
|
+
)
|
54
|
+
if not isinstance(self.data, list):
|
55
|
+
raise ComponentError(
|
56
|
+
f"Incompatible kind of data received, expected *list*, receives {type(self.data)}"
|
57
|
+
)
|
58
|
+
return True
|
59
|
+
|
60
|
+
async def close(self):
|
61
|
+
pass
|
62
|
+
|
63
|
+
async def run(self):
|
64
|
+
"""
|
65
|
+
Saving Langchain Documents on a Milvus Database.
|
66
|
+
"""
|
67
|
+
# Connecting to Milvus
|
68
|
+
# TODO: add Collection creation:
|
69
|
+
self._result = None
|
70
|
+
async with self as connection:
|
71
|
+
vector, documents = await connection.load_documents(
|
72
|
+
self.data,
|
73
|
+
collection=self.collection_name,
|
74
|
+
upsert=self.upsert,
|
75
|
+
pk=self.pk,
|
76
|
+
dimension=self._dimension,
|
77
|
+
index_type=self._index_type,
|
78
|
+
metric_type=self._metric_type
|
79
|
+
)
|
80
|
+
result = {
|
81
|
+
"vectorstore": vector,
|
82
|
+
"documents": documents
|
83
|
+
}
|
84
|
+
self._result = result
|
85
|
+
self.add_metric('DOCUMENTS_LOADED', len(self.data))
|
86
|
+
# self.add_metric('DOCUMENTS', documents)
|
87
|
+
return result
|
@@ -0,0 +1,175 @@
|
|
1
|
+
import asyncio
|
2
|
+
import pandas as pd
|
3
|
+
import geopandas as gpd
|
4
|
+
from shapely.geometry import Point
|
5
|
+
from concurrent.futures import ProcessPoolExecutor
|
6
|
+
from .flow import FlowComponent
|
7
|
+
from ..exceptions import ComponentError, DataNotFound
|
8
|
+
|
9
|
+
|
10
|
+
class NearByStores(FlowComponent):
|
11
|
+
"""NearByStores.
|
12
|
+
|
13
|
+
Overview:
|
14
|
+
Calculates the nearest stores to an employee location.
|
15
|
+
|
16
|
+
|
17
|
+
|
18
|
+
Example:
|
19
|
+
|
20
|
+
```yaml
|
21
|
+
NearByStores:
|
22
|
+
depends:
|
23
|
+
- QueryToPandas_1
|
24
|
+
- QueryToPandas_2
|
25
|
+
radius: 50
|
26
|
+
```
|
27
|
+
|
28
|
+
"""
|
29
|
+
async def start(self, **kwargs):
|
30
|
+
if self.previous:
|
31
|
+
try:
|
32
|
+
self.df1: pd.DataFrame = self.previous[0].output()
|
33
|
+
self.df2: pd.DataFrame = self.previous[1].output()
|
34
|
+
except IndexError:
|
35
|
+
raise ComponentError(
|
36
|
+
"NearByStores Requires 2 Dataframes", status=404
|
37
|
+
)
|
38
|
+
else:
|
39
|
+
raise DataNotFound(
|
40
|
+
"Data Not Found", status=404
|
41
|
+
)
|
42
|
+
await super().start(**kwargs)
|
43
|
+
return True
|
44
|
+
|
45
|
+
async def close(self):
|
46
|
+
pass
|
47
|
+
|
48
|
+
def _print_data_(self, df: pd.DataFrame, title: str = None):
|
49
|
+
if not title:
|
50
|
+
title = self.__class__.__name__
|
51
|
+
print(f"::: Printing {title} === ")
|
52
|
+
print("Data: ", df)
|
53
|
+
if df.empty:
|
54
|
+
print("The DataFrame is empty.")
|
55
|
+
else:
|
56
|
+
for column, t in df.dtypes.items():
|
57
|
+
print(f"{column} -> {t} -> {df[column].iloc[0]}")
|
58
|
+
|
59
|
+
def _find_nearby_stores(self, employee_row, stores_gdf, employees_gdf):
|
60
|
+
# Employee's buffer geometry
|
61
|
+
employee_buffer = employee_row['buffer']
|
62
|
+
employee_buffer_gdf = gpd.GeoDataFrame(
|
63
|
+
{'geometry': [employee_buffer]}, crs=employees_gdf.crs
|
64
|
+
)
|
65
|
+
|
66
|
+
# Spatial join to find stores within the buffer
|
67
|
+
nearby_stores = gpd.sjoin(
|
68
|
+
stores_gdf, employee_buffer_gdf, how='inner', predicate='intersects'
|
69
|
+
)
|
70
|
+
|
71
|
+
# If no stores are found, return an empty list
|
72
|
+
if nearby_stores.empty:
|
73
|
+
return []
|
74
|
+
|
75
|
+
# Build a list of dictionaries combining employee and store information
|
76
|
+
rows = []
|
77
|
+
employee_info = {
|
78
|
+
'associate_oid': employee_row['associate_oid'],
|
79
|
+
'corporate_email': employee_row['corporate_email'],
|
80
|
+
'employee_coordinates': (employee_row.geometry.y, employee_row.geometry.x),
|
81
|
+
'employee_position': (employee_row.latitude, employee_row.longitude)
|
82
|
+
}
|
83
|
+
|
84
|
+
for idx, store_row in nearby_stores.iterrows():
|
85
|
+
store_info = {
|
86
|
+
'store_id': store_row['store_id'],
|
87
|
+
'store_name': store_row['store_name'],
|
88
|
+
'store_coordinates': (store_row.geometry.y, store_row.geometry.x),
|
89
|
+
'store_position': (store_row.latitude, store_row.longitude),
|
90
|
+
'visit_rule': store_row.get('visit_rule', None),
|
91
|
+
'visit_category': store_row.get('visit_category', None)
|
92
|
+
}
|
93
|
+
# Combine employee and store info
|
94
|
+
combined_row = {**employee_info, **store_info}
|
95
|
+
rows.append(combined_row)
|
96
|
+
|
97
|
+
return rows
|
98
|
+
|
99
|
+
async def _async_find_nearby_stores(self, employee_row, stores_gdf, employees_gdf):
|
100
|
+
try:
|
101
|
+
result = await asyncio.to_thread(
|
102
|
+
self._find_nearby_stores,
|
103
|
+
employee_row,
|
104
|
+
stores_gdf,
|
105
|
+
employees_gdf
|
106
|
+
)
|
107
|
+
return result
|
108
|
+
except Exception as e:
|
109
|
+
# Log the exception and return None
|
110
|
+
print(f"An error occurred: {e}")
|
111
|
+
return None
|
112
|
+
|
113
|
+
async def run(self):
|
114
|
+
# Create geometry columns for employees
|
115
|
+
self.df2['geometry'] = self.df2.apply(
|
116
|
+
lambda row: Point(row['longitude'], row['latitude']), axis=1
|
117
|
+
)
|
118
|
+
employees_gdf = gpd.GeoDataFrame(self.df2, geometry='geometry', crs='EPSG:4326')
|
119
|
+
|
120
|
+
# Create geometry columns for stores
|
121
|
+
self.df1['geometry'] = self.df1.apply(
|
122
|
+
lambda row: Point(row['longitude'], row['latitude']), axis=1
|
123
|
+
)
|
124
|
+
stores_gdf = gpd.GeoDataFrame(self.df1, geometry='geometry', crs='EPSG:4326')
|
125
|
+
|
126
|
+
# Reproject to EPSG:3857 that allows accurate distance measurements in meters.
|
127
|
+
employees_gdf = employees_gdf.to_crs(epsg=3857)
|
128
|
+
stores_gdf = stores_gdf.to_crs(epsg=3857)
|
129
|
+
|
130
|
+
# Build spatial index for stores_gdf
|
131
|
+
stores_gdf.sindex
|
132
|
+
|
133
|
+
# radius:
|
134
|
+
radius = getattr(self, 'radius', 100)
|
135
|
+
|
136
|
+
# Convert miles to meters (1 mile = 1609.34 meters)
|
137
|
+
buffer_radius = radius * 1609.34 # 482,802 meters
|
138
|
+
|
139
|
+
# Create buffers
|
140
|
+
employees_gdf['buffer'] = employees_gdf.geometry.buffer(buffer_radius)
|
141
|
+
|
142
|
+
batch_size = 50
|
143
|
+
|
144
|
+
# Create a list of tasks
|
145
|
+
tasks = [
|
146
|
+
self._async_find_nearby_stores(employee_row, stores_gdf, employees_gdf)
|
147
|
+
for _, employee_row in employees_gdf.iterrows()
|
148
|
+
]
|
149
|
+
|
150
|
+
tasks_chunks = [tasks[i:i + batch_size] for i in range(0, len(tasks), batch_size)]
|
151
|
+
|
152
|
+
results = []
|
153
|
+
for chunk in tasks_chunks:
|
154
|
+
# Run tasks in the chunk concurrently
|
155
|
+
chunk_results = await asyncio.gather(*chunk)
|
156
|
+
# Collect the rows from each result
|
157
|
+
for result in chunk_results:
|
158
|
+
if result: # Check if the list is not empty
|
159
|
+
results.extend(result) # Extend the results list with the returned rows
|
160
|
+
|
161
|
+
# Concatenate all results
|
162
|
+
if results:
|
163
|
+
final_df = pd.DataFrame(results)
|
164
|
+
else:
|
165
|
+
# If no results, create an empty DataFrame with the expected columns
|
166
|
+
final_df = pd.DataFrame(columns=[
|
167
|
+
'associate_oid', 'corporate_email', 'employee_position',
|
168
|
+
'store_id', 'store_position', 'visit_rule', 'visit_category'
|
169
|
+
])
|
170
|
+
|
171
|
+
# Set the final output
|
172
|
+
self._print_data_(final_df)
|
173
|
+
self._result = final_df
|
174
|
+
|
175
|
+
return self._result
|
@@ -0,0 +1,52 @@
|
|
1
|
+
from .organization import Organization
|
2
|
+
from .client import Client
|
3
|
+
from .store import Store, StoreType, StoreGeography
|
4
|
+
from .user import Role, User, StaffingUser
|
5
|
+
from .photos import Document, Photo, PhotoCategory
|
6
|
+
from .project import Project
|
7
|
+
from .forms import Form, FormMetadata, FormData, FormDefinition
|
8
|
+
from .events import Event, EventPunch
|
9
|
+
from .account import Account
|
10
|
+
|
11
|
+
|
12
|
+
NetworkNinja_Map = {
|
13
|
+
"store": Store,
|
14
|
+
"client": Client,
|
15
|
+
"orgid": Organization,
|
16
|
+
"user": User,
|
17
|
+
"staffing_user": StaffingUser,
|
18
|
+
'photo_category': PhotoCategory,
|
19
|
+
'store_photo': Photo,
|
20
|
+
"role": Role,
|
21
|
+
"project": Project,
|
22
|
+
"store_type": StoreType,
|
23
|
+
"document": Document,
|
24
|
+
'store_geography': StoreGeography,
|
25
|
+
'form': FormDefinition,
|
26
|
+
'form_metadata': FormMetadata,
|
27
|
+
'form_data': FormData,
|
28
|
+
'event': Event,
|
29
|
+
'retailer': Account,
|
30
|
+
'event_cico': EventPunch
|
31
|
+
}
|
32
|
+
|
33
|
+
|
34
|
+
NN_Order = [
|
35
|
+
'client',
|
36
|
+
'project',
|
37
|
+
'orgid',
|
38
|
+
'retailer',
|
39
|
+
'role',
|
40
|
+
'store_type',
|
41
|
+
'store_geography',
|
42
|
+
'store',
|
43
|
+
'user',
|
44
|
+
'staffing_user',
|
45
|
+
'form',
|
46
|
+
'event',
|
47
|
+
'event_cico',
|
48
|
+
'form_metadata',
|
49
|
+
'form_data',
|
50
|
+
'photo_category',
|
51
|
+
'store_photo',
|
52
|
+
]
|