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,319 @@
|
|
1
|
+
import asyncio
|
2
|
+
import random
|
3
|
+
import pandas as pd
|
4
|
+
from collections.abc import Callable
|
5
|
+
from duckduckgo_search.exceptions import RatelimitException
|
6
|
+
from typing import List, Dict, Any, Optional
|
7
|
+
from tqdm.asyncio import tqdm
|
8
|
+
from ...exceptions import ComponentError, ConfigError
|
9
|
+
from ...interfaces import HTTPService, SeleniumService
|
10
|
+
from ...interfaces.http import ua
|
11
|
+
from ..flow import FlowComponent
|
12
|
+
from .parsers import EpsonParser, HPParser, CanonParser, BrotherParser, SamsungParser
|
13
|
+
from googleapiclient.discovery import build
|
14
|
+
|
15
|
+
class ProductInfo(FlowComponent, HTTPService, SeleniumService):
|
16
|
+
"""
|
17
|
+
Product Information Scraper Component
|
18
|
+
|
19
|
+
This component extracts detailed product information by:
|
20
|
+
1. Searching for products using search terms
|
21
|
+
2. Extracting model codes from URLs
|
22
|
+
3. Parsing product details from manufacturer websites
|
23
|
+
|
24
|
+
Configuration options:
|
25
|
+
- search_column: Column name containing search terms (default: 'model')
|
26
|
+
- parsers: List of parser names to use (default: ['epson'])
|
27
|
+
- max_results: Maximum number of search results to process (default: 5)
|
28
|
+
- concurrently: Process items concurrently (default: True)
|
29
|
+
- task_parts: Number of parts to split concurrent tasks (default: 10)
|
30
|
+
"""
|
31
|
+
|
32
|
+
def __init__(
|
33
|
+
self,
|
34
|
+
loop: asyncio.AbstractEventLoop = None,
|
35
|
+
job: Callable = None,
|
36
|
+
stat: Callable = None,
|
37
|
+
**kwargs
|
38
|
+
) -> None:
|
39
|
+
self.search_column = kwargs.get('search_column', 'model')
|
40
|
+
self.parsers_list = kwargs.get('parsers', ['epson'])
|
41
|
+
self.max_results = kwargs.get('max_results', 5)
|
42
|
+
self.concurrently = kwargs.get('concurrently', True)
|
43
|
+
self.task_parts = kwargs.get('task_parts', 10)
|
44
|
+
self.use_proxy = kwargs.get('use_proxy', True)
|
45
|
+
self._free_proxy = kwargs.get('free_proxy', False)
|
46
|
+
self.google_api_key = kwargs.get('google_api_key')
|
47
|
+
self.google_cse = kwargs.get('google_cse')
|
48
|
+
|
49
|
+
super().__init__(loop=loop, job=job, stat=stat, **kwargs)
|
50
|
+
|
51
|
+
# Configure headers
|
52
|
+
self.headers = {
|
53
|
+
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
|
54
|
+
"Accept-Encoding": "gzip, deflate",
|
55
|
+
"Accept-Language": "en-US,en;q=0.5",
|
56
|
+
"DNT": "1",
|
57
|
+
"Connection": "keep-alive",
|
58
|
+
"Upgrade-Insecure-Requests": "1",
|
59
|
+
"User-Agent": random.choice(ua),
|
60
|
+
**kwargs.get('headers', {})
|
61
|
+
}
|
62
|
+
|
63
|
+
# Initialize semaphore for concurrent requests
|
64
|
+
self._semaphore = asyncio.Semaphore(10)
|
65
|
+
|
66
|
+
async def start(self, **kwargs) -> bool:
|
67
|
+
"""Initialize component and validate requirements."""
|
68
|
+
if self.previous:
|
69
|
+
self.data = self.input
|
70
|
+
|
71
|
+
if not isinstance(self.data, pd.DataFrame):
|
72
|
+
raise ComponentError(
|
73
|
+
"Input must be a DataFrame",
|
74
|
+
status=404
|
75
|
+
)
|
76
|
+
|
77
|
+
if self.search_column not in self.data.columns:
|
78
|
+
raise ConfigError(
|
79
|
+
f"Column '{self.search_column}' not found in DataFrame"
|
80
|
+
)
|
81
|
+
|
82
|
+
# Initialize result columns
|
83
|
+
new_columns = [
|
84
|
+
'search_term',
|
85
|
+
'search_url',
|
86
|
+
'model_code',
|
87
|
+
'product_name',
|
88
|
+
'price',
|
89
|
+
'description',
|
90
|
+
'specs',
|
91
|
+
'images',
|
92
|
+
'search_status',
|
93
|
+
'parse_status'
|
94
|
+
]
|
95
|
+
|
96
|
+
for col in new_columns:
|
97
|
+
if col not in self.data.columns:
|
98
|
+
self.data[col] = None
|
99
|
+
|
100
|
+
return await super(ProductInfo, self).start(**kwargs)
|
101
|
+
|
102
|
+
def split_parts(self, tasks: List, num_parts: int = 5) -> List[List]:
|
103
|
+
"""Split tasks into parts for concurrent processing."""
|
104
|
+
part_size = len(tasks) // num_parts
|
105
|
+
remainder = len(tasks) % num_parts
|
106
|
+
parts = []
|
107
|
+
start = 0
|
108
|
+
|
109
|
+
for i in range(num_parts):
|
110
|
+
# Distribute remainder across first parts
|
111
|
+
end = start + part_size + (1 if i < remainder else 0)
|
112
|
+
parts.append(tasks[start:end])
|
113
|
+
start = end
|
114
|
+
|
115
|
+
return parts
|
116
|
+
|
117
|
+
async def _processing_tasks(self, tasks: List) -> pd.DataFrame:
|
118
|
+
"""Process tasks and format results."""
|
119
|
+
results = []
|
120
|
+
total_tasks = len(tasks)
|
121
|
+
|
122
|
+
with tqdm(total=total_tasks, desc="Processing Products", unit="product") as pbar:
|
123
|
+
if not self.concurrently:
|
124
|
+
# Sequential processing
|
125
|
+
for task in tasks:
|
126
|
+
try:
|
127
|
+
idx, row = await task
|
128
|
+
results.append((idx, row))
|
129
|
+
await asyncio.sleep(random.uniform(0.5, 2))
|
130
|
+
except Exception as e:
|
131
|
+
self._logger.error(f"Task error: {str(e)}")
|
132
|
+
if hasattr(e, 'idx') and hasattr(e, 'row'):
|
133
|
+
results.append((e.idx, e.row))
|
134
|
+
finally:
|
135
|
+
pbar.update(1)
|
136
|
+
else:
|
137
|
+
# Concurrent processing
|
138
|
+
for chunk in self.split_parts(tasks, self.task_parts):
|
139
|
+
chunk_size = len(chunk)
|
140
|
+
chunk_results = await asyncio.gather(*chunk, return_exceptions=True)
|
141
|
+
|
142
|
+
for result in chunk_results:
|
143
|
+
if isinstance(result, Exception):
|
144
|
+
self._logger.error(f"Task error: {str(result)}")
|
145
|
+
if hasattr(result, 'idx') and hasattr(result, 'row'):
|
146
|
+
results.append((result.idx, result.row))
|
147
|
+
else:
|
148
|
+
results.append(result)
|
149
|
+
|
150
|
+
pbar.update(chunk_size)
|
151
|
+
|
152
|
+
# Process results
|
153
|
+
if not results:
|
154
|
+
return pd.DataFrame()
|
155
|
+
|
156
|
+
indices, data_dicts = zip(*results)
|
157
|
+
return pd.DataFrame(data_dicts, index=indices)
|
158
|
+
|
159
|
+
async def _search_product(self, idx: int, row: dict) -> tuple:
|
160
|
+
"""Search for product and extract information."""
|
161
|
+
async with self._semaphore:
|
162
|
+
# Get search term and retailer
|
163
|
+
search_term = row[self.search_column]
|
164
|
+
retailer = row.get('retailer') # Opcional, puede ser None
|
165
|
+
|
166
|
+
if not search_term:
|
167
|
+
row['search_status'] = 'error: empty search term'
|
168
|
+
return idx, row
|
169
|
+
|
170
|
+
# Determine which parser to use based on brand
|
171
|
+
brand = row.get('brand', '').lower()
|
172
|
+
parser = None
|
173
|
+
|
174
|
+
if brand == 'epson' and 'epson' in self.parsers_list:
|
175
|
+
parser = EpsonParser()
|
176
|
+
elif brand == 'hp' and 'hp' in self.parsers_list:
|
177
|
+
parser = HPParser()
|
178
|
+
elif brand == 'canon' and 'canon' in self.parsers_list:
|
179
|
+
parser = CanonParser()
|
180
|
+
elif brand == 'brother' and 'brother' in self.parsers_list:
|
181
|
+
parser = BrotherParser()
|
182
|
+
elif brand == 'samsung' and 'samsung' in self.parsers_list:
|
183
|
+
parser = SamsungParser()
|
184
|
+
elif retailer: # Set retailer info before any operations
|
185
|
+
parser = CanonParser()
|
186
|
+
parser.retailer = retailer
|
187
|
+
parser.region = parser.determine_region(retailer)
|
188
|
+
|
189
|
+
# If no matching parser for brand, try all parsers
|
190
|
+
if not parser:
|
191
|
+
# Initialize all parsers as before
|
192
|
+
parsers = []
|
193
|
+
for parser_name in self.parsers_list:
|
194
|
+
if parser_name == 'epson':
|
195
|
+
parsers.append(EpsonParser())
|
196
|
+
elif parser_name == 'hp':
|
197
|
+
parsers.append(HPParser())
|
198
|
+
elif parser_name == 'canon':
|
199
|
+
parsers.append(CanonParser())
|
200
|
+
elif parser_name == 'brother':
|
201
|
+
parsers.append(BrotherParser())
|
202
|
+
elif parser_name == 'samsung':
|
203
|
+
parsers.append(SamsungParser())
|
204
|
+
# Add more parsers here as they are implemented
|
205
|
+
|
206
|
+
if not parsers:
|
207
|
+
row['search_status'] = 'error: no valid parsers'
|
208
|
+
return idx, row
|
209
|
+
else:
|
210
|
+
# Use only the brand-specific parser
|
211
|
+
parsers = [parser]
|
212
|
+
|
213
|
+
# Try each parser (either brand-specific or all available)
|
214
|
+
for parser in parsers:
|
215
|
+
try:
|
216
|
+
# Create search query
|
217
|
+
query = parser.create_search_query(search_term)
|
218
|
+
row['search_term'] = query
|
219
|
+
|
220
|
+
# Usar Google directamente como en CompanyScraper
|
221
|
+
google_results = None
|
222
|
+
try:
|
223
|
+
# Obtener resultados de Google
|
224
|
+
google_config = {
|
225
|
+
'api_key': self.google_api_key,
|
226
|
+
'cse_id': self.google_cse,
|
227
|
+
'num': self.max_results
|
228
|
+
}
|
229
|
+
|
230
|
+
google_search = build(
|
231
|
+
"customsearch", "v1",
|
232
|
+
developerKey=google_config['api_key']
|
233
|
+
)
|
234
|
+
|
235
|
+
google_results = google_search.cse().list(
|
236
|
+
q=query,
|
237
|
+
cx=google_config['cse_id'],
|
238
|
+
num=google_config['num']
|
239
|
+
).execute()
|
240
|
+
|
241
|
+
search_results = google_results.get('items', [])
|
242
|
+
|
243
|
+
if not search_results:
|
244
|
+
self._logger.warning(f"No search results for: {query}")
|
245
|
+
continue
|
246
|
+
|
247
|
+
# Format search results
|
248
|
+
formatted_results = []
|
249
|
+
for item in search_results:
|
250
|
+
formatted_results.append({
|
251
|
+
'title': item.get('title', ''),
|
252
|
+
'link': item.get('link', ''),
|
253
|
+
'snippet': item.get('snippet', '')
|
254
|
+
})
|
255
|
+
|
256
|
+
search_results = formatted_results
|
257
|
+
|
258
|
+
except Exception as e:
|
259
|
+
self._logger.error(f"Google search error: {str(e)}")
|
260
|
+
row['search_status'] = f'error: search failed - {str(e)}'
|
261
|
+
continue
|
262
|
+
|
263
|
+
# Get product URLs
|
264
|
+
product_urls = parser.get_product_urls(search_results, self.max_results)
|
265
|
+
if not product_urls:
|
266
|
+
self._logger.warning(f"No matching URLs found for: {query}")
|
267
|
+
continue
|
268
|
+
|
269
|
+
# Process each URL
|
270
|
+
for url in product_urls:
|
271
|
+
# Extract model code (puede ser None para algunos parsers)
|
272
|
+
model_code = parser.extract_model_code(url)
|
273
|
+
|
274
|
+
# Store in row
|
275
|
+
row['search_url'] = url
|
276
|
+
row['model_code'] = model_code # Podría ser None aquí
|
277
|
+
row['search_status'] = 'success'
|
278
|
+
|
279
|
+
# Parse additional product details - el modelo se extraerá durante este paso para parsers sin model_pattern
|
280
|
+
try:
|
281
|
+
product_info = await parser.parse(url, search_term, retailer)
|
282
|
+
if product_info and product_info['parse_status'] == 'success':
|
283
|
+
# Update with detailed information
|
284
|
+
for key, value in product_info.items():
|
285
|
+
if key != 'search_term' and key != 'search_url':
|
286
|
+
row[key] = value
|
287
|
+
except Exception as parse_error:
|
288
|
+
self._logger.error(f"Error parsing product details: {str(parse_error)}")
|
289
|
+
row['parse_status'] = f'error: {str(parse_error)}'
|
290
|
+
|
291
|
+
# Return after first successful match
|
292
|
+
return idx, row
|
293
|
+
|
294
|
+
except Exception as e:
|
295
|
+
self._logger.error(f"Error searching with {parser.__class__.__name__}: {str(e)}")
|
296
|
+
continue
|
297
|
+
|
298
|
+
# If we get here, no successful matches were found
|
299
|
+
row['search_status'] = 'not found'
|
300
|
+
return idx, row
|
301
|
+
|
302
|
+
async def run(self):
|
303
|
+
"""Execute product info extraction for each row."""
|
304
|
+
# Create tasks for each row
|
305
|
+
tasks = [
|
306
|
+
self._search_product(idx, row.to_dict())
|
307
|
+
for idx, row in self.data.iterrows()
|
308
|
+
]
|
309
|
+
|
310
|
+
# Process tasks
|
311
|
+
result_df = await self._processing_tasks(tasks)
|
312
|
+
|
313
|
+
# Output results
|
314
|
+
self._result = result_df
|
315
|
+
return self._result
|
316
|
+
|
317
|
+
async def close(self):
|
318
|
+
"""Clean up resources."""
|
319
|
+
return True
|
@@ -0,0 +1,118 @@
|
|
1
|
+
import asyncio
|
2
|
+
from collections.abc import Callable
|
3
|
+
from bs4 import BeautifulSoup
|
4
|
+
import urllib
|
5
|
+
import pandas as pd
|
6
|
+
from ..exceptions import ComponentError
|
7
|
+
from .flow import FlowComponent
|
8
|
+
from ..interfaces.http import HTTPService
|
9
|
+
|
10
|
+
|
11
|
+
class ProductPricing(HTTPService, FlowComponent):
|
12
|
+
"""
|
13
|
+
ProductPricing.
|
14
|
+
|
15
|
+
Overview
|
16
|
+
|
17
|
+
This component Get the price of a list of products
|
18
|
+
|
19
|
+
.. table:: Properties
|
20
|
+
:widths: auto
|
21
|
+
|
22
|
+
|
23
|
+
+--------------+----------+-----------+-------------------------------------------------------+
|
24
|
+
| Name | Required | Summary |
|
25
|
+
+--------------+----------+-----------+-------------------------------------------------------+
|
26
|
+
| column | Yes | Set the column in dataframe used as term search |
|
27
|
+
+--------------+----------+-----------+-------------------------------------------------------+
|
28
|
+
| price_column| No | name of the price column |
|
29
|
+
+--------------+----------+-----------+-------------------------------------------------------+
|
30
|
+
|
31
|
+
Return the prices in a column of dataframe
|
32
|
+
"""
|
33
|
+
|
34
|
+
def __init__(
|
35
|
+
self,
|
36
|
+
loop: asyncio.AbstractEventLoop = None,
|
37
|
+
job: Callable = None,
|
38
|
+
stat: Callable = None,
|
39
|
+
**kwargs,
|
40
|
+
):
|
41
|
+
"""Init Method."""
|
42
|
+
self.column: str = None
|
43
|
+
self.price_column: str = 'price'
|
44
|
+
self.accept = 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/png,image/svg+xml,*/*;q=0.8'
|
45
|
+
self.credentials = None
|
46
|
+
super(ProductPricing, self).__init__(
|
47
|
+
loop=loop,
|
48
|
+
job=job,
|
49
|
+
stat=stat,
|
50
|
+
**kwargs
|
51
|
+
)
|
52
|
+
HTTPService.__init__(self, **kwargs)
|
53
|
+
|
54
|
+
async def start(self, **kwargs):
|
55
|
+
# Si lo que llega no es un DataFrame de Pandas se cancela la tarea
|
56
|
+
if self.previous:
|
57
|
+
self.data = self.input
|
58
|
+
else:
|
59
|
+
raise ComponentError("Data Not Found")
|
60
|
+
if not isinstance(self.data, pd.DataFrame):
|
61
|
+
raise ComponentError('Incompatible Pandas Dataframe')
|
62
|
+
if not self.column:
|
63
|
+
raise ComponentError('A column is necessary')
|
64
|
+
self.headers = {
|
65
|
+
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36',
|
66
|
+
'Host': 'www.amazon.com',
|
67
|
+
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/png,image/svg+xml,*/*;q=0.8',
|
68
|
+
'Accept-Language': 'en-US;q=0.5,en;q=0.3',
|
69
|
+
'Accept-Encoding': 'gzip, deflate, br, zstd',
|
70
|
+
'DNT': '1',
|
71
|
+
'Connection': 'keep-alive',
|
72
|
+
'Upgrade-Insecure-Requests': '1',
|
73
|
+
'Sec-Fetch-Dest': 'document',
|
74
|
+
'Sec-Fetch-Mode': 'navigate',
|
75
|
+
'Sec-Fetch-Site': 'same-origin',
|
76
|
+
'Sec-Fetch-User': '?1'
|
77
|
+
}
|
78
|
+
|
79
|
+
async def close(self):
|
80
|
+
pass
|
81
|
+
|
82
|
+
async def pricing(self, model):
|
83
|
+
model = urllib.parse.quote_plus(str(model))
|
84
|
+
self._base_url = f'https://www.amazon.com/s?k={model}&s=relevanceblender'
|
85
|
+
args = {
|
86
|
+
"url": self._base_url,
|
87
|
+
"method": "get"
|
88
|
+
}
|
89
|
+
response, error = await self.async_request(**args)
|
90
|
+
|
91
|
+
if not error:
|
92
|
+
soup = BeautifulSoup(response, 'html.parser')
|
93
|
+
content = soup.find('div', class_='s-desktop-content')
|
94
|
+
items = content.find_all('div', {'data-component-type': 's-search-result'})
|
95
|
+
for item in items:
|
96
|
+
sponsored = False if item.find('span', class_='puis-sponsored-label-info-icon') is None else True
|
97
|
+
if not sponsored:
|
98
|
+
price = item.find('span', class_='a-offscreen')
|
99
|
+
if price is not None:
|
100
|
+
self._logger.info(f'{model} -> {price.text}')
|
101
|
+
return price.text.replace('$', '')
|
102
|
+
else:
|
103
|
+
return None
|
104
|
+
|
105
|
+
async def run(self):
|
106
|
+
try:
|
107
|
+
prices = []
|
108
|
+
df = self.data[self.column].drop_duplicates().to_frame()
|
109
|
+
for model in df[self.column]:
|
110
|
+
price = await self.pricing(model)
|
111
|
+
prices.append(price)
|
112
|
+
df[self.price_column] = prices
|
113
|
+
df_merged = pd.merge(self.data, df, on=self.column, how='left')
|
114
|
+
self.add_metric("NUMROWS", len(df.index))
|
115
|
+
self._result = df_merged
|
116
|
+
return self._result
|
117
|
+
except Exception as err:
|
118
|
+
raise ComponentError(f"Error in ProductPricing: {err}") from err
|