From 731548b431ff04ba416e17c9294e12faeef0f03d Mon Sep 17 00:00:00 2001 From: Aarushi <50577581+aarushik93@users.noreply.github.com> Date: Mon, 10 Jun 2024 13:50:57 +0100 Subject: [PATCH] adding frontend to codebase for ease of local dev use. (#285) * adding frontend to codebase for ease of local dev use. * fix linting --- Dockerfile.frontend | 37 ++++ README.md | 2 + docker-compose.full.yml | 14 +- frontend/__init__.py | 0 frontend/chat.py | 183 ++++++++++++++++ frontend/codex_client.py | 412 ++++++++++++++++++++++++++++++++++++ frontend/codex_model.py | 210 +++++++++++++++++++ poetry.lock | 436 ++++++++++++++++++++++++++++++++++++++- pyproject.toml | 1 + 9 files changed, 1293 insertions(+), 2 deletions(-) create mode 100644 Dockerfile.frontend create mode 100644 frontend/__init__.py create mode 100644 frontend/chat.py create mode 100644 frontend/codex_client.py create mode 100644 frontend/codex_model.py diff --git a/Dockerfile.frontend b/Dockerfile.frontend new file mode 100644 index 00000000..53c4a756 --- /dev/null +++ b/Dockerfile.frontend @@ -0,0 +1,37 @@ +# Use an official Python runtime as a parent image +FROM python:3.11-slim as frontend + +# Set environment variables +ENV PYTHONDONTWRITEBYTECODE 1 +ENV PYTHONUNBUFFERED 1 + +# Set work directory in the container +WORKDIR /app + + +# Install Poetry +ENV POETRY_VERSION=1.1.8 \ + POETRY_HOME="/opt/poetry" \ + POETRY_NO_INTERACTION=1 \ + POETRY_VIRTUALENVS_CREATE=false \ + PATH="$POETRY_HOME/bin:$PATH" + +RUN pip3 install --no-cache-dir python-dotenv poetry + +COPY pyproject.toml poetry.lock* /app/ + +RUN mkdir /app/frontend +RUN touch /app/frontend/__init__.py +RUN touch /app/README.md + +# Install dependencies +RUN poetry install --no-interaction --no-ansi + +# Copy the rest of the application code +COPY frontend/ /app + +# Expose the application port +EXPOSE 8501 + +# Command to run the application +ENTRYPOINT ["streamlit", "run", "chat.py", "--server.port=8501", "--server.address=0.0.0.0"] diff --git a/README.md b/README.md index 5d399c87..486c35f5 100644 --- a/README.md +++ b/README.md @@ -49,6 +49,8 @@ If you want both the db and app running: docker compose -f docker-compose.full.yml up ``` +The visit localhost:8501 to use the frontend to chat and build your codebase. + ### Step 3: Configure and Migrate Database In a new terminal, copy the .env file template: diff --git a/docker-compose.full.yml b/docker-compose.full.yml index 5e226197..d3cf72db 100644 --- a/docker-compose.full.yml +++ b/docker-compose.full.yml @@ -44,12 +44,24 @@ services: "CMD", "curl", "-f", - "http://localhost:${PORT:-8000}/docs" + "http://localhost:8080/docs" ] interval: 30s timeout: 10s retries: 3 start_period: 10s + frontend: + build: + context: . + dockerfile: Dockerfile.frontend + ports: + - "8501:8501" + networks: + - codex_network + depends_on: + - app + environment: + BACKEND_URL: "http://app:8080" networks: codex_network: diff --git a/frontend/__init__.py b/frontend/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/frontend/chat.py b/frontend/chat.py new file mode 100644 index 00000000..c8946e58 --- /dev/null +++ b/frontend/chat.py @@ -0,0 +1,183 @@ +import uuid +import asyncio +from datetime import datetime, timedelta, timezone +from codex_client import CodexClient +import logging + +import streamlit as st + + +# Set up logging +logging.basicConfig(level=logging.INFO) +logger = logging.getLogger(__name__) + +# Streamlit app +if "id" not in st.session_state: + st.session_state.id = uuid.uuid4() + st.session_state.file_cache = {} +if "process_complete" not in st.session_state: + st.session_state.process_complete = False + +session_id = st.session_state.id +client = None + +st.set_page_config(layout="wide") + +if not st.session_state.process_complete: + st.title("AutoGPT Coding Ability") + + # Input fields + client_url = "http://localhost:8080/api/v1" + project_name = st.text_input("Name your project") + task = st.text_area("Describe your project") + user_id = "" + codex_id = "" + + # Initialize session state attributes + if "progress" not in st.session_state: + st.session_state.progress = 0 + if "codex_client" not in st.session_state: + st.session_state.codex_client = None + if "interview_response" not in st.session_state: + st.session_state.interview_response = None + if "user_message" not in st.session_state: + st.session_state.user_message = "" + if "messages" not in st.session_state: + st.session_state.messages = [] + + async def init_codex_client(user_id, codex_id, client_url): + codex_client = CodexClient(base_url=client_url) + await codex_client.init(cloud_services_user_id=user_id, codex_user_id=codex_id) + st.session_state.codex_client = codex_client + + async def create_app_and_start_interview(codex_client): + try: + app = await codex_client.create_app(app_name=project_name, description=task) + st.session_state.app_id = app.id + logger.info(f"Application Created: {app.id}") + st.session_state.messages.append("App creation started! Let's gooo") + + interview = await codex_client.start_interview(name=project_name, task=task) + st.session_state.interview_id = interview.id + st.session_state.progress = 1 + st.session_state.interview_response = interview + st.session_state.messages.append(interview.say_to_user) + except Exception as e: + logger.error(f"Failed to create app: {e}") + st.error(f"Failed to create app: {e}") + + async def handle_interview(codex_client, interview_response, user_message): + try: + interview_response = await codex_client.interview_next(user_message) + st.session_state.messages.append(interview_response.say_to_user) + st.session_state.interview_response = interview_response + + if interview_response.phase_completed: + if interview_response.phase in ["ARCHITECT", "COMPLETED"]: + future_time = datetime.now(timezone.utc) + timedelta(minutes=15) + future_timestamp = int(future_time.timestamp()) + st.session_state.messages.append( + f"Okay starting developing app... Expected completion time: {future_timestamp}" + ) + st.session_state.progress = 2 + elif interview_response.phase == "FEATURES": + st.session_state.messages.append(interview_response.say_to_user) + interview_response = await codex_client.interview_next("") + st.session_state.interview_response = interview_response + except Exception as e: + logger.error(f"Failed to handle interview: {e}") + st.error(f"Failed to handle interview: {e}") + + async def generate_spec(codex_client): + try: + spec_response = await codex_client.generate_spec() + st.session_state.spec_id = spec_response.id + logger.info(f"Spec Generated: {spec_response.id}") + st.session_state.messages.append("Specification Generated!") + st.session_state.progress = 3 + st.experimental_rerun() + return spec_response + except Exception as e: + logger.error(f"Failed to generate spec: {e}") + st.error(f"Failed to generate spec: {e}") + + async def generate_deliverable(codex_client): + try: + deliverable_response = await codex_client.generate_deliverable() + st.session_state.deliverable_id = deliverable_response.id + logger.info(f"Deliverable Generated: {deliverable_response.id}") + st.session_state.messages.append("Deliverable Generated!") + st.session_state.progress = 4 + st.experimental_rerun() + return deliverable_response + except Exception as e: + logger.error(f"Failed to generate deliverable: {e}") + st.error(f"Failed to generate deliverable: {e}") + + async def create_deployment(codex_client): + try: + deployment_response = await codex_client.create_deployment() + st.session_state.deployment_id = deployment_response.id + logger.info(f"Deployment Generated: {deployment_response.id}") + st.session_state.messages.append("Deployment Created!") + st.session_state.messages.append(f"GitHub Repo: {deployment_response.repo}") + st.session_state.progress = 5 + st.session_state.github_repo = deployment_response.repo + + st.experimental_rerun() + return deployment_response + except Exception as e: + logger.error(f"Failed to create deployment: {e}") + st.error(f"Failed to create deployment: {e}") + + async def main(): + if st.session_state.codex_client is None: + await init_codex_client(user_id, codex_id, client_url) + + if st.session_state.progress == 0: + await create_app_and_start_interview(st.session_state.codex_client) + + if st.session_state.progress == 1 and st.session_state.user_message: + await handle_interview( + st.session_state.codex_client, + st.session_state.interview_response, + st.session_state.user_message, + ) + st.session_state.user_message = ( + "" # Reset the user message after handling it + ) + + if st.session_state.progress == 2: + st.write("Generating Specification...") + await generate_spec(st.session_state.codex_client) + + if st.session_state.progress == 3: + st.write("Generating Deliverable...") + await generate_deliverable(st.session_state.codex_client) + + if st.session_state.progress == 4: + st.write("Creating Deployment...") + await create_deployment(st.session_state.codex_client) + + if st.button("Start Building"): + asyncio.run(main()) + + # Display all messages in chronological order + for message in st.session_state.messages: + st.write(message) + + if st.session_state.progress == 1: + user_message = st.text_input("Your response", key="user_response") + if st.button("Submit Response"): + st.session_state.user_message = user_message + asyncio.run( + handle_interview( + st.session_state.codex_client, + st.session_state.interview_response, + user_message, + ) + ) + st.experimental_rerun() + + if st.session_state.progress in [2, 3, 4, 5]: + asyncio.run(main()) diff --git a/frontend/codex_client.py b/frontend/codex_client.py new file mode 100644 index 00000000..eabea781 --- /dev/null +++ b/frontend/codex_client.py @@ -0,0 +1,412 @@ +from typing import Tuple +import logging +import aiohttp +from pydantic import ValidationError +from typing import Optional +from codex_model import ( + ApplicationResponse, + ApplicationCreate, + InterviewResponse, + InterviewNextRequest, + SpecificationResponse, + DeliverableResponse, + DeploymentResponse, +) + +logger = logging.getLogger(__name__) + +# Hardcoded user data +HARDCODED_USER_ID = "7b3a9e01-4ede-4a56-919b-d7063ba3c6e3" +HARDCODED_CODEX_ID = "7b3a9e01-4ede-4a56-919b-d7063ba3c6e3" +HARDCODED_DISCORD_ID = "hardcoded_discord_id" + + +class CodexClient: + def __init__( + self, + base_url: Optional[str] = None, + auth_key: Optional[str] = None, + ): + """ + Initialize the codex client. + + Args: + base_url (str, optional): the base url for the codex service. Defaults to None to use the production url. + auth_key (str, optional): the authorization key for the codex service. Defaults to None. + """ + # Set the base url for codex + if not base_url: + self.base_url = "https://codegen-xca4qjgx4a-uc.a.run.app/api/v1" + else: + self.base_url = base_url + + # Set the headers + self.headers: dict[str, str] = {"accept": "application/json"} + if auth_key: + self.headers["Authorization"] = f"Bearer {auth_key}" + + self.app_id: Optional[str] = None + self.interview_id: Optional[str] = None + self.specification_id: Optional[str] = None + self.deliverable_id: Optional[str] = None + self.deployment_id: Optional[str] = None + + async def init( + self, + cloud_services_user_id: Optional[str] = None, + codex_user_id: Optional[str] = None, + app_id: Optional[str] = None, + interview_id: Optional[str] = None, + specification_id: Optional[str] = None, + deliverable_id: Optional[str] = None, + deployment_id: Optional[str] = None, + ): + """ + Initialize the async part of the codex client. + + Sets the user and the codex_user_id. + + Args: + cloud_services_user_id (str): the id of the user in the cloud services + codex_user_id (str): the id of the user in the codex service + """ + # Using hardcoded values + self.codex_user_id = HARDCODED_CODEX_ID + self.user_id = HARDCODED_USER_ID + self.user = { + "id": HARDCODED_USER_ID, + "codexId": HARDCODED_CODEX_ID, + "discordId": HARDCODED_DISCORD_ID, + } + + if app_id: + self.app_id = app_id + if interview_id: + self.interview_id = interview_id + if specification_id: + self.specification_id = specification_id + if deliverable_id: + self.deliverable_id = deliverable_id + if deployment_id: + self.deployment_id = deployment_id + + async def create_app(self, app_name: str, description: str) -> ApplicationResponse: + """ + Creates a new app for the given user. + + Args: + app_name (str): The name of the new app to be created. + description (str): The description of the new app to be created. + + Returns: + ApplicationResponse: The response from the server after attempting to create the app. + """ + + url = f"{self.base_url}/user/{self.codex_user_id}/apps/" + data = ApplicationCreate(name=app_name, description=description) + + try: + async with aiohttp.ClientSession() as session: + async with session.post( + url, headers=self.headers, json=data.model_dump() + ) as response: + response.raise_for_status() + app_response = ApplicationResponse(**await response.json()) + self.app_id = app_response.id + return app_response + + except aiohttp.ClientError as e: + logger.exception(f"Error creating app: {e}") + raise e + except ValidationError as e: + logger.exception(f"Error parsing app: {e}") + raise e + except Exception as e: + logger.exception(f"Unknown Error when trying to create an app: {e}") + raise e + + async def get_app(self, app_id: Optional[str] = None) -> ApplicationResponse: + """ + Get the app from the codex service. + + Args: + app_id (str): the id of the app + + Returns: + ApplicationResponse: the response from the server after attempting to get the app. + """ + if not app_id and not self.app_id: + raise ValueError("You must provide an app_id to get the app") + url = f"{self.base_url}/user/{self.codex_user_id}/apps/{app_id or self.app_id}" + + try: + async with aiohttp.ClientSession() as session: + async with session.get(url, headers=self.headers) as response: + response.raise_for_status() + app_response = ApplicationResponse(**await response.json()) + return app_response + + except aiohttp.ClientError as e: + logger.exception(f"Error getting app: {e}") + raise e + except ValidationError as e: + logger.exception(f"Error parsing app: {e}") + raise e + except Exception as e: + logger.exception(f"Unknown Error when trying to get app: {e}") + raise e + + async def start_interview( + self, + name: str, + task: str, + ) -> InterviewResponse: + """ + Start an interview for the app. + """ + + if not self.app_id: + raise ValueError("You must create an app before starting an interview") + url = f"{self.base_url}/user/{self.codex_user_id}/apps/{self.app_id}/interview/" + + try: + async with aiohttp.ClientSession() as session: + async with session.post(url, headers=self.headers) as response: + if response.status != 200: + logger.error(f"Error starting interview: {response.status}") + logger.error(await response.text()) + response.raise_for_status() + interview_response = InterviewResponse(**await response.json()) + self.interview_id = interview_response.id + return interview_response + except aiohttp.ClientError as e: + logger.exception(f"Error starting interview: {e}") + raise e + except ValidationError as e: + logger.exception(f"Error parsing interview: {e}") + raise e + except Exception as e: + logger.exception(f"Unknown Error when trying to start the interview: {e}") + raise e + + async def interview_next(self, user_message: str) -> InterviewResponse: + """ + Answer the next question in the interview. + + Args: + user_message (str): A message from the user + Returns: + InterviewResponse: The response from the server after attempting to answer the next question in the interview. + """ + if not self.app_id or not self.interview_id: + raise ValueError( + "You must create an app and participate in an interview before answering the next question" + ) + url = f"{self.base_url}/user/{self.codex_user_id}/apps/{self.app_id}/interview/{self.interview_id}/next" + + obj = InterviewNextRequest(msg=user_message) + + try: + async with aiohttp.ClientSession() as session: + async with session.post( + url, headers=self.headers, json=obj.model_dump() + ) as response: + response.raise_for_status() + interview_response = InterviewResponse(**await response.json()) + return interview_response + except aiohttp.ClientError as e: + logger.exception(f"Error answering next question: {e}") + raise e + except ValidationError as e: + logger.exception(f"Error parsing next question: {e}") + raise e + except Exception as e: + logger.exception( + f"Unknown Error when trying to answer the next question: {e}" + ) + raise e + + async def generate_spec(self) -> SpecificationResponse: + """ + Generate the requirements for the app based on the given description. + + Returns: + SpecificationResponse: The response from the server after attempting to generate the app specifications. + """ + if not self.app_id and not self.interview_id: + raise ValueError( + "You must create an app and participate in an interview before generating a spec" + ) + url = f"{self.base_url}/user/{self.codex_user_id}/apps/{self.app_id}/specs/" + + try: + async with aiohttp.ClientSession() as session: + async with session.post( + url, + headers=self.headers, + timeout=3000, + params={"interview_id": self.interview_id}, + ) as response: + response.raise_for_status() + spec_response = SpecificationResponse(**await response.json()) + self.specification_id = spec_response.id + return spec_response + + except aiohttp.ClientError as e: + logger.exception(f"Error generating app spec: {e}") + raise e + except ValidationError as e: + logger.exception(f"Error parsing app spec: {e}") + raise e + except Exception as e: + logger.exception(f"Unknown Error when trying to generate the spec: {e}") + raise e + + async def generate_deliverable(self) -> DeliverableResponse: + """ + Generate the deliverable for the app based on a specific specification. + + Returns: + DeliverableResponse: The response from the server after attempting to generate the app deliverable. + """ + if not self.app_id or not self.specification_id: + raise ValueError( + "You must create an app and generate a spec before generating a deliverable" + ) + url = f"{self.base_url}/user/{self.codex_user_id}/apps/{self.app_id}/specs/{self.specification_id}/deliverables/" + + try: + async with aiohttp.ClientSession() as session: + async with session.post( + url, headers=self.headers, timeout=3000 + ) as response: + response.raise_for_status() + deliverable_response = DeliverableResponse(**await response.json()) + self.deliverable_id = deliverable_response.id + return deliverable_response + + except aiohttp.ClientError as e: + logger.exception(f"Error generating app deliverable: {e}") + raise e + except ValidationError as e: + logger.exception(f"Error parsing app deliverable: {e}") + raise e + + except Exception as e: + logger.exception( + f"Unknown Error when trying to generate the deliverable: {e}" + ) + raise e + + async def create_deployment(self) -> DeploymentResponse: + """ + Create a deployment for the app based on the deliverable. + + Returns: + DeploymentResponse: The response from the server after attempting to create the app deployment. + """ + if not self.app_id or not self.specification_id or not self.deliverable_id: + raise ValueError( + "You must create an app, generate a spec, and generate a deliverable before creating a deployment" + ) + url = f"{self.base_url}/user/{self.codex_user_id}/apps/{self.app_id}/specs/{self.specification_id}/deliverables/{self.deliverable_id}/deployments/" + + try: + async with aiohttp.ClientSession() as session: + async with session.post(url, headers=self.headers) as response: + if response.status != 200: + logger.error(f"Error creating deployment: {response.status}") + logger.error(await response.text()) + response.raise_for_status() + deployment_response = DeploymentResponse(**await response.json()) + self.deployment_id = deployment_response.id + return deployment_response + except aiohttp.ClientError as e: + logger.exception(f"Error creating app deployment: {e}") + raise e + except ValidationError as e: + logger.exception(f"Error parsing app deployment: {e}") + raise e + except Exception as e: + logger.exception(f"Unknown Error when trying to create the deployment: {e}") + raise e + + async def download_zip(self) -> Tuple[bytes, str]: + """ + Step 6: Download the deployment zip file. + + Note: The request returns a FastAPI streaming response. + + Returns: + Tuple[bytes, str]: The bytes of the zip file and the name of the file. + """ + if not self.deployment_id: + raise ValueError("You must create a deployment before downloading a zip") + url = f"{self.base_url}/deployments/{self.deployment_id}/download" + try: + async with aiohttp.ClientSession() as session: + async with session.get(url, headers=self.headers) as response: + response.raise_for_status() + content = await response.read() + filename = response.headers.get("Content-Disposition", "").split( + "filename=" + )[1] + return content, filename + except aiohttp.ClientError as e: + logger.exception(f"HTTP error occurred: {e}") + raise e + except Exception as err: + logger.exception(f"An error occurred: {err}") + raise + + @staticmethod + async def build_codex_client( + cloud_services_user_id: str, + codex_user_id: str, + base_url: Optional[str] = None, + auth_key: Optional[str] = None, + app_id: Optional[str] = None, + interview_id: Optional[str] = None, + spec_id: Optional[str] = None, + deliverable_id: Optional[str] = None, + deployment_id: Optional[str] = None, + ) -> "CodexClient": + """ + Build the codex client without database dependency. + + Returns: + CodexClient: The codex client. + """ + codex = CodexClient( + base_url=base_url, + auth_key=auth_key, + ) + await codex.init( + cloud_services_user_id=cloud_services_user_id, + codex_user_id=codex_user_id, + ) + + if interview_id and not app_id: + raise ValueError( + "You must provide an app_id if you provide an interview_id" + ) + if spec_id and not interview_id and not app_id: + raise ValueError( + "You must provide an app_id and interview_id if you provide a spec_id" + ) + if deliverable_id and not spec_id and not app_id: + raise ValueError( + "You must provide an app_id and a spec_id if you provide a deliverable_id" + ) + if deployment_id and not deliverable_id and not spec_id and not app_id: + raise ValueError( + "You must provide an app_id, a spec_id, and a deliverable_id if you provide a deployment_id" + ) + + codex.app_id = app_id + codex.interview_id = interview_id + codex.specification_id = spec_id + codex.deliverable_id = deliverable_id + codex.deployment_id = deployment_id + + return codex diff --git a/frontend/codex_model.py b/frontend/codex_model.py new file mode 100644 index 00000000..d400f0d6 --- /dev/null +++ b/frontend/codex_model.py @@ -0,0 +1,210 @@ +import enum +import logging +from datetime import datetime +from typing import List, Optional + +from pydantic import BaseModel, Field + +logger = logging.getLogger(__name__) + + +class Role(enum.Enum): + USER = "USER" + ADMIN = "ADMIN" + + +class Identifiers(BaseModel): + user_id: str + cloud_services_id: str + app_id: str + interview_id: str | None = None + spec_id: str | None = None + completed_app_id: str | None = None + deployment_id: str | None = None + function_def_id: str | None = None + + +class Pagination(BaseModel): + total_items: int = Field(..., description="Total number of items.", examples=[42]) + total_pages: int = Field(..., description="Total number of pages.", examples=[97]) + current_page: int = Field( + ..., description="Current_page page number.", examples=[1] + ) + page_size: int = Field(..., description="Number of items per page.", examples=[25]) + + +###### USERS ###### + + +class UserBase(BaseModel): + cloud_services_id: str = Field( + ..., description="The unique identifier of the user in cloud services" + ) + discord_id: Optional[str] = Field( + None, description="The unique Discord ID of the user" + ) + + +class UserCreate(UserBase): + pass + + +class UserUpdate(BaseModel): + id: str = Field(..., description="The unique identifier of the user") + role: Role = Field(default=Role.USER, description="The role of the user") + + +class UserResponse(BaseModel): + id: str + cloud_services_id: str + discord_id: str + createdAt: datetime + role: Role + + +class UsersListResponse(BaseModel): + users: List[UserResponse] + pagination: Optional[Pagination] = None + + +####### APPS ####### + + +class ApplicationBase(BaseModel): + name: str = Field(..., description="The name of the application") + + +class ApplicationCreate(ApplicationBase): + """ApplicationCreate is the model for creating a new application. It includes the name and description of the application (from the base)""" + + description: str = Field(..., description="The description of the application") + pass + + +class ApplicationResponse(ApplicationBase): + id: str = Field(..., description="The unique identifier of the application") + createdAt: datetime = Field( + description="The date and time the application was created" + ) + updatedAt: datetime = Field( + description="The date and time the application was last updated" + ) + userid: str + + +class ApplicationsListResponse(BaseModel): + applications: List[ApplicationResponse] + pagination: Optional[Pagination] = None + + +####### INTERVIEWS ####### + + +class InterviewNextRequest(BaseModel): + msg: str + + +class Feature(BaseModel): + name: str + functionality: str + + +class InterviewResponse(BaseModel): + id: str + say_to_user: str + phase: str + phase_completed: bool + + +###### SPECS ###### + + +class ParamModel(BaseModel): + id: str + createdAt: datetime + name: str + description: str + param_type: str + + +class RequestObjectModel(BaseModel): + id: str + createdAt: datetime + name: str + description: str + params: List[ParamModel] = [] + + +class ResponseObjectModel(BaseModel): + id: str + createdAt: datetime + name: str + description: str + params: List[ParamModel] = [] + + +class APIRouteSpecModel(BaseModel): + id: str + createdAt: datetime + method: str + path: str + description: str + requestObject: Optional[RequestObjectModel] = None + responseObject: Optional[ResponseObjectModel] = None + + +class SpecificationBase(BaseModel): + pass + + +class SpecificationDelayedResponse(BaseModel): + message: str + + +class SpecificationResponse(BaseModel): + id: str + createdAt: datetime + name: str + context: str + apiRouteSpecs: List[APIRouteSpecModel] = [] + + +class SpecificationsListResponse(BaseModel): + specs: List[SpecificationResponse] | List[None] = [] + pagination: Optional[Pagination] = None + + +### Deliverables ### + + +class CompiledRouteModel(BaseModel): + id: str + createdAt: datetime + description: str + code: str + + +class DeliverableResponse(BaseModel): + id: str + created_at: datetime + name: str + description: str + + +class DeliverablesListResponse(BaseModel): + deliverables: List[DeliverableResponse] + pagination: Optional[Pagination] = None + + +### Deployements ### + + +class DeploymentResponse(BaseModel): + id: str + created_at: datetime + repo: str + + +class DeploymentsListResponse(BaseModel): + deployments: List[DeploymentResponse] + pagination: Optional[Pagination] = None diff --git a/poetry.lock b/poetry.lock index 348096a4..f039d3ef 100644 --- a/poetry.lock +++ b/poetry.lock @@ -120,6 +120,30 @@ files = [ [package.dependencies] frozenlist = ">=1.1.0" +[[package]] +name = "altair" +version = "5.3.0" +description = "Vega-Altair: A declarative statistical visualization library for Python." +optional = false +python-versions = ">=3.8" +files = [ + {file = "altair-5.3.0-py3-none-any.whl", hash = "sha256:7084a1dab4d83c5e7e5246b92dc1b4451a6c68fd057f3716ee9d315c8980e59a"}, + {file = "altair-5.3.0.tar.gz", hash = "sha256:5a268b1a0983b23d8f9129f819f956174aa7aea2719ed55a52eba9979b9f6675"}, +] + +[package.dependencies] +jinja2 = "*" +jsonschema = ">=3.0" +numpy = "*" +packaging = "*" +pandas = ">=0.25" +toolz = "*" + +[package.extras] +all = ["altair-tiles (>=0.3.0)", "anywidget (>=0.9.0)", "pyarrow (>=11)", "vega-datasets (>=0.9.0)", "vegafusion[embed] (>=1.6.6)", "vl-convert-python (>=1.3.0)"] +dev = ["geopandas", "hatch", "ipython", "m2r", "mypy", "pandas-stubs", "pytest", "pytest-cov", "ruff (>=0.3.0)", "types-jsonschema", "types-setuptools"] +doc = ["docutils", "jinja2", "myst-parser", "numpydoc", "pillow (>=9,<10)", "pydata-sphinx-theme (>=0.14.1)", "scipy", "sphinx", "sphinx-copybutton", "sphinx-design", "sphinxext-altair"] + [[package]] name = "annotated-types" version = "0.6.0" @@ -225,6 +249,17 @@ d = ["aiohttp (>=3.7.4)", "aiohttp (>=3.7.4,!=3.9.0)"] jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] uvloop = ["uvloop (>=0.15.2)"] +[[package]] +name = "blinker" +version = "1.8.2" +description = "Fast, simple object-to-object and broadcast signaling" +optional = false +python-versions = ">=3.8" +files = [ + {file = "blinker-1.8.2-py3-none-any.whl", hash = "sha256:1779309f71bf239144b9399d06ae925637cf6634cf6bd131104184531bf67c01"}, + {file = "blinker-1.8.2.tar.gz", hash = "sha256:8f77b09d3bf7c795e969e9486f39c2c5e9c39d4ee07424be2bc594ece9642d83"}, +] + [[package]] name = "cachetools" version = "5.3.3" @@ -1460,6 +1495,41 @@ MarkupSafe = ">=2.0" [package.extras] i18n = ["Babel (>=2.7)"] +[[package]] +name = "jsonschema" +version = "4.22.0" +description = "An implementation of JSON Schema validation for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "jsonschema-4.22.0-py3-none-any.whl", hash = "sha256:ff4cfd6b1367a40e7bc6411caec72effadd3db0bbe5017de188f2d6108335802"}, + {file = "jsonschema-4.22.0.tar.gz", hash = "sha256:5b22d434a45935119af990552c862e5d6d564e8f6601206b305a61fdf661a2b7"}, +] + +[package.dependencies] +attrs = ">=22.2.0" +jsonschema-specifications = ">=2023.03.6" +referencing = ">=0.28.4" +rpds-py = ">=0.7.1" + +[package.extras] +format = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3987", "uri-template", "webcolors (>=1.11)"] +format-nongpl = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3986-validator (>0.1.0)", "uri-template", "webcolors (>=1.11)"] + +[[package]] +name = "jsonschema-specifications" +version = "2023.12.1" +description = "The JSON Schema meta-schemas and vocabularies, exposed as a Registry" +optional = false +python-versions = ">=3.8" +files = [ + {file = "jsonschema_specifications-2023.12.1-py3-none-any.whl", hash = "sha256:87e4fdf3a94858b8a2ba2778d9ba57d8a9cafca7c7489c46ba0d30a8bc6a9c3c"}, + {file = "jsonschema_specifications-2023.12.1.tar.gz", hash = "sha256:48a76787b3e70f5ed53f1160d2b81f586e4ca6d1548c5de7085d1682674764cc"}, +] + +[package.dependencies] +referencing = ">=0.31.0" + [[package]] name = "kiwisolver" version = "1.4.5" @@ -1691,6 +1761,30 @@ files = [ [package.dependencies] rapidfuzz = ">=3.8.0,<4.0.0" +[[package]] +name = "markdown-it-py" +version = "3.0.0" +description = "Python port of markdown-it. Markdown parsing, done right!" +optional = false +python-versions = ">=3.8" +files = [ + {file = "markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb"}, + {file = "markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1"}, +] + +[package.dependencies] +mdurl = ">=0.1,<1.0" + +[package.extras] +benchmarking = ["psutil", "pytest", "pytest-benchmark"] +code-style = ["pre-commit (>=3.0,<4.0)"] +compare = ["commonmark (>=0.9,<1.0)", "markdown (>=3.4,<4.0)", "mistletoe (>=1.0,<2.0)", "mistune (>=2.0,<3.0)", "panflute (>=2.3,<3.0)"] +linkify = ["linkify-it-py (>=1,<3)"] +plugins = ["mdit-py-plugins"] +profiling = ["gprof2dot"] +rtd = ["jupyter_sphinx", "mdit-py-plugins", "myst-parser", "pyyaml", "sphinx", "sphinx-copybutton", "sphinx-design", "sphinx_book_theme"] +testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"] + [[package]] name = "markdown2" version = "2.4.13" @@ -1824,6 +1918,17 @@ pillow = ">=8" pyparsing = ">=2.3.1" python-dateutil = ">=2.7" +[[package]] +name = "mdurl" +version = "0.1.2" +description = "Markdown URL utilities" +optional = false +python-versions = ">=3.7" +files = [ + {file = "mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"}, + {file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"}, +] + [[package]] name = "multidict" version = "6.0.5" @@ -2525,6 +2630,54 @@ files = [ {file = "psycopg2_binary-2.9.9-cp39-cp39-win_amd64.whl", hash = "sha256:f7ae5d65ccfbebdfa761585228eb4d0df3a8b15cfb53bd953e713e09fbb12957"}, ] +[[package]] +name = "pyarrow" +version = "16.1.0" +description = "Python library for Apache Arrow" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pyarrow-16.1.0-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:17e23b9a65a70cc733d8b738baa6ad3722298fa0c81d88f63ff94bf25eaa77b9"}, + {file = "pyarrow-16.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4740cc41e2ba5d641071d0ab5e9ef9b5e6e8c7611351a5cb7c1d175eaf43674a"}, + {file = "pyarrow-16.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:98100e0268d04e0eec47b73f20b39c45b4006f3c4233719c3848aa27a03c1aef"}, + {file = "pyarrow-16.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f68f409e7b283c085f2da014f9ef81e885d90dcd733bd648cfba3ef265961848"}, + {file = "pyarrow-16.1.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:a8914cd176f448e09746037b0c6b3a9d7688cef451ec5735094055116857580c"}, + {file = "pyarrow-16.1.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:48be160782c0556156d91adbdd5a4a7e719f8d407cb46ae3bb4eaee09b3111bd"}, + {file = "pyarrow-16.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:9cf389d444b0f41d9fe1444b70650fea31e9d52cfcb5f818b7888b91b586efff"}, + {file = "pyarrow-16.1.0-cp311-cp311-macosx_10_15_x86_64.whl", hash = "sha256:d0ebea336b535b37eee9eee31761813086d33ed06de9ab6fc6aaa0bace7b250c"}, + {file = "pyarrow-16.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2e73cfc4a99e796727919c5541c65bb88b973377501e39b9842ea71401ca6c1c"}, + {file = "pyarrow-16.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf9251264247ecfe93e5f5a0cd43b8ae834f1e61d1abca22da55b20c788417f6"}, + {file = "pyarrow-16.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ddf5aace92d520d3d2a20031d8b0ec27b4395cab9f74e07cc95edf42a5cc0147"}, + {file = "pyarrow-16.1.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:25233642583bf658f629eb230b9bb79d9af4d9f9229890b3c878699c82f7d11e"}, + {file = "pyarrow-16.1.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:a33a64576fddfbec0a44112eaf844c20853647ca833e9a647bfae0582b2ff94b"}, + {file = "pyarrow-16.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:185d121b50836379fe012753cf15c4ba9638bda9645183ab36246923875f8d1b"}, + {file = "pyarrow-16.1.0-cp312-cp312-macosx_10_15_x86_64.whl", hash = "sha256:2e51ca1d6ed7f2e9d5c3c83decf27b0d17bb207a7dea986e8dc3e24f80ff7d6f"}, + {file = "pyarrow-16.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:06ebccb6f8cb7357de85f60d5da50e83507954af617d7b05f48af1621d331c9a"}, + {file = "pyarrow-16.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b04707f1979815f5e49824ce52d1dceb46e2f12909a48a6a753fe7cafbc44a0c"}, + {file = "pyarrow-16.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0d32000693deff8dc5df444b032b5985a48592c0697cb6e3071a5d59888714e2"}, + {file = "pyarrow-16.1.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:8785bb10d5d6fd5e15d718ee1d1f914fe768bf8b4d1e5e9bf253de8a26cb1628"}, + {file = "pyarrow-16.1.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:e1369af39587b794873b8a307cc6623a3b1194e69399af0efd05bb202195a5a7"}, + {file = "pyarrow-16.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:febde33305f1498f6df85e8020bca496d0e9ebf2093bab9e0f65e2b4ae2b3444"}, + {file = "pyarrow-16.1.0-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:b5f5705ab977947a43ac83b52ade3b881eb6e95fcc02d76f501d549a210ba77f"}, + {file = "pyarrow-16.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:0d27bf89dfc2576f6206e9cd6cf7a107c9c06dc13d53bbc25b0bd4556f19cf5f"}, + {file = "pyarrow-16.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0d07de3ee730647a600037bc1d7b7994067ed64d0eba797ac74b2bc77384f4c2"}, + {file = "pyarrow-16.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fbef391b63f708e103df99fbaa3acf9f671d77a183a07546ba2f2c297b361e83"}, + {file = "pyarrow-16.1.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:19741c4dbbbc986d38856ee7ddfdd6a00fc3b0fc2d928795b95410d38bb97d15"}, + {file = "pyarrow-16.1.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:f2c5fb249caa17b94e2b9278b36a05ce03d3180e6da0c4c3b3ce5b2788f30eed"}, + {file = "pyarrow-16.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:e6b6d3cd35fbb93b70ade1336022cc1147b95ec6af7d36906ca7fe432eb09710"}, + {file = "pyarrow-16.1.0-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:18da9b76a36a954665ccca8aa6bd9f46c1145f79c0bb8f4f244f5f8e799bca55"}, + {file = "pyarrow-16.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:99f7549779b6e434467d2aa43ab2b7224dd9e41bdde486020bae198978c9e05e"}, + {file = "pyarrow-16.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f07fdffe4fd5b15f5ec15c8b64584868d063bc22b86b46c9695624ca3505b7b4"}, + {file = "pyarrow-16.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ddfe389a08ea374972bd4065d5f25d14e36b43ebc22fc75f7b951f24378bf0b5"}, + {file = "pyarrow-16.1.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:3b20bd67c94b3a2ea0a749d2a5712fc845a69cb5d52e78e6449bbd295611f3aa"}, + {file = "pyarrow-16.1.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:ba8ac20693c0bb0bf4b238751d4409e62852004a8cf031c73b0e0962b03e45e3"}, + {file = "pyarrow-16.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:31a1851751433d89a986616015841977e0a188662fcffd1a5677453f1df2de0a"}, + {file = "pyarrow-16.1.0.tar.gz", hash = "sha256:15fbb22ea96d11f0b5768504a3f961edab25eaf4197c341720c4a387f6c60315"}, +] + +[package.dependencies] +numpy = ">=1.16.6" + [[package]] name = "pyasn1" version = "0.6.0" @@ -2672,6 +2825,25 @@ files = [ [package.dependencies] typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" +[[package]] +name = "pydeck" +version = "0.9.1" +description = "Widget for deck.gl maps" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pydeck-0.9.1-py2.py3-none-any.whl", hash = "sha256:b3f75ba0d273fc917094fa61224f3f6076ca8752b93d46faf3bcfd9f9d59b038"}, + {file = "pydeck-0.9.1.tar.gz", hash = "sha256:f74475ae637951d63f2ee58326757f8d4f9cd9f2a457cf42950715003e2cb605"}, +] + +[package.dependencies] +jinja2 = ">=2.10.1" +numpy = ">=1.16.4" + +[package.extras] +carto = ["pydeck-carto"] +jupyter = ["ipykernel (>=5.1.2)", "ipython (>=5.8.0)", "ipywidgets (>=7,<8)", "traitlets (>=4.3.2)"] + [[package]] name = "pygithub" version = "2.3.0" @@ -3145,6 +3317,21 @@ files = [ [package.extras] full = ["numpy"] +[[package]] +name = "referencing" +version = "0.35.1" +description = "JSON Referencing + Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "referencing-0.35.1-py3-none-any.whl", hash = "sha256:eda6d3234d62814d1c64e305c1331c9a3a6132da475ab6382eaa997b21ee75de"}, + {file = "referencing-0.35.1.tar.gz", hash = "sha256:25b42124a6c8b632a425174f24087783efb348a6f1e0008e63cd4466fedf703c"}, +] + +[package.dependencies] +attrs = ">=22.2.0" +rpds-py = ">=0.7.0" + [[package]] name = "regex" version = "2024.4.16" @@ -3286,6 +3473,132 @@ requests = ">=2.0.0" [package.extras] rsa = ["oauthlib[signedtoken] (>=3.0.0)"] +[[package]] +name = "rich" +version = "13.7.1" +description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" +optional = false +python-versions = ">=3.7.0" +files = [ + {file = "rich-13.7.1-py3-none-any.whl", hash = "sha256:4edbae314f59eb482f54e9e30bf00d33350aaa94f4bfcd4e9e3110e64d0d7222"}, + {file = "rich-13.7.1.tar.gz", hash = "sha256:9be308cb1fe2f1f57d67ce99e95af38a1e2bc71ad9813b0e247cf7ffbcc3a432"}, +] + +[package.dependencies] +markdown-it-py = ">=2.2.0" +pygments = ">=2.13.0,<3.0.0" + +[package.extras] +jupyter = ["ipywidgets (>=7.5.1,<9)"] + +[[package]] +name = "rpds-py" +version = "0.18.1" +description = "Python bindings to Rust's persistent data structures (rpds)" +optional = false +python-versions = ">=3.8" +files = [ + {file = "rpds_py-0.18.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:d31dea506d718693b6b2cffc0648a8929bdc51c70a311b2770f09611caa10d53"}, + {file = "rpds_py-0.18.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:732672fbc449bab754e0b15356c077cc31566df874964d4801ab14f71951ea80"}, + {file = "rpds_py-0.18.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4a98a1f0552b5f227a3d6422dbd61bc6f30db170939bd87ed14f3c339aa6c7c9"}, + {file = "rpds_py-0.18.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7f1944ce16401aad1e3f7d312247b3d5de7981f634dc9dfe90da72b87d37887d"}, + {file = "rpds_py-0.18.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:38e14fb4e370885c4ecd734f093a2225ee52dc384b86fa55fe3f74638b2cfb09"}, + {file = "rpds_py-0.18.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:08d74b184f9ab6289b87b19fe6a6d1a97fbfea84b8a3e745e87a5de3029bf944"}, + {file = "rpds_py-0.18.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d70129cef4a8d979caa37e7fe957202e7eee8ea02c5e16455bc9808a59c6b2f0"}, + {file = "rpds_py-0.18.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ce0bb20e3a11bd04461324a6a798af34d503f8d6f1aa3d2aa8901ceaf039176d"}, + {file = "rpds_py-0.18.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:81c5196a790032e0fc2464c0b4ab95f8610f96f1f2fa3d4deacce6a79852da60"}, + {file = "rpds_py-0.18.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:f3027be483868c99b4985fda802a57a67fdf30c5d9a50338d9db646d590198da"}, + {file = "rpds_py-0.18.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:d44607f98caa2961bab4fa3c4309724b185b464cdc3ba6f3d7340bac3ec97cc1"}, + {file = "rpds_py-0.18.1-cp310-none-win32.whl", hash = "sha256:c273e795e7a0f1fddd46e1e3cb8be15634c29ae8ff31c196debb620e1edb9333"}, + {file = "rpds_py-0.18.1-cp310-none-win_amd64.whl", hash = "sha256:8352f48d511de5f973e4f2f9412736d7dea76c69faa6d36bcf885b50c758ab9a"}, + {file = "rpds_py-0.18.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:6b5ff7e1d63a8281654b5e2896d7f08799378e594f09cf3674e832ecaf396ce8"}, + {file = "rpds_py-0.18.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8927638a4d4137a289e41d0fd631551e89fa346d6dbcfc31ad627557d03ceb6d"}, + {file = "rpds_py-0.18.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:154bf5c93d79558b44e5b50cc354aa0459e518e83677791e6adb0b039b7aa6a7"}, + {file = "rpds_py-0.18.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:07f2139741e5deb2c5154a7b9629bc5aa48c766b643c1a6750d16f865a82c5fc"}, + {file = "rpds_py-0.18.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8c7672e9fba7425f79019db9945b16e308ed8bc89348c23d955c8c0540da0a07"}, + {file = "rpds_py-0.18.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:489bdfe1abd0406eba6b3bb4fdc87c7fa40f1031de073d0cfb744634cc8fa261"}, + {file = "rpds_py-0.18.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3c20f05e8e3d4fc76875fc9cb8cf24b90a63f5a1b4c5b9273f0e8225e169b100"}, + {file = "rpds_py-0.18.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:967342e045564cef76dfcf1edb700b1e20838d83b1aa02ab313e6a497cf923b8"}, + {file = "rpds_py-0.18.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2cc7c1a47f3a63282ab0f422d90ddac4aa3034e39fc66a559ab93041e6505da7"}, + {file = "rpds_py-0.18.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:f7afbfee1157e0f9376c00bb232e80a60e59ed716e3211a80cb8506550671e6e"}, + {file = "rpds_py-0.18.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9e6934d70dc50f9f8ea47081ceafdec09245fd9f6032669c3b45705dea096b88"}, + {file = "rpds_py-0.18.1-cp311-none-win32.whl", hash = "sha256:c69882964516dc143083d3795cb508e806b09fc3800fd0d4cddc1df6c36e76bb"}, + {file = "rpds_py-0.18.1-cp311-none-win_amd64.whl", hash = "sha256:70a838f7754483bcdc830444952fd89645569e7452e3226de4a613a4c1793fb2"}, + {file = "rpds_py-0.18.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:3dd3cd86e1db5aadd334e011eba4e29d37a104b403e8ca24dcd6703c68ca55b3"}, + {file = "rpds_py-0.18.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:05f3d615099bd9b13ecf2fc9cf2d839ad3f20239c678f461c753e93755d629ee"}, + {file = "rpds_py-0.18.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:35b2b771b13eee8729a5049c976197ff58a27a3829c018a04341bcf1ae409b2b"}, + {file = "rpds_py-0.18.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ee17cd26b97d537af8f33635ef38be873073d516fd425e80559f4585a7b90c43"}, + {file = "rpds_py-0.18.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b646bf655b135ccf4522ed43d6902af37d3f5dbcf0da66c769a2b3938b9d8184"}, + {file = "rpds_py-0.18.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:19ba472b9606c36716062c023afa2484d1e4220548751bda14f725a7de17b4f6"}, + {file = "rpds_py-0.18.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e30ac5e329098903262dc5bdd7e2086e0256aa762cc8b744f9e7bf2a427d3f8"}, + {file = "rpds_py-0.18.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d58ad6317d188c43750cb76e9deacf6051d0f884d87dc6518e0280438648a9ac"}, + {file = "rpds_py-0.18.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e1735502458621921cee039c47318cb90b51d532c2766593be6207eec53e5c4c"}, + {file = "rpds_py-0.18.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:f5bab211605d91db0e2995a17b5c6ee5edec1270e46223e513eaa20da20076ac"}, + {file = "rpds_py-0.18.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2fc24a329a717f9e2448f8cd1f960f9dac4e45b6224d60734edeb67499bab03a"}, + {file = "rpds_py-0.18.1-cp312-none-win32.whl", hash = "sha256:1805d5901779662d599d0e2e4159d8a82c0b05faa86ef9222bf974572286b2b6"}, + {file = "rpds_py-0.18.1-cp312-none-win_amd64.whl", hash = "sha256:720edcb916df872d80f80a1cc5ea9058300b97721efda8651efcd938a9c70a72"}, + {file = "rpds_py-0.18.1-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:c827576e2fa017a081346dce87d532a5310241648eb3700af9a571a6e9fc7e74"}, + {file = "rpds_py-0.18.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:aa3679e751408d75a0b4d8d26d6647b6d9326f5e35c00a7ccd82b78ef64f65f8"}, + {file = "rpds_py-0.18.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0abeee75434e2ee2d142d650d1e54ac1f8b01e6e6abdde8ffd6eeac6e9c38e20"}, + {file = "rpds_py-0.18.1-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ed402d6153c5d519a0faf1bb69898e97fb31613b49da27a84a13935ea9164dfc"}, + {file = "rpds_py-0.18.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:338dee44b0cef8b70fd2ef54b4e09bb1b97fc6c3a58fea5db6cc083fd9fc2724"}, + {file = "rpds_py-0.18.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7750569d9526199c5b97e5a9f8d96a13300950d910cf04a861d96f4273d5b104"}, + {file = "rpds_py-0.18.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:607345bd5912aacc0c5a63d45a1f73fef29e697884f7e861094e443187c02be5"}, + {file = "rpds_py-0.18.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:207c82978115baa1fd8d706d720b4a4d2b0913df1c78c85ba73fe6c5804505f0"}, + {file = "rpds_py-0.18.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:6d1e42d2735d437e7e80bab4d78eb2e459af48c0a46e686ea35f690b93db792d"}, + {file = "rpds_py-0.18.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:5463c47c08630007dc0fe99fb480ea4f34a89712410592380425a9b4e1611d8e"}, + {file = "rpds_py-0.18.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:06d218939e1bf2ca50e6b0ec700ffe755e5216a8230ab3e87c059ebb4ea06afc"}, + {file = "rpds_py-0.18.1-cp38-none-win32.whl", hash = "sha256:312fe69b4fe1ffbe76520a7676b1e5ac06ddf7826d764cc10265c3b53f96dbe9"}, + {file = "rpds_py-0.18.1-cp38-none-win_amd64.whl", hash = "sha256:9437ca26784120a279f3137ee080b0e717012c42921eb07861b412340f85bae2"}, + {file = "rpds_py-0.18.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:19e515b78c3fc1039dd7da0a33c28c3154458f947f4dc198d3c72db2b6b5dc93"}, + {file = "rpds_py-0.18.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a7b28c5b066bca9a4eb4e2f2663012debe680f097979d880657f00e1c30875a0"}, + {file = "rpds_py-0.18.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:673fdbbf668dd958eff750e500495ef3f611e2ecc209464f661bc82e9838991e"}, + {file = "rpds_py-0.18.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d960de62227635d2e61068f42a6cb6aae91a7fe00fca0e3aeed17667c8a34611"}, + {file = "rpds_py-0.18.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:352a88dc7892f1da66b6027af06a2e7e5d53fe05924cc2cfc56495b586a10b72"}, + {file = "rpds_py-0.18.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4e0ee01ad8260184db21468a6e1c37afa0529acc12c3a697ee498d3c2c4dcaf3"}, + {file = "rpds_py-0.18.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4c39ad2f512b4041343ea3c7894339e4ca7839ac38ca83d68a832fc8b3748ab"}, + {file = "rpds_py-0.18.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:aaa71ee43a703c321906813bb252f69524f02aa05bf4eec85f0c41d5d62d0f4c"}, + {file = "rpds_py-0.18.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:6cd8098517c64a85e790657e7b1e509b9fe07487fd358e19431cb120f7d96338"}, + {file = "rpds_py-0.18.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:4adec039b8e2928983f885c53b7cc4cda8965b62b6596501a0308d2703f8af1b"}, + {file = "rpds_py-0.18.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:32b7daaa3e9389db3695964ce8e566e3413b0c43e3394c05e4b243a4cd7bef26"}, + {file = "rpds_py-0.18.1-cp39-none-win32.whl", hash = "sha256:2625f03b105328729f9450c8badda34d5243231eef6535f80064d57035738360"}, + {file = "rpds_py-0.18.1-cp39-none-win_amd64.whl", hash = "sha256:bf18932d0003c8c4d51a39f244231986ab23ee057d235a12b2684ea26a353590"}, + {file = "rpds_py-0.18.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:cbfbea39ba64f5e53ae2915de36f130588bba71245b418060ec3330ebf85678e"}, + {file = "rpds_py-0.18.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:a3d456ff2a6a4d2adcdf3c1c960a36f4fd2fec6e3b4902a42a384d17cf4e7a65"}, + {file = "rpds_py-0.18.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7700936ef9d006b7ef605dc53aa364da2de5a3aa65516a1f3ce73bf82ecfc7ae"}, + {file = "rpds_py-0.18.1-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:51584acc5916212e1bf45edd17f3a6b05fe0cbb40482d25e619f824dccb679de"}, + {file = "rpds_py-0.18.1-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:942695a206a58d2575033ff1e42b12b2aece98d6003c6bc739fbf33d1773b12f"}, + {file = "rpds_py-0.18.1-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b906b5f58892813e5ba5c6056d6a5ad08f358ba49f046d910ad992196ea61397"}, + {file = "rpds_py-0.18.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6f8e3fecca256fefc91bb6765a693d96692459d7d4c644660a9fff32e517843"}, + {file = "rpds_py-0.18.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7732770412bab81c5a9f6d20aeb60ae943a9b36dcd990d876a773526468e7163"}, + {file = "rpds_py-0.18.1-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:bd1105b50ede37461c1d51b9698c4f4be6e13e69a908ab7751e3807985fc0346"}, + {file = "rpds_py-0.18.1-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:618916f5535784960f3ecf8111581f4ad31d347c3de66d02e728de460a46303c"}, + {file = "rpds_py-0.18.1-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:17c6d2155e2423f7e79e3bb18151c686d40db42d8645e7977442170c360194d4"}, + {file = "rpds_py-0.18.1-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:6c4c4c3f878df21faf5fac86eda32671c27889e13570645a9eea0a1abdd50922"}, + {file = "rpds_py-0.18.1-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:fab6ce90574645a0d6c58890e9bcaac8d94dff54fb51c69e5522a7358b80ab64"}, + {file = "rpds_py-0.18.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:531796fb842b53f2695e94dc338929e9f9dbf473b64710c28af5a160b2a8927d"}, + {file = "rpds_py-0.18.1-pp38-pypy38_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:740884bc62a5e2bbb31e584f5d23b32320fd75d79f916f15a788d527a5e83644"}, + {file = "rpds_py-0.18.1-pp38-pypy38_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:998125738de0158f088aef3cb264a34251908dd2e5d9966774fdab7402edfab7"}, + {file = "rpds_py-0.18.1-pp38-pypy38_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e2be6e9dd4111d5b31ba3b74d17da54a8319d8168890fbaea4b9e5c3de630ae5"}, + {file = "rpds_py-0.18.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d0cee71bc618cd93716f3c1bf56653740d2d13ddbd47673efa8bf41435a60daa"}, + {file = "rpds_py-0.18.1-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2c3caec4ec5cd1d18e5dd6ae5194d24ed12785212a90b37f5f7f06b8bedd7139"}, + {file = "rpds_py-0.18.1-pp38-pypy38_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:27bba383e8c5231cd559affe169ca0b96ec78d39909ffd817f28b166d7ddd4d8"}, + {file = "rpds_py-0.18.1-pp38-pypy38_pp73-musllinux_1_2_i686.whl", hash = "sha256:a888e8bdb45916234b99da2d859566f1e8a1d2275a801bb8e4a9644e3c7e7909"}, + {file = "rpds_py-0.18.1-pp38-pypy38_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:6031b25fb1b06327b43d841f33842b383beba399884f8228a6bb3df3088485ff"}, + {file = "rpds_py-0.18.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:48c2faaa8adfacefcbfdb5f2e2e7bdad081e5ace8d182e5f4ade971f128e6bb3"}, + {file = "rpds_py-0.18.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:d85164315bd68c0806768dc6bb0429c6f95c354f87485ee3593c4f6b14def2bd"}, + {file = "rpds_py-0.18.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6afd80f6c79893cfc0574956f78a0add8c76e3696f2d6a15bca2c66c415cf2d4"}, + {file = "rpds_py-0.18.1-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fa242ac1ff583e4ec7771141606aafc92b361cd90a05c30d93e343a0c2d82a89"}, + {file = "rpds_py-0.18.1-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d21be4770ff4e08698e1e8e0bce06edb6ea0626e7c8f560bc08222880aca6a6f"}, + {file = "rpds_py-0.18.1-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5c45a639e93a0c5d4b788b2613bd637468edd62f8f95ebc6fcc303d58ab3f0a8"}, + {file = "rpds_py-0.18.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:910e71711d1055b2768181efa0a17537b2622afeb0424116619817007f8a2b10"}, + {file = "rpds_py-0.18.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b9bb1f182a97880f6078283b3505a707057c42bf55d8fca604f70dedfdc0772a"}, + {file = "rpds_py-0.18.1-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:1d54f74f40b1f7aaa595a02ff42ef38ca654b1469bef7d52867da474243cc633"}, + {file = "rpds_py-0.18.1-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:8d2e182c9ee01135e11e9676e9a62dfad791a7a467738f06726872374a83db49"}, + {file = "rpds_py-0.18.1-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:636a15acc588f70fda1661234761f9ed9ad79ebed3f2125d44be0862708b666e"}, + {file = "rpds_py-0.18.1.tar.gz", hash = "sha256:dc48b479d540770c811fbd1eb9ba2bb66951863e448efec2e2c102625328e92f"}, +] + [[package]] name = "rsa" version = "4.9" @@ -3456,6 +3769,41 @@ anyio = ">=3.4.0,<5" [package.extras] full = ["httpx (>=0.22.0)", "itsdangerous", "jinja2", "python-multipart (>=0.0.7)", "pyyaml"] +[[package]] +name = "streamlit" +version = "1.35.0" +description = "A faster way to build and share data apps" +optional = false +python-versions = "!=3.9.7,>=3.8" +files = [ + {file = "streamlit-1.35.0-py2.py3-none-any.whl", hash = "sha256:e17d1d86830a0d7687c37faf2fe47bffa752d0c95a306e96d7749bd3faa72a5b"}, + {file = "streamlit-1.35.0.tar.gz", hash = "sha256:679d55bb6189743f606abf0696623df0bfd223a6d0c8d96b8d60678d4891d2d6"}, +] + +[package.dependencies] +altair = ">=4.0,<6" +blinker = ">=1.0.0,<2" +cachetools = ">=4.0,<6" +click = ">=7.0,<9" +gitpython = ">=3.0.7,<3.1.19 || >3.1.19,<4" +numpy = ">=1.19.3,<2" +packaging = ">=16.8,<25" +pandas = ">=1.3.0,<3" +pillow = ">=7.1.0,<11" +protobuf = ">=3.20,<5" +pyarrow = ">=7.0" +pydeck = ">=0.8.0b4,<1" +requests = ">=2.27,<3" +rich = ">=10.14.0,<14" +tenacity = ">=8.1.0,<9" +toml = ">=0.10.1,<2" +tornado = ">=6.0.3,<7" +typing-extensions = ">=4.3.0,<5" +watchdog = {version = ">=2.1.5", markers = "platform_system != \"Darwin\""} + +[package.extras] +snowflake = ["snowflake-connector-python (>=2.8.0)", "snowflake-snowpark-python (>=0.9.0)"] + [[package]] name = "tenacity" version = "8.2.3" @@ -3522,6 +3870,17 @@ requests = ">=2.26.0" [package.extras] blobfile = ["blobfile (>=2)"] +[[package]] +name = "toml" +version = "0.10.2" +description = "Python Library for Tom's Obvious, Minimal Language" +optional = false +python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" +files = [ + {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, + {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, +] + [[package]] name = "tomlkit" version = "0.12.4" @@ -3533,6 +3892,37 @@ files = [ {file = "tomlkit-0.12.4.tar.gz", hash = "sha256:7ca1cfc12232806517a8515047ba66a19369e71edf2439d0f5824f91032b6cc3"}, ] +[[package]] +name = "toolz" +version = "0.12.1" +description = "List processing tools and functional utilities" +optional = false +python-versions = ">=3.7" +files = [ + {file = "toolz-0.12.1-py3-none-any.whl", hash = "sha256:d22731364c07d72eea0a0ad45bafb2c2937ab6fd38a3507bf55eae8744aa7d85"}, + {file = "toolz-0.12.1.tar.gz", hash = "sha256:ecca342664893f177a13dac0e6b41cbd8ac25a358e5f215316d43e2100224f4d"}, +] + +[[package]] +name = "tornado" +version = "6.4.1" +description = "Tornado is a Python web framework and asynchronous networking library, originally developed at FriendFeed." +optional = false +python-versions = ">=3.8" +files = [ + {file = "tornado-6.4.1-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:163b0aafc8e23d8cdc3c9dfb24c5368af84a81e3364745ccb4427669bf84aec8"}, + {file = "tornado-6.4.1-cp38-abi3-macosx_10_9_x86_64.whl", hash = "sha256:6d5ce3437e18a2b66fbadb183c1d3364fb03f2be71299e7d10dbeeb69f4b2a14"}, + {file = "tornado-6.4.1-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e2e20b9113cd7293f164dc46fffb13535266e713cdb87bd2d15ddb336e96cfc4"}, + {file = "tornado-6.4.1-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8ae50a504a740365267b2a8d1a90c9fbc86b780a39170feca9bcc1787ff80842"}, + {file = "tornado-6.4.1-cp38-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:613bf4ddf5c7a95509218b149b555621497a6cc0d46ac341b30bd9ec19eac7f3"}, + {file = "tornado-6.4.1-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:25486eb223babe3eed4b8aecbac33b37e3dd6d776bc730ca14e1bf93888b979f"}, + {file = "tornado-6.4.1-cp38-abi3-musllinux_1_2_i686.whl", hash = "sha256:454db8a7ecfcf2ff6042dde58404164d969b6f5d58b926da15e6b23817950fc4"}, + {file = "tornado-6.4.1-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a02a08cc7a9314b006f653ce40483b9b3c12cda222d6a46d4ac63bb6c9057698"}, + {file = "tornado-6.4.1-cp38-abi3-win32.whl", hash = "sha256:d9a566c40b89757c9aa8e6f032bcdb8ca8795d7c1a9762910c722b1635c9de4d"}, + {file = "tornado-6.4.1-cp38-abi3-win_amd64.whl", hash = "sha256:b24b8982ed444378d7f21d563f4180a2de31ced9d8d84443907a0a64da2072e7"}, + {file = "tornado-6.4.1.tar.gz", hash = "sha256:92d3ab53183d8c50f8204a51e6f91d18a15d5ef261e84d452800d4ff6fc504e9"}, +] + [[package]] name = "tqdm" version = "4.66.2" @@ -3706,6 +4096,50 @@ platformdirs = ">=3.9.1,<5" docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2,!=7.3)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8)", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10)"] +[[package]] +name = "watchdog" +version = "4.0.1" +description = "Filesystem events monitoring" +optional = false +python-versions = ">=3.8" +files = [ + {file = "watchdog-4.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:da2dfdaa8006eb6a71051795856bedd97e5b03e57da96f98e375682c48850645"}, + {file = "watchdog-4.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e93f451f2dfa433d97765ca2634628b789b49ba8b504fdde5837cdcf25fdb53b"}, + {file = "watchdog-4.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ef0107bbb6a55f5be727cfc2ef945d5676b97bffb8425650dadbb184be9f9a2b"}, + {file = "watchdog-4.0.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:17e32f147d8bf9657e0922c0940bcde863b894cd871dbb694beb6704cfbd2fb5"}, + {file = "watchdog-4.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:03e70d2df2258fb6cb0e95bbdbe06c16e608af94a3ffbd2b90c3f1e83eb10767"}, + {file = "watchdog-4.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:123587af84260c991dc5f62a6e7ef3d1c57dfddc99faacee508c71d287248459"}, + {file = "watchdog-4.0.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:093b23e6906a8b97051191a4a0c73a77ecc958121d42346274c6af6520dec175"}, + {file = "watchdog-4.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:611be3904f9843f0529c35a3ff3fd617449463cb4b73b1633950b3d97fa4bfb7"}, + {file = "watchdog-4.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:62c613ad689ddcb11707f030e722fa929f322ef7e4f18f5335d2b73c61a85c28"}, + {file = "watchdog-4.0.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:d4925e4bf7b9bddd1c3de13c9b8a2cdb89a468f640e66fbfabaf735bd85b3e35"}, + {file = "watchdog-4.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:cad0bbd66cd59fc474b4a4376bc5ac3fc698723510cbb64091c2a793b18654db"}, + {file = "watchdog-4.0.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:a3c2c317a8fb53e5b3d25790553796105501a235343f5d2bf23bb8649c2c8709"}, + {file = "watchdog-4.0.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c9904904b6564d4ee8a1ed820db76185a3c96e05560c776c79a6ce5ab71888ba"}, + {file = "watchdog-4.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:667f3c579e813fcbad1b784db7a1aaa96524bed53437e119f6a2f5de4db04235"}, + {file = "watchdog-4.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d10a681c9a1d5a77e75c48a3b8e1a9f2ae2928eda463e8d33660437705659682"}, + {file = "watchdog-4.0.1-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:0144c0ea9997b92615af1d94afc0c217e07ce2c14912c7b1a5731776329fcfc7"}, + {file = "watchdog-4.0.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:998d2be6976a0ee3a81fb8e2777900c28641fb5bfbd0c84717d89bca0addcdc5"}, + {file = "watchdog-4.0.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:e7921319fe4430b11278d924ef66d4daa469fafb1da679a2e48c935fa27af193"}, + {file = "watchdog-4.0.1-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:f0de0f284248ab40188f23380b03b59126d1479cd59940f2a34f8852db710625"}, + {file = "watchdog-4.0.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:bca36be5707e81b9e6ce3208d92d95540d4ca244c006b61511753583c81c70dd"}, + {file = "watchdog-4.0.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:ab998f567ebdf6b1da7dc1e5accfaa7c6992244629c0fdaef062f43249bd8dee"}, + {file = "watchdog-4.0.1-py3-none-manylinux2014_aarch64.whl", hash = "sha256:dddba7ca1c807045323b6af4ff80f5ddc4d654c8bce8317dde1bd96b128ed253"}, + {file = "watchdog-4.0.1-py3-none-manylinux2014_armv7l.whl", hash = "sha256:4513ec234c68b14d4161440e07f995f231be21a09329051e67a2118a7a612d2d"}, + {file = "watchdog-4.0.1-py3-none-manylinux2014_i686.whl", hash = "sha256:4107ac5ab936a63952dea2a46a734a23230aa2f6f9db1291bf171dac3ebd53c6"}, + {file = "watchdog-4.0.1-py3-none-manylinux2014_ppc64.whl", hash = "sha256:6e8c70d2cd745daec2a08734d9f63092b793ad97612470a0ee4cbb8f5f705c57"}, + {file = "watchdog-4.0.1-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:f27279d060e2ab24c0aa98363ff906d2386aa6c4dc2f1a374655d4e02a6c5e5e"}, + {file = "watchdog-4.0.1-py3-none-manylinux2014_s390x.whl", hash = "sha256:f8affdf3c0f0466e69f5b3917cdd042f89c8c63aebdb9f7c078996f607cdb0f5"}, + {file = "watchdog-4.0.1-py3-none-manylinux2014_x86_64.whl", hash = "sha256:ac7041b385f04c047fcc2951dc001671dee1b7e0615cde772e84b01fbf68ee84"}, + {file = "watchdog-4.0.1-py3-none-win32.whl", hash = "sha256:206afc3d964f9a233e6ad34618ec60b9837d0582b500b63687e34011e15bb429"}, + {file = "watchdog-4.0.1-py3-none-win_amd64.whl", hash = "sha256:7577b3c43e5909623149f76b099ac49a1a01ca4e167d1785c76eb52fa585745a"}, + {file = "watchdog-4.0.1-py3-none-win_ia64.whl", hash = "sha256:d7b9f5f3299e8dd230880b6c55504a1f69cf1e4316275d1b215ebdd8187ec88d"}, + {file = "watchdog-4.0.1.tar.gz", hash = "sha256:eebaacf674fa25511e8867028d281e602ee6500045b57f43b08778082f7f8b44"}, +] + +[package.extras] +watchmedo = ["PyYAML (>=3.10)"] + [[package]] name = "watchfiles" version = "0.21.0" @@ -4073,4 +4507,4 @@ multidict = ">=4.0" [metadata] lock-version = "2.0" python-versions = ">=3.11,<3.13" -content-hash = "d0b80fa95580950ba73979ef8e99197278b842f35a03194e31e5a78b4fb9f7b8" +content-hash = "fb3aa724a43c00e6d8a7736f6df8a2fde069dd953554eda0ca5ae9401b207d65" diff --git a/pyproject.toml b/pyproject.toml index ad1d1aeb..ab3d7736 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -42,6 +42,7 @@ google-auth-oauthlib = "^1.2.0" nicegui = "^1.4.22" langsmith = "^0.1.52" python-levenshtein = "^0.25.1" +streamlit = "^1.35.0" [tool.poetry.group.dev.dependencies] pytest = "^7.4.3"