From 6a93a68fc37710b3f67cca8542bdb4c48a8bdb7e Mon Sep 17 00:00:00 2001 From: Harrison Chase Date: Mon, 1 Jan 2024 12:33:03 -0800 Subject: [PATCH 01/19] start --- examples/langgraph.ipynb | 107 +++++++++++++++++++++++++++++ permchain/langgraph/__init__.py | 115 ++++++++++++++++++++++++++++++++ 2 files changed, 222 insertions(+) create mode 100644 examples/langgraph.ipynb create mode 100644 permchain/langgraph/__init__.py diff --git a/examples/langgraph.ipynb b/examples/langgraph.ipynb new file mode 100644 index 000000000..f3500d8bf --- /dev/null +++ b/examples/langgraph.ipynb @@ -0,0 +1,107 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "53b9dce4-e4ae-4bdb-b752-0f04350a2e3d", + "metadata": {}, + "outputs": [], + "source": [ + "from langchain.chat_models import ChatOpenAI\n", + "from langchain.agents import create_openai_functions_agent\n", + "from langchain_core.prompts import PromptTemplate\n", + "from langchain import hub\n", + "from langchain.agents import AgentExecutor, create_openai_functions_agent\n", + "from langchain_community.chat_models import ChatOpenAI\n", + "from langchain_community.tools.tavily_search import TavilySearchResults\n", + "from langchain_core.runnables import RunnablePassthrough, RunnableLambda\n", + "from permchain.langgraph import Actor, DecisionPoint, Graph\n", + "\n", + "tools = [TavilySearchResults(max_results=1)]\n", + "\n", + "# Get the prompt to use - you can modify this!\n", + "prompt = hub.pull(\"hwchase17/openai-functions-agent\")\n", + "\n", + "# Choose the LLM that will drive the agent\n", + "llm = ChatOpenAI(model=\"gpt-3.5-turbo-1106\")\n", + "\n", + "# Construct the OpenAI Functions agent\n", + "agent_runnable = create_openai_functions_agent(llm, tools, prompt)\n", + "\n", + "from langchain_core.agents import AgentFinish\n", + "# Define decision-making logic\n", + "def should_continue(data):\n", + " # Logic to decide whether to continue in the loop or exit\n", + " if isinstance(data['agent_outcome'], AgentFinish):\n", + " return \"exit\"\n", + " else:\n", + " return \"continue\"\n", + " \n", + "def execute_tools(data):\n", + " agent_action = data.pop('agent_outcome')\n", + " observation = {t.name: t for t in tools}[agent_action.tool].invoke(agent_action.tool_input)\n", + " data['intermediate_steps'].append((agent_action, observation))\n", + " return data\n", + " \n", + " \n", + "\n", + "# Define agents\n", + "agent = RunnablePassthrough.assign(\n", + " agent_outcome = agent_runnable\n", + ")\n", + "\n", + "# Define a new graph\n", + "workflow = Graph()\n", + "decision_point = DecisionPoint(\"exit?\", should_continue)\n", + "llm_agent = Actor(\"agent\", agent)\n", + "tool_actor = Actor(\"tools\", RunnableLambda(execute_tools))\n", + "\n", + "# Register actors\n", + "workflow.register(llm_agent)\n", + "workflow.register(tool_actor)\n", + "workflow.register(decision_point)\n", + "\n", + "# Define connections with conditional logic\n", + "workflow.connect(llm_agent, decision_point)\n", + "workflow.branch(decision_point, tool_actor, condition=\"continue\")\n", + "workflow.branch(decision_point, None, condition=\"exit\") # Exit the workflow\n", + "workflow.connect(tool_actor, llm_agent)\n", + "\n", + "# Define entry point and execute the graph\n", + "workflow.set_entry_point(llm_agent)\n", + "chain = workflow.compile()\n", + "\n", + "chain.invoke({\"input\": \"what is the weather in sf\", \"intermediate_steps\": []})" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2515edbc-a9b6-42ce-bb5e-f1f2503d1bb4", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.1" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/permchain/langgraph/__init__.py b/permchain/langgraph/__init__.py new file mode 100644 index 000000000..f93eff29f --- /dev/null +++ b/permchain/langgraph/__init__.py @@ -0,0 +1,115 @@ +from langchain_core.runnables import Runnable, RunnableMap +from typing import Callable, Union, Optional +from permchain import Channel, Pregel + +class Actor: + + def __init__(self, name: str, runnable: Runnable): + self.name = name + self.runnable = runnable + + +class DecisionPoint: + + def __init__(self, name: str, callable: Callable): + self.name = name + self.callable = callable + +class End: + name = "end" + + +def branch(data, condition, mapping): + result = condition(data) + return Channel.write_to(mapping[result]) + +class Graph: + + def __init__(self): + self.nodes = {"end": End()} + self.connections = {} + self.branches = {} + self.entry_point: Optional[str] = None + self.finish_points = set() + + def register(self, node: Union[Actor, DecisionPoint]): + if node.name in self.nodes: + raise ValueError(f"Actor `{node.name}` already present.") + self.nodes[node.name] = node + + def connect(self, start: Actor, end: Union[Actor, DecisionPoint]): + if start.name not in self.nodes: + raise ValueError(f"Need to register `{start.name}` first") + if end.name not in self.nodes: + raise ValueError(f"Need to register `{end.name}` first") + if start.name in self.connections: + raise ValueError(f"Already found path for {start.name}") + self.connections[start.name] = end.name + + def branch(self, start: DecisionPoint, end: Optional[Actor], condition: str): + end = end or End() + if start.name not in self.nodes: + raise ValueError(f"Need to register `{start.name}` first") + if end.name not in self.nodes: + raise ValueError(f"Need to register `{end.name}` first") + if start.name not in self.branches: + self.branches[start.name] = {} + if condition in self.branches[start.name]: + raise ValueError(f"Already found a condition for {start.name} and {condition}") + self.branches[start.name][condition] = end.name + + def set_entry_point(self, node: Union[DecisionPoint, Actor]): + if node.name not in self.nodes: + raise ValueError(f"Need to register `{node.name}` first") + self.entry_point = node.name + + def set_finish_point(self, node: Actor): + if node.name not in self.nodes: + raise ValueError(f"Need to register `{node.name}` first") + self.finish_points |= node.name + + def compile(self): + # Validate all nodes have an entry point + all_nodes = set(self.nodes) + all_entry_points = set(self.connections).union(self.branches).union(self.finish_points) + branch_ends = set() + for v in self.branches.values(): + branch_ends.update(v.values()) + all_finish_points = set(self.connections.values()).union(branch_ends).union({self.entry_point}) + # If a node is not a finish point, then it is missing an entry point + missing_entry = all_nodes.difference(all_finish_points) + if missing_entry: + raise ValueError(f"Some nodes are missing entry points: {missing_entry}") + # If a node is not an entry point, then it is missing a finish point + missing_finish = all_nodes.difference(all_entry_points).difference({"end"}) + if missing_finish: + raise ValueError(f"Some nodes are missing finish points: {missing_finish}") + chains = { + start: Channel.subscribe_to(start) | self.nodes[start].runnable | Channel.write_to(end) + for start, end in self.connections.items() + } + + decisions = { + start: Channel.subscribe_to(start) | (lambda x: branch(x, self.nodes[start].callable, mapping)) + for start, mapping in self.branches.items() + } + endings = { + end: Channel.subscribe_to(end) | self.nodes[end].runnable | Channel.write_to("end") + for end in self.finish_points + } + app = Pregel( + chains = {**chains, **decisions, **endings}, + input=self.entry_point, + output="end" + ) + return app + + + + + + + + + + From 0f6ea1fe4b521da1803b240a4b9fb073f3425e6a Mon Sep 17 00:00:00 2001 From: Harrison Chase Date: Mon, 1 Jan 2024 13:10:20 -0800 Subject: [PATCH 02/19] cr --- examples/langgraph.ipynb | 294 +++++++++++++++++++++++++++++++- permchain/langgraph/__init__.py | 11 +- 2 files changed, 293 insertions(+), 12 deletions(-) diff --git a/examples/langgraph.ipynb b/examples/langgraph.ipynb index f3500d8bf..19c708dd4 100644 --- a/examples/langgraph.ipynb +++ b/examples/langgraph.ipynb @@ -1,9 +1,17 @@ { "cells": [ + { + "cell_type": "markdown", + "id": "396e20d9-8684-40ea-a46a-e3dfa36ed5a6", + "metadata": {}, + "source": [ + "## Existing Agent Executor" + ] + }, { "cell_type": "code", - "execution_count": null, - "id": "53b9dce4-e4ae-4bdb-b752-0f04350a2e3d", + "execution_count": 1, + "id": "d642e6af-217a-4414-a78c-509b44155eca", "metadata": {}, "outputs": [], "source": [ @@ -69,15 +77,293 @@ "\n", "# Define entry point and execute the graph\n", "workflow.set_entry_point(llm_agent)\n", + "chain = workflow.compile()" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "c46bd262-9605-4449-9391-f6b6e0fe440e", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'input': 'what is the weather in sf',\n", + " 'intermediate_steps': [(AgentActionMessageLog(tool='tavily_search_results_json', tool_input={'query': 'weather in San Francisco'}, log=\"\\nInvoking: `tavily_search_results_json` with `{'query': 'weather in San Francisco'}`\\n\\n\\n\", message_log=[AIMessage(content='', additional_kwargs={'function_call': {'name': 'tavily_search_results_json', 'arguments': '{\"query\":\"weather in San Francisco\"}'}})]),\n", + " [{'url': 'https://www.weather2travel.com/california/san-francisco/january/',\n", + " 'content': 'San Francisco weather in January 2024 Expect 13°C daytime maximum temperatures long-term weather averages for San Francisco in January before you book your next holiday to California in 2024/2025. San Francisco January sunrise & sunset times How sunny is it in San Francisco in January?San Francisco weather in January 2024 Expect 13°C daytime maximum temperatures in the shade with on average 6 hours of sunshine per day in San Francisco in January. Check more long-term weather averages for San Francisco in January before you book your next holiday to California in 2024/2025. 13 13°C max day temperature 6'}])],\n", + " 'agent_outcome': AgentFinish(return_values={'output': 'The weather in San Francisco in January 2024 is expected to have a daytime maximum temperature of 13°C with an average of 6 hours of sunshine per day. You can find more long-term weather averages for San Francisco in January on this [website](https://www.weather2travel.com/california/san-francisco/january/).'}, log='The weather in San Francisco in January 2024 is expected to have a daytime maximum temperature of 13°C with an average of 6 hours of sunshine per day. You can find more long-term weather averages for San Francisco in January on this [website](https://www.weather2travel.com/california/san-francisco/january/).')}" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "chain.invoke({\"input\": \"what is the weather in sf\", \"intermediate_steps\": []})" + ] + }, + { + "cell_type": "markdown", + "id": "592c3886-71d1-4539-80dd-111e55cc3a85", + "metadata": {}, + "source": [ + "## Reflexion Agent" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "f6f96e81-4a20-4599-a625-8d18df6fa76d", + "metadata": {}, + "outputs": [], + "source": [ + "from langchain.agents import AgentExecutor, BaseMultiActionAgent, Tool\n", + "from langchain.schema import AgentAction, AgentFinish\n", + "from langchain_core.language_models.chat_models import BaseChatModel\n", + "from langchain.chains import LLMChain\n", + "\n", + "from langchain.globals import set_llm_cache\n", + "\n", + "from dotenv import load_dotenv\n", + "\n", + "from pydantic import BaseModel\n", + "\n", + "from langchain.chat_models import ChatOpenAI\n", + "from langchain.cache import SQLiteCache\n", + "\n", + "from langchain_core.output_parsers import BaseOutputParser\n", + "\n", + "from langchain.prompts.chat import ChatPromptTemplate\n", + "from langchain.callbacks import get_openai_callback\n", + "from langchain.tools.tavily_search import TavilySearchResults\n", + "from langchain.utilities.tavily_search import TavilySearchAPIWrapper\n", + "from langchain.pydantic_v1 import BaseModel\n", + "import os\n", + "\n", + "from langchain.agents import AgentType, initialize_agent, load_tools\n", + "\n", + "set_llm_cache(SQLiteCache(database_path=\".langchain.db\"))\n", + "\n", + "\n", + "llm = ChatOpenAI(\n", + " temperature=0.0,\n", + " max_tokens=2000,\n", + " max_retries=100,\n", + " model=\"gpt-4-1106-preview\",\n", + ")\n", + "\n", + "search = TavilySearchAPIWrapper()\n", + "tavily_tool = TavilySearchResults(api_wrapper=search, max_results=5)\n", + "\n", + "NEXT_STEP_TEMPLATE = \"\"\"You are expert researcher trying answer a question ~250 words. You are asked to answer the following question: {question}\n", + "\n", + "The way you are going to answer the question is as follows:\n", + "\n", + "1. Revise your previous answer using the new information.\n", + " - You should use the previous critique to add important information to your answer.\n", + " _ You MUST include numerical citations in your revised answer to ensure it can be verified.\n", + " - Add a \"References\" section to the bottom of your answer (which does not count towards the word limit). In form of:\n", + " - [1] https://example.com\n", + " - [2] https://example.com\n", + " - You should use the previous critique to remove superfluous information from your answer and make SURE it is not more than 250 words.\n", + "2. Reflect and critique your answer. Specifically, you should:\n", + " - Think about what is missing from your answer.\n", + " - Think about what is superfluous in your answer.\n", + " - Think about what search query you should use next to improve your answer.\n", + " Give your answer in exactly 2 parts. The first should address what is missing from your answer. The second should address what could be removed from your answer. Your should be VERY harsh as we really want to improve the answer.\n", + "3. Give the search query you came up with to improve your answer.\n", + "\n", + "Previous steps: \n", + "\n", + "{previous_steps}\n", + "\n", + "===\n", + "\n", + "Format your answer as follows:\n", + "\n", + "Revised answer: [give your revised answer based on the previous critique and new information from the search engine then the \"References\" section]\n", + "Critique: [give your harsh critique of your revised answer in 2 parts: what is missing and what is superfluous]\n", + "Search query: [give the new search query you came up with to enter into the search engine to improve your answer. If you have more than one, make sure they are comma separated and in quotes]\n", + "\n", + "SAY NOTHING else please.\"\"\"\n", + "\n", + "INITIAL_ANSWER_TEMPLATE = \"\"\"You are expert researcher trying answer a question ~250 words. You are asked to answer the following question: {question}\n", + "\n", + "The way you are going to answer the question is as follows:\n", + "\n", + "1. Give a detailed in ~250 words.\n", + "2. Reflect and critique your answer. Specifically, you should:\n", + " - Think about what is missing from your answer.\n", + " - Think about what is superfluous in your answer.\n", + " - Think about what search query you should use next to improve your answer.\n", + " Give your answer in exactly 2 parts. The first should address what is missing from your answer. The second should address what could be removed from your answer. Your should be VERY harsh as we really want to improve the answer.\n", + "3. Give the search query you came up with to improve your answer.\n", + "\n", + "===\n", + "\n", + "Format your answer as follows:\n", + "\n", + "Answer: [give your initial answer]\n", + "Critique: [give your harsh critique of your answer in 2 parts: what is missing and what is superfluous]\n", + "Search query: [give the search query you came up with to improve your answer. If you have more than one, make sure they are comma separated and in quotes]\n", + "\n", + "SAY NOTHING else please.\"\"\"\n", + "\n", + "\n", + "class ReflexionStep(BaseModel):\n", + " \"\"\"A single step in the reflexion process.\"\"\"\n", + "\n", + " answer: str\n", + " critique: str\n", + " search_query: str\n", + "\n", + " def __str__(self):\n", + " return f\"Answer: {self.answer}\\nCritique: {self.critique}\\nSearch query: {self.search_query}\"\n", + "\n", + "def _parse_reflexion_step(output: str) -> tuple[str, str, str]:\n", + " # find answer using .split()\n", + " if (\"Answer:\" not in output and \"Revised answer:\" not in output) or not \"Critique:\" in output or not \"Search query:\" in output:\n", + " raise ValueError(f\"The output is not formatted correctly. Output: {output}\")\n", + " if \"Answer:\" in output:\n", + " answer = output.split(\"Answer:\")[1].split(\"Critique:\")[0].strip()\n", + " else:\n", + " answer = output.split(\"Revised answer:\")[1].split(\"Critique:\")[0].strip()\n", + " critique = output.split(\"Critique:\")[1].split(\"Search query:\")[0].strip()\n", + " search_query = output.split(\"Search query:\")[1].strip()\n", + " return answer, critique, search_query\n", + "\n", + "class ReflexionStepParser(BaseOutputParser[ReflexionStep]):\n", + " \"\"\"Parser for the reflexion step.\"\"\"\n", + "\n", + " def parse(self, output: str) -> ReflexionStep:\n", + " \"\"\"Parse the output.\"\"\"\n", + " # try to find answer or initial answer\n", + " answer, critique, search_query = _parse_reflexion_step(output)\n", + " return ReflexionStep(\n", + " answer=answer, critique=critique, search_query=search_query\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "id": "7708fa95-547b-4bea-b126-3656de7d5873", + "metadata": {}, + "outputs": [], + "source": [ + "initial_chain = RunnablePassthrough.assign(\n", + " agent_outcome = ChatPromptTemplate.from_template(INITIAL_ANSWER_TEMPLATE) | llm | ReflexionStepParser() | (lambda x: AgentAction(\n", + " tool=\"tavily_search_results_json\",\n", + " tool_input=x.search_query,\n", + " log=str(x),\n", + " ))\n", + ")\n", + "\n", + "def prep_next(inputs):\n", + " intermediate_steps = inputs[\"intermediate_steps\"]\n", + " previous_steps = list[str]()\n", + "\n", + " for i, (action, observation) in enumerate(intermediate_steps, start=1):\n", + " last_step_str = f\"\"\"Step {i}:\n", + "\n", + "{action.log}\n", + "\n", + "Search output for \"{action.tool_input}\":\n", + "\n", + "{observation}\"\"\"\n", + " previous_steps.append(last_step_str)\n", + "\n", + " previous_steps_str = \"\\n\\n\".join(previous_steps)\n", + " inputs[\"previous_steps\"] = previous_steps_str\n", + " return inputs\n", + " \n", + "next_chain = RunnablePassthrough.assign(\n", + " agent_outcome = prep_next | ChatPromptTemplate.from_template(NEXT_STEP_TEMPLATE) | llm | ReflexionStepParser() | (lambda x: AgentAction(\n", + " tool=\"tavily_search_results_json\",\n", + " tool_input=x.search_query,\n", + " log=str(x),\n", + " ))\n", + ")\n", + "\n", + "def finish(inputs):\n", + " intermediate_steps = inputs[\"intermediate_steps\"]\n", + " last_action, _ = intermediate_steps[-1]\n", + " last_step_str = last_action.log\n", + " # extract answer\n", + " answer, _, _ = _parse_reflexion_step(last_step_str)\n", + "\n", + " first_action, _ = intermediate_steps[0]\n", + " first_step_str = first_action.log\n", + " # extract answer\n", + " initial_answer, _, _ = _parse_reflexion_step(first_step_str)\n", + "\n", + " return AgentFinish(\n", + " log=\"Reached max steps.\",\n", + " return_values={\"output\": answer, \"initial_answer\": initial_answer},\n", + " )\n", + "\n", + "\n", + "def execute_tools(data):\n", + " agent_action = data.pop('agent_outcome')\n", + " observation = {t.name: t for t in tools}[agent_action.tool].invoke(agent_action.tool_input)\n", + " data['intermediate_steps'].append((agent_action, observation))\n", + " return data\n" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "id": "d6cdd1cd-e480-4dd7-99b4-9018eb243b4d", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "AgentFinish(return_values={'output': \"The current weather in San Francisco is characterized by a daytime maximum temperature of 13°C in January, with an average of 6 hours of sunshine per day and 10 days of some rainfall. Nighttime temperatures typically drop to around 7°C. There is no significant heat and humidity, and the monthly rainfall averages at 125 mm. The UV index is low at 2, and the sea temperature averages at 11°C. These conditions reflect San Francisco's Mediterranean-like climate, with its wet winters and dry summers. However, weather can vary between neighborhoods due to microclimates, so localized weather advisories should be checked. For real-time updates and specific forecasts, including any weather advisories, it is recommended to consult a reliable weather service[1].\\n\\nReferences:\\n- [1] https://www.weather2travel.com/california/san-francisco/january/\", 'initial_answer': \"The weather in San Francisco (SF) is characterized by a mild, Mediterranean-like climate with wet winters and dry summers. The city's unique topography and coastal location result in microclimates, where weather conditions can vary significantly from one neighborhood to another. Average temperatures typically range from the mid-40s to the low 70s Fahrenheit (7-22 degrees Celsius), with the warmest months being September and October. Fog is a common occurrence, particularly in the summer, often rolling in during the evening and clearing by midday. Rainfall is most frequent from November to March, while the rest of the year is relatively dry. Wind is another constant factor, with the afternoon sea breeze being a defining feature of the city's weather. Despite these general patterns, it's always advisable to check the current weather forecast before planning activities in San Francisco, as conditions can change rapidly.\"}, log='Reached max steps.')" + ] + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "workflow = Graph()\n", + "decision_point = DecisionPoint(\"exit?\", lambda x: \"exit\" if len(x['intermediate_steps']) >= 2 else \"continue\")\n", + "initial_answer_actor = Actor(\"initial\", initial_chain)\n", + "next_step_actor = Actor(\"next\", next_chain)\n", + "finish_actor = Actor(\"finish\", RunnableLambda(finish))\n", + "tool_actor = Actor(\"tools\", RunnableLambda(execute_tools))\n", + "\n", + "# Register actors\n", + "workflow.register(initial_answer_actor)\n", + "workflow.register(next_step_actor)\n", + "workflow.register(finish_actor)\n", + "workflow.register(decision_point)\n", + "workflow.register(tool_actor)\n", + "\n", + "# Define connections with conditional logic\n", + "workflow.connect(initial_answer_actor, tool_actor)\n", + "workflow.branch(decision_point, next_step_actor, condition=\"continue\")\n", + "workflow.connect(next_step_actor, tool_actor)\n", + "workflow.branch(decision_point, finish_actor, condition=\"exit\") # Exit the workflow\n", + "workflow.connect(tool_actor, decision_point)\n", + "\n", + "# Define entry point and execute the graph\n", + "workflow.set_entry_point(initial_answer_actor)\n", + "workflow.set_finish_point(finish_actor)\n", "chain = workflow.compile()\n", "\n", - "chain.invoke({\"input\": \"what is the weather in sf\", \"intermediate_steps\": []})" + "chain.invoke({\"question\": \"what is the weather in sf\", \"intermediate_steps\": []})" ] }, { "cell_type": "code", "execution_count": null, - "id": "2515edbc-a9b6-42ce-bb5e-f1f2503d1bb4", + "id": "9babf196-b1fd-492d-9197-96a674f5e81d", "metadata": {}, "outputs": [], "source": [] diff --git a/permchain/langgraph/__init__.py b/permchain/langgraph/__init__.py index f93eff29f..b15bc1102 100644 --- a/permchain/langgraph/__init__.py +++ b/permchain/langgraph/__init__.py @@ -30,7 +30,6 @@ class Graph: self.connections = {} self.branches = {} self.entry_point: Optional[str] = None - self.finish_points = set() def register(self, node: Union[Actor, DecisionPoint]): if node.name in self.nodes: @@ -66,12 +65,12 @@ class Graph: def set_finish_point(self, node: Actor): if node.name not in self.nodes: raise ValueError(f"Need to register `{node.name}` first") - self.finish_points |= node.name + self.connections[node.name] = "end" def compile(self): # Validate all nodes have an entry point all_nodes = set(self.nodes) - all_entry_points = set(self.connections).union(self.branches).union(self.finish_points) + all_entry_points = set(self.connections).union(self.branches) branch_ends = set() for v in self.branches.values(): branch_ends.update(v.values()) @@ -93,12 +92,8 @@ class Graph: start: Channel.subscribe_to(start) | (lambda x: branch(x, self.nodes[start].callable, mapping)) for start, mapping in self.branches.items() } - endings = { - end: Channel.subscribe_to(end) | self.nodes[end].runnable | Channel.write_to("end") - for end in self.finish_points - } app = Pregel( - chains = {**chains, **decisions, **endings}, + chains = {**chains, **decisions}, input=self.entry_point, output="end" ) From b6e3cd90448aa21720b83d1581b998b4f268f3b6 Mon Sep 17 00:00:00 2001 From: Jake Rachleff Date: Tue, 2 Jan 2024 23:42:08 -0800 Subject: [PATCH 03/19] update graph to use more graph like syntax --- examples/langgraph.ipynb | 110 ++- permchain/langgraph/__init__.py | 265 ++++-- poetry.lock | 1382 ++++++++++++++++--------------- pyproject.toml | 3 +- 4 files changed, 951 insertions(+), 809 deletions(-) diff --git a/examples/langgraph.ipynb b/examples/langgraph.ipynb index 19c708dd4..3595bc705 100644 --- a/examples/langgraph.ipynb +++ b/examples/langgraph.ipynb @@ -16,14 +16,13 @@ "outputs": [], "source": [ "from langchain.chat_models import ChatOpenAI\n", - "from langchain.agents import create_openai_functions_agent\n", "from langchain_core.prompts import PromptTemplate\n", "from langchain import hub\n", "from langchain.agents import AgentExecutor, create_openai_functions_agent\n", "from langchain_community.chat_models import ChatOpenAI\n", "from langchain_community.tools.tavily_search import TavilySearchResults\n", "from langchain_core.runnables import RunnablePassthrough, RunnableLambda\n", - "from permchain.langgraph import Actor, DecisionPoint, Graph\n", + "from permchain.langgraph import Actor, Graph, End\n", "\n", "tools = [TavilySearchResults(max_results=1)]\n", "\n", @@ -58,49 +57,36 @@ " agent_outcome = agent_runnable\n", ")\n", "\n", + "\n", "# Define a new graph\n", "workflow = Graph()\n", - "decision_point = DecisionPoint(\"exit?\", should_continue)\n", "llm_agent = Actor(\"agent\", agent)\n", "tool_actor = Actor(\"tools\", RunnableLambda(execute_tools))\n", + "end = End()\n", "\n", - "# Register actors\n", - "workflow.register(llm_agent)\n", - "workflow.register(tool_actor)\n", - "workflow.register(decision_point)\n", + "workflow.register_node(llm_agent)\n", + "workflow.register_node(tool_actor)\n", "\n", - "# Define connections with conditional logic\n", - "workflow.connect(llm_agent, decision_point)\n", - "workflow.branch(decision_point, tool_actor, condition=\"continue\")\n", - "workflow.branch(decision_point, None, condition=\"exit\") # Exit the workflow\n", - "workflow.connect(tool_actor, llm_agent)\n", + "workflow.set_entry_point(llm_agent.key)\n", "\n", - "# Define entry point and execute the graph\n", - "workflow.set_entry_point(llm_agent)\n", + "workflow.register_conditional_edges(\n", + " llm_agent.key,\n", + " should_continue,\n", + " {\n", + " \"continue\": tool_actor.key,\n", + " \"exit\": end.key\n", + " }\n", + ")\n", + "workflow.register_edge(tool_actor.key, llm_agent.key)\n", "chain = workflow.compile()" ] }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "id": "c46bd262-9605-4449-9391-f6b6e0fe440e", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'input': 'what is the weather in sf',\n", - " 'intermediate_steps': [(AgentActionMessageLog(tool='tavily_search_results_json', tool_input={'query': 'weather in San Francisco'}, log=\"\\nInvoking: `tavily_search_results_json` with `{'query': 'weather in San Francisco'}`\\n\\n\\n\", message_log=[AIMessage(content='', additional_kwargs={'function_call': {'name': 'tavily_search_results_json', 'arguments': '{\"query\":\"weather in San Francisco\"}'}})]),\n", - " [{'url': 'https://www.weather2travel.com/california/san-francisco/january/',\n", - " 'content': 'San Francisco weather in January 2024 Expect 13°C daytime maximum temperatures long-term weather averages for San Francisco in January before you book your next holiday to California in 2024/2025. San Francisco January sunrise & sunset times How sunny is it in San Francisco in January?San Francisco weather in January 2024 Expect 13°C daytime maximum temperatures in the shade with on average 6 hours of sunshine per day in San Francisco in January. Check more long-term weather averages for San Francisco in January before you book your next holiday to California in 2024/2025. 13 13°C max day temperature 6'}])],\n", - " 'agent_outcome': AgentFinish(return_values={'output': 'The weather in San Francisco in January 2024 is expected to have a daytime maximum temperature of 13°C with an average of 6 hours of sunshine per day. You can find more long-term weather averages for San Francisco in January on this [website](https://www.weather2travel.com/california/san-francisco/january/).'}, log='The weather in San Francisco in January 2024 is expected to have a daytime maximum temperature of 13°C with an average of 6 hours of sunshine per day. You can find more long-term weather averages for San Francisco in January on this [website](https://www.weather2travel.com/california/san-francisco/january/).')}" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "chain.invoke({\"input\": \"what is the weather in sf\", \"intermediate_steps\": []})" ] @@ -115,7 +101,7 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": null, "id": "f6f96e81-4a20-4599-a625-8d18df6fa76d", "metadata": {}, "outputs": [], @@ -249,7 +235,7 @@ }, { "cell_type": "code", - "execution_count": 21, + "execution_count": null, "id": "7708fa95-547b-4bea-b126-3656de7d5873", "metadata": {}, "outputs": [], @@ -315,46 +301,38 @@ }, { "cell_type": "code", - "execution_count": 22, + "execution_count": null, "id": "d6cdd1cd-e480-4dd7-99b4-9018eb243b4d", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "AgentFinish(return_values={'output': \"The current weather in San Francisco is characterized by a daytime maximum temperature of 13°C in January, with an average of 6 hours of sunshine per day and 10 days of some rainfall. Nighttime temperatures typically drop to around 7°C. There is no significant heat and humidity, and the monthly rainfall averages at 125 mm. The UV index is low at 2, and the sea temperature averages at 11°C. These conditions reflect San Francisco's Mediterranean-like climate, with its wet winters and dry summers. However, weather can vary between neighborhoods due to microclimates, so localized weather advisories should be checked. For real-time updates and specific forecasts, including any weather advisories, it is recommended to consult a reliable weather service[1].\\n\\nReferences:\\n- [1] https://www.weather2travel.com/california/san-francisco/january/\", 'initial_answer': \"The weather in San Francisco (SF) is characterized by a mild, Mediterranean-like climate with wet winters and dry summers. The city's unique topography and coastal location result in microclimates, where weather conditions can vary significantly from one neighborhood to another. Average temperatures typically range from the mid-40s to the low 70s Fahrenheit (7-22 degrees Celsius), with the warmest months being September and October. Fog is a common occurrence, particularly in the summer, often rolling in during the evening and clearing by midday. Rainfall is most frequent from November to March, while the rest of the year is relatively dry. Wind is another constant factor, with the afternoon sea breeze being a defining feature of the city's weather. Despite these general patterns, it's always advisable to check the current weather forecast before planning activities in San Francisco, as conditions can change rapidly.\"}, log='Reached max steps.')" - ] - }, - "execution_count": 22, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "workflow = Graph()\n", - "decision_point = DecisionPoint(\"exit?\", lambda x: \"exit\" if len(x['intermediate_steps']) >= 2 else \"continue\")\n", "initial_answer_actor = Actor(\"initial\", initial_chain)\n", "next_step_actor = Actor(\"next\", next_chain)\n", "finish_actor = Actor(\"finish\", RunnableLambda(finish))\n", "tool_actor = Actor(\"tools\", RunnableLambda(execute_tools))\n", "\n", "# Register actors\n", - "workflow.register(initial_answer_actor)\n", - "workflow.register(next_step_actor)\n", - "workflow.register(finish_actor)\n", - "workflow.register(decision_point)\n", - "workflow.register(tool_actor)\n", + "workflow.register_node(initial_answer_actor)\n", + "workflow.register_node(next_step_actor)\n", + "workflow.register_node(finish_actor)\n", + "workflow.register_node(tool_actor)\n", "\n", - "# Define connections with conditional logic\n", - "workflow.connect(initial_answer_actor, tool_actor)\n", - "workflow.branch(decision_point, next_step_actor, condition=\"continue\")\n", - "workflow.connect(next_step_actor, tool_actor)\n", - "workflow.branch(decision_point, finish_actor, condition=\"exit\") # Exit the workflow\n", - "workflow.connect(tool_actor, decision_point)\n", + "# Enter with initial actor, then loop through tools -> next steps until finished\n", + "workflow.set_entry_point(initial_answer_actor.key)\n", + "\n", + "workflow.register_edge(initial_answer_actor.key, tool_actor.key)\n", + "workflow.register_conditional_edges(\n", + " tool_actor.key,\n", + " lambda x: \"exit\" if len(x['intermediate_steps']) >= 2 else \"continue\",\n", + " {\n", + " \"continue\": next_step_actor.key,\n", + " \"exit\": finish_actor.key\n", + " }\n", + ")\n", + "workflow.register_edge(next_step_actor.key, tool_actor.key)\n", + "workflow.set_finish_point(finish_actor.key)\n", "\n", - "# Define entry point and execute the graph\n", - "workflow.set_entry_point(initial_answer_actor)\n", - "workflow.set_finish_point(finish_actor)\n", "chain = workflow.compile()\n", "\n", "chain.invoke({\"question\": \"what is the weather in sf\", \"intermediate_steps\": []})" @@ -367,6 +345,14 @@ "metadata": {}, "outputs": [], "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "58ce0d58-fb00-4dc1-a12b-8fc015474611", + "metadata": {}, + "outputs": [], + "source": [] } ], "metadata": { @@ -385,7 +371,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.1" + "version": "3.11.6" } }, "nbformat": 4, diff --git a/permchain/langgraph/__init__.py b/permchain/langgraph/__init__.py index b15bc1102..b513fb175 100644 --- a/permchain/langgraph/__init__.py +++ b/permchain/langgraph/__init__.py @@ -1,99 +1,224 @@ -from langchain_core.runnables import Runnable, RunnableMap -from typing import Callable, Union, Optional +from langchain_core.runnables import Runnable, RunnableMap, RunnableLambda, RunnablePassthrough +from typing import Callable, Union, Optional, List, Any, Dict from permchain import Channel, Pregel -class Actor: +######################################################### +# NODE CLASSES # +######################################################### - def __init__(self, name: str, runnable: Runnable): - self.name = name +class LangGraphNode: + def __init__(self, key: str): + self.key = key + + def get_runnable(self) -> Runnable: + pass + + +class Actor(LangGraphNode): + + def __init__(self, key: str, runnable: Runnable): self.runnable = runnable + super().__init__(key) + + def get_runnable(self) -> Union[Runnable, Callable]: + return self.runnable -class DecisionPoint: +class End(LangGraphNode): + def __init__(self): + super().__init__(key="end") - def __init__(self, name: str, callable: Callable): - self.name = name + def get_runnable(self) -> Union[Runnable, Callable]: + raise NotImplementedError + + +class Branch(LangGraphNode): + + def __init__(self, parent_key: str, condition: str): + self.parent_key = parent_key + self.condition = condition + super().__init__(f"{self.parent_key}.{self.condition}") + + def get_runnable(self) -> Union[Runnable, Callable]: + # Only used for structure, so the runnable should never be called + raise NotImplementedError + + +class Conditional(LangGraphNode): + + def __init__(self, key: str, conditional_edge_mapping: Dict[str, str], callable: Callable): self.callable = callable + self.branches = [] -class End: - name = "end" + for condition, output in conditional_edge_mapping.items(): + self.branches.append(Branch(key, condition)) + + self.conditional_edge_mapping = conditional_edge_mapping + + super().__init__(key) + + def get_runnable(self) -> Union[Runnable, Callable]: + return self.callable + -def branch(data, condition, mapping): - result = condition(data) - return Channel.write_to(mapping[result]) +######################################################### +# EDGE CLASSES # +######################################################### + +class LangGraphEdge: + def __init__(self, start_key: str, end_key: str): + self.start_key = start_key + self.end_key = end_key + + def flow(self, node_map: Dict[str, LangGraphNode]): + return ( + Channel.subscribe_to(self.start_key) | + node_map[self.start_key].get_runnable() | + Channel.write_to(self.end_key) + ) + + +class BranchEdge(LangGraphEdge): + + def flow(self, node_map: Dict[str, LangGraphNode]): + # flow should skip over the branch edge + raise NotImplementedError + + +class ConditionalEdge(LangGraphEdge): + + def __init__(self, base_key: str, branch_key: str): + self.base_key = base_key + self.branch_key = branch_key + if not branch_key.startswith(base_key) or not branch_key[len(base_key)] == ".": + raise ValueError(f"Invalid branch edge from {base_key} to {branch_key}") + + super().__init__(base_key, branch_key) + + def _branch(self, data, condition, mapping): + result = condition(data) + return Channel.write_to(mapping[result]) + + def flow(self, node_map: Dict[str, LangGraphNode]): + conditional_node = node_map[self.base_key] + + return ( + Channel.subscribe_to(self.start_key) | + ( + lambda x: self._branch( + x, + conditional_node.get_runnable(), + conditional_node.conditional_edge_mapping + ) + ) + ) + class Graph: def __init__(self): - self.nodes = {"end": End()} - self.connections = {} - self.branches = {} + end_node = End() + self.nodes = {end_node.key: end_node} + self.edges = [] + + # self.connections = {} + # self.branches = {} self.entry_point: Optional[str] = None - def register(self, node: Union[Actor, DecisionPoint]): - if node.name in self.nodes: - raise ValueError(f"Actor `{node.name}` already present.") - self.nodes[node.name] = node + def register_node(self, node: Actor): + if node.key in self.nodes: + raise ValueError(f"Actor `{node.key}` already present.") + self.nodes[node.key] = node - def connect(self, start: Actor, end: Union[Actor, DecisionPoint]): - if start.name not in self.nodes: - raise ValueError(f"Need to register `{start.name}` first") - if end.name not in self.nodes: - raise ValueError(f"Need to register `{end.name}` first") - if start.name in self.connections: - raise ValueError(f"Already found path for {start.name}") - self.connections[start.name] = end.name - def branch(self, start: DecisionPoint, end: Optional[Actor], condition: str): - end = end or End() - if start.name not in self.nodes: - raise ValueError(f"Need to register `{start.name}` first") - if end.name not in self.nodes: - raise ValueError(f"Need to register `{end.name}` first") - if start.name not in self.branches: - self.branches[start.name] = {} - if condition in self.branches[start.name]: - raise ValueError(f"Already found a condition for {start.name} and {condition}") - self.branches[start.name][condition] = end.name + def register_edge(self, start_key: str, end_key: str): + if start_key not in self.nodes: + raise ValueError(f"Need to register_node `{start_key}` first") + if end_key not in self.nodes: + raise ValueError(f"Need to register_node `{end_key}` first") - def set_entry_point(self, node: Union[DecisionPoint, Actor]): - if node.name not in self.nodes: - raise ValueError(f"Need to register `{node.name}` first") - self.entry_point = node.name + # TODO: support multiple message passing + if start_key in set(edge.start_key for edge in self.edges): + raise ValueError(f"Already found path for {start_key}") + + self.edges.append(LangGraphEdge(start_key, end_key)) - def set_finish_point(self, node: Actor): - if node.name not in self.nodes: - raise ValueError(f"Need to register `{node.name}` first") - self.connections[node.name] = "end" + def register_conditional_edges( + self, + start_key: str, + condition: Callable[Any, str], + conditional_edge_mapping: Dict[str, str]): + + conditional_node = Conditional( + f"_conditional_from_{start_key}", + conditional_edge_mapping, + condition + ) + + self.register_node(conditional_node) + self.register_edge(start_key, conditional_node.key) + + for branch in conditional_node.branches: + self.register_node(branch) + self.edges.append(ConditionalEdge(conditional_node.key, branch.key)) + self.edges.append( + BranchEdge(branch.key, conditional_node.conditional_edge_mapping[branch.condition]) + ) + + + def set_entry_point(self, key: str): + if key not in self.nodes: + raise ValueError(f"Need to register_node `{node.key}` first") + self.entry_point = key + + def set_finish_point(self, key: str): + if key not in self.nodes: + raise ValueError(f"Need to register_node `{node.key}` first") + self.register_edge(key, "end") def compile(self): - # Validate all nodes have an entry point - all_nodes = set(self.nodes) - all_entry_points = set(self.connections).union(self.branches) - branch_ends = set() - for v in self.branches.values(): - branch_ends.update(v.values()) - all_finish_points = set(self.connections.values()).union(branch_ends).union({self.entry_point}) - # If a node is not a finish point, then it is missing an entry point - missing_entry = all_nodes.difference(all_finish_points) - if missing_entry: - raise ValueError(f"Some nodes are missing entry points: {missing_entry}") - # If a node is not an entry point, then it is missing a finish point - missing_finish = all_nodes.difference(all_entry_points).difference({"end"}) - if missing_finish: - raise ValueError(f"Some nodes are missing finish points: {missing_finish}") - chains = { - start: Channel.subscribe_to(start) | self.nodes[start].runnable | Channel.write_to(end) - for start, end in self.connections.items() - } - decisions = { - start: Channel.subscribe_to(start) | (lambda x: branch(x, self.nodes[start].callable, mapping)) - for start, mapping in self.branches.items() + ################################################ + # STEP 1: VALIDATE GRAPH STRUCTURE # + ################################################ + seen_node_keys = set() + all_node_keys = set(self.nodes.keys()) + + edge_map = {} + for edge in self.edges: + edge_map[edge.start_key] = edge_map.get(edge.start_key, []) + [edge.end_key] + + to_see = [self.entry_point] + while len(to_see) > 0: + current = to_see.pop(0) + if current in seen_node_keys: + continue + + seen_node_keys.add(current) + next_nodes = edge_map.get(current, []) + to_see += next_nodes + + if len(next_nodes) == 0 and current != "end": + raise ValueError(f"Node {current} is a dead end") + + if seen_node_keys != all_node_keys: + raise ValueError(f"Found unreachable nodes: {list(all_node_keys - seen_node_keys)}") + + + ################################################ + # STEP 2: CREATE GRAPH # + ################################################ + + chains = { + edge.start_key: edge.flow(self.nodes) + for edge in self.edges + # specifically skip over branch edges since they are defined purely for structure + if not isinstance(edge, BranchEdge) } + app = Pregel( - chains = {**chains, **decisions}, + chains=chains, input=self.entry_point, output="end" ) diff --git a/poetry.lock b/poetry.lock index 9f474956c..f8f608c67 100644 --- a/poetry.lock +++ b/poetry.lock @@ -126,24 +126,25 @@ typing-extensions = {version = ">=4.0.0", markers = "python_version < \"3.9\""} [[package]] name = "anyio" -version = "3.7.1" +version = "4.2.0" description = "High level compatibility layer for multiple asynchronous event loop implementations" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "anyio-3.7.1-py3-none-any.whl", hash = "sha256:91dee416e570e92c64041bd18b900d1d6fa78dff7048769ce5ac5ddad004fbb5"}, - {file = "anyio-3.7.1.tar.gz", hash = "sha256:44a3c9aba0f5defa43261a8b3efb97891f2bd7d804e0e1f56419befa1adfc780"}, + {file = "anyio-4.2.0-py3-none-any.whl", hash = "sha256:745843b39e829e108e518c489b31dc757de7d2131d53fac32bd8df268227bfee"}, + {file = "anyio-4.2.0.tar.gz", hash = "sha256:e1875bb4b4e2de1669f4bc7869b6d3f54231cdced71605e6e64c9be77e3be50f"}, ] [package.dependencies] -exceptiongroup = {version = "*", markers = "python_version < \"3.11\""} +exceptiongroup = {version = ">=1.0.2", markers = "python_version < \"3.11\""} idna = ">=2.8" sniffio = ">=1.1" +typing-extensions = {version = ">=4.1", markers = "python_version < \"3.11\""} [package.extras] -doc = ["Sphinx", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme (>=1.2.2)", "sphinxcontrib-jquery"] -test = ["anyio[trio]", "coverage[toml] (>=4.5)", "hypothesis (>=4.0)", "mock (>=4)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (>=0.17)"] -trio = ["trio (<0.22)"] +doc = ["Sphinx (>=7)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme"] +test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (>=0.17)"] +trio = ["trio (>=0.23)"] [[package]] name = "appnope" @@ -277,36 +278,36 @@ files = [ [[package]] name = "attrs" -version = "23.1.0" +version = "23.2.0" description = "Classes Without Boilerplate" optional = false python-versions = ">=3.7" files = [ - {file = "attrs-23.1.0-py3-none-any.whl", hash = "sha256:1f28b4522cdc2fb4256ac1a020c78acf9cba2c6b461ccd2c126f3aa8e8335d04"}, - {file = "attrs-23.1.0.tar.gz", hash = "sha256:6279836d581513a26f1bf235f9acd333bc9115683f14f7e8fae46c98fc50e015"}, + {file = "attrs-23.2.0-py3-none-any.whl", hash = "sha256:99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1"}, + {file = "attrs-23.2.0.tar.gz", hash = "sha256:935dc3b529c262f6cf76e50877d35a4bd3c1de194fd41f47a2b7ae8f19971f30"}, ] [package.extras] cov = ["attrs[tests]", "coverage[toml] (>=5.3)"] -dev = ["attrs[docs,tests]", "pre-commit"] +dev = ["attrs[tests]", "pre-commit"] docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope-interface"] tests = ["attrs[tests-no-zope]", "zope-interface"] -tests-no-zope = ["cloudpickle", "hypothesis", "mypy (>=1.1.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +tests-mypy = ["mypy (>=1.6)", "pytest-mypy-plugins"] +tests-no-zope = ["attrs[tests-mypy]", "cloudpickle", "hypothesis", "pympler", "pytest (>=4.3.0)", "pytest-xdist[psutil]"] [[package]] name = "babel" -version = "2.13.1" +version = "2.14.0" description = "Internationalization utilities" optional = false python-versions = ">=3.7" files = [ - {file = "Babel-2.13.1-py3-none-any.whl", hash = "sha256:7077a4984b02b6727ac10f1f7294484f737443d7e2e66c5e4380e41a3ae0b4ed"}, - {file = "Babel-2.13.1.tar.gz", hash = "sha256:33e0952d7dd6374af8dbf6768cc4ddf3ccfefc244f9986d4074704f2fbd18900"}, + {file = "Babel-2.14.0-py3-none-any.whl", hash = "sha256:efb1a25b7118e67ce3a259bed20545c29cb68be8ad2c784c83689981b7a57287"}, + {file = "Babel-2.14.0.tar.gz", hash = "sha256:6919867db036398ba21eb5c7a0f6b28ab8cbc3ae7a73a44ebe34ae74a4e7d363"}, ] [package.dependencies] pytz = {version = ">=2015.7", markers = "python_version < \"3.9\""} -setuptools = {version = "*", markers = "python_version >= \"3.12\""} [package.extras] dev = ["freezegun (>=1.0,<2.0)", "pytest (>=6.0)", "pytest-cov"] @@ -545,13 +546,13 @@ files = [ [[package]] name = "comm" -version = "0.2.0" +version = "0.2.1" description = "Jupyter Python Comm implementation, for usage in ipykernel, xeus-python etc." optional = false python-versions = ">=3.8" files = [ - {file = "comm-0.2.0-py3-none-any.whl", hash = "sha256:2da8d9ebb8dd7bfc247adaff99f24dce705638a8042b85cb995066793e391001"}, - {file = "comm-0.2.0.tar.gz", hash = "sha256:a517ea2ca28931c7007a7a99c562a0fa5883cfb48963140cf642c41c948498be"}, + {file = "comm-0.2.1-py3-none-any.whl", hash = "sha256:87928485c0dfc0e7976fd89fc1e187023cf587e7c353e4a9b417555b44adf021"}, + {file = "comm-0.2.1.tar.gz", hash = "sha256:0bc91edae1344d39d3661dcbc36937181fdaddb304790458f8b044dbc064b89a"}, ] [package.dependencies] @@ -562,63 +563,63 @@ test = ["pytest"] [[package]] name = "coverage" -version = "7.3.2" +version = "7.4.0" description = "Code coverage measurement for Python" optional = false python-versions = ">=3.8" files = [ - {file = "coverage-7.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d872145f3a3231a5f20fd48500274d7df222e291d90baa2026cc5152b7ce86bf"}, - {file = "coverage-7.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:310b3bb9c91ea66d59c53fa4989f57d2436e08f18fb2f421a1b0b6b8cc7fffda"}, - {file = "coverage-7.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f47d39359e2c3779c5331fc740cf4bce6d9d680a7b4b4ead97056a0ae07cb49a"}, - {file = "coverage-7.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aa72dbaf2c2068404b9870d93436e6d23addd8bbe9295f49cbca83f6e278179c"}, - {file = "coverage-7.3.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:beaa5c1b4777f03fc63dfd2a6bd820f73f036bfb10e925fce067b00a340d0f3f"}, - {file = "coverage-7.3.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:dbc1b46b92186cc8074fee9d9fbb97a9dd06c6cbbef391c2f59d80eabdf0faa6"}, - {file = "coverage-7.3.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:315a989e861031334d7bee1f9113c8770472db2ac484e5b8c3173428360a9148"}, - {file = "coverage-7.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d1bc430677773397f64a5c88cb522ea43175ff16f8bfcc89d467d974cb2274f9"}, - {file = "coverage-7.3.2-cp310-cp310-win32.whl", hash = "sha256:a889ae02f43aa45032afe364c8ae84ad3c54828c2faa44f3bfcafecb5c96b02f"}, - {file = "coverage-7.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:c0ba320de3fb8c6ec16e0be17ee1d3d69adcda99406c43c0409cb5c41788a611"}, - {file = "coverage-7.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ac8c802fa29843a72d32ec56d0ca792ad15a302b28ca6203389afe21f8fa062c"}, - {file = "coverage-7.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:89a937174104339e3a3ffcf9f446c00e3a806c28b1841c63edb2b369310fd074"}, - {file = "coverage-7.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e267e9e2b574a176ddb983399dec325a80dbe161f1a32715c780b5d14b5f583a"}, - {file = "coverage-7.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2443cbda35df0d35dcfb9bf8f3c02c57c1d6111169e3c85fc1fcc05e0c9f39a3"}, - {file = "coverage-7.3.2-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4175e10cc8dda0265653e8714b3174430b07c1dca8957f4966cbd6c2b1b8065a"}, - {file = "coverage-7.3.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0cbf38419fb1a347aaf63481c00f0bdc86889d9fbf3f25109cf96c26b403fda1"}, - {file = "coverage-7.3.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:5c913b556a116b8d5f6ef834038ba983834d887d82187c8f73dec21049abd65c"}, - {file = "coverage-7.3.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:1981f785239e4e39e6444c63a98da3a1db8e971cb9ceb50a945ba6296b43f312"}, - {file = "coverage-7.3.2-cp311-cp311-win32.whl", hash = "sha256:43668cabd5ca8258f5954f27a3aaf78757e6acf13c17604d89648ecc0cc66640"}, - {file = "coverage-7.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:e10c39c0452bf6e694511c901426d6b5ac005acc0f78ff265dbe36bf81f808a2"}, - {file = "coverage-7.3.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:4cbae1051ab791debecc4a5dcc4a1ff45fc27b91b9aee165c8a27514dd160836"}, - {file = "coverage-7.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:12d15ab5833a997716d76f2ac1e4b4d536814fc213c85ca72756c19e5a6b3d63"}, - {file = "coverage-7.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3c7bba973ebee5e56fe9251300c00f1579652587a9f4a5ed8404b15a0471f216"}, - {file = "coverage-7.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fe494faa90ce6381770746077243231e0b83ff3f17069d748f645617cefe19d4"}, - {file = "coverage-7.3.2-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6e9589bd04d0461a417562649522575d8752904d35c12907d8c9dfeba588faf"}, - {file = "coverage-7.3.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d51ac2a26f71da1b57f2dc81d0e108b6ab177e7d30e774db90675467c847bbdf"}, - {file = "coverage-7.3.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:99b89d9f76070237975b315b3d5f4d6956ae354a4c92ac2388a5695516e47c84"}, - {file = "coverage-7.3.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:fa28e909776dc69efb6ed975a63691bc8172b64ff357e663a1bb06ff3c9b589a"}, - {file = "coverage-7.3.2-cp312-cp312-win32.whl", hash = "sha256:289fe43bf45a575e3ab10b26d7b6f2ddb9ee2dba447499f5401cfb5ecb8196bb"}, - {file = "coverage-7.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:7dbc3ed60e8659bc59b6b304b43ff9c3ed858da2839c78b804973f613d3e92ed"}, - {file = "coverage-7.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f94b734214ea6a36fe16e96a70d941af80ff3bfd716c141300d95ebc85339738"}, - {file = "coverage-7.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:af3d828d2c1cbae52d34bdbb22fcd94d1ce715d95f1a012354a75e5913f1bda2"}, - {file = "coverage-7.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:630b13e3036e13c7adc480ca42fa7afc2a5d938081d28e20903cf7fd687872e2"}, - {file = "coverage-7.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c9eacf273e885b02a0273bb3a2170f30e2d53a6d53b72dbe02d6701b5296101c"}, - {file = "coverage-7.3.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d8f17966e861ff97305e0801134e69db33b143bbfb36436efb9cfff6ec7b2fd9"}, - {file = "coverage-7.3.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b4275802d16882cf9c8b3d057a0839acb07ee9379fa2749eca54efbce1535b82"}, - {file = "coverage-7.3.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:72c0cfa5250f483181e677ebc97133ea1ab3eb68645e494775deb6a7f6f83901"}, - {file = "coverage-7.3.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:cb536f0dcd14149425996821a168f6e269d7dcd2c273a8bff8201e79f5104e76"}, - {file = "coverage-7.3.2-cp38-cp38-win32.whl", hash = "sha256:307adb8bd3abe389a471e649038a71b4eb13bfd6b7dd9a129fa856f5c695cf92"}, - {file = "coverage-7.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:88ed2c30a49ea81ea3b7f172e0269c182a44c236eb394718f976239892c0a27a"}, - {file = "coverage-7.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b631c92dfe601adf8f5ebc7fc13ced6bb6e9609b19d9a8cd59fa47c4186ad1ce"}, - {file = "coverage-7.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d3d9df4051c4a7d13036524b66ecf7a7537d14c18a384043f30a303b146164e9"}, - {file = "coverage-7.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5f7363d3b6a1119ef05015959ca24a9afc0ea8a02c687fe7e2d557705375c01f"}, - {file = "coverage-7.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2f11cc3c967a09d3695d2a6f03fb3e6236622b93be7a4b5dc09166a861be6d25"}, - {file = "coverage-7.3.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:149de1d2401ae4655c436a3dced6dd153f4c3309f599c3d4bd97ab172eaf02d9"}, - {file = "coverage-7.3.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:3a4006916aa6fee7cd38db3bfc95aa9c54ebb4ffbfc47c677c8bba949ceba0a6"}, - {file = "coverage-7.3.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9028a3871280110d6e1aa2df1afd5ef003bab5fb1ef421d6dc748ae1c8ef2ebc"}, - {file = "coverage-7.3.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:9f805d62aec8eb92bab5b61c0f07329275b6f41c97d80e847b03eb894f38d083"}, - {file = "coverage-7.3.2-cp39-cp39-win32.whl", hash = "sha256:d1c88ec1a7ff4ebca0219f5b1ef863451d828cccf889c173e1253aa84b1e07ce"}, - {file = "coverage-7.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:b4767da59464bb593c07afceaddea61b154136300881844768037fd5e859353f"}, - {file = "coverage-7.3.2-pp38.pp39.pp310-none-any.whl", hash = "sha256:ae97af89f0fbf373400970c0a21eef5aa941ffeed90aee43650b81f7d7f47637"}, - {file = "coverage-7.3.2.tar.gz", hash = "sha256:be32ad29341b0170e795ca590e1c07e81fc061cb5b10c74ce7203491484404ef"}, + {file = "coverage-7.4.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:36b0ea8ab20d6a7564e89cb6135920bc9188fb5f1f7152e94e8300b7b189441a"}, + {file = "coverage-7.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0676cd0ba581e514b7f726495ea75aba3eb20899d824636c6f59b0ed2f88c471"}, + {file = "coverage-7.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d0ca5c71a5a1765a0f8f88022c52b6b8be740e512980362f7fdbb03725a0d6b9"}, + {file = "coverage-7.4.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a7c97726520f784239f6c62506bc70e48d01ae71e9da128259d61ca5e9788516"}, + {file = "coverage-7.4.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:815ac2d0f3398a14286dc2cea223a6f338109f9ecf39a71160cd1628786bc6f5"}, + {file = "coverage-7.4.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:80b5ee39b7f0131ebec7968baa9b2309eddb35b8403d1869e08f024efd883566"}, + {file = "coverage-7.4.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:5b2ccb7548a0b65974860a78c9ffe1173cfb5877460e5a229238d985565574ae"}, + {file = "coverage-7.4.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:995ea5c48c4ebfd898eacb098164b3cc826ba273b3049e4a889658548e321b43"}, + {file = "coverage-7.4.0-cp310-cp310-win32.whl", hash = "sha256:79287fd95585ed36e83182794a57a46aeae0b64ca53929d1176db56aacc83451"}, + {file = "coverage-7.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:5b14b4f8760006bfdb6e08667af7bc2d8d9bfdb648351915315ea17645347137"}, + {file = "coverage-7.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:04387a4a6ecb330c1878907ce0dc04078ea72a869263e53c72a1ba5bbdf380ca"}, + {file = "coverage-7.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ea81d8f9691bb53f4fb4db603203029643caffc82bf998ab5b59ca05560f4c06"}, + {file = "coverage-7.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:74775198b702868ec2d058cb92720a3c5a9177296f75bd97317c787daf711505"}, + {file = "coverage-7.4.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:76f03940f9973bfaee8cfba70ac991825611b9aac047e5c80d499a44079ec0bc"}, + {file = "coverage-7.4.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:485e9f897cf4856a65a57c7f6ea3dc0d4e6c076c87311d4bc003f82cfe199d25"}, + {file = "coverage-7.4.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:6ae8c9d301207e6856865867d762a4b6fd379c714fcc0607a84b92ee63feff70"}, + {file = "coverage-7.4.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:bf477c355274a72435ceb140dc42de0dc1e1e0bf6e97195be30487d8eaaf1a09"}, + {file = "coverage-7.4.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:83c2dda2666fe32332f8e87481eed056c8b4d163fe18ecc690b02802d36a4d26"}, + {file = "coverage-7.4.0-cp311-cp311-win32.whl", hash = "sha256:697d1317e5290a313ef0d369650cfee1a114abb6021fa239ca12b4849ebbd614"}, + {file = "coverage-7.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:26776ff6c711d9d835557ee453082025d871e30b3fd6c27fcef14733f67f0590"}, + {file = "coverage-7.4.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:13eaf476ec3e883fe3e5fe3707caeb88268a06284484a3daf8250259ef1ba143"}, + {file = "coverage-7.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846f52f46e212affb5bcf131c952fb4075b55aae6b61adc9856222df89cbe3e2"}, + {file = "coverage-7.4.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:26f66da8695719ccf90e794ed567a1549bb2644a706b41e9f6eae6816b398c4a"}, + {file = "coverage-7.4.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:164fdcc3246c69a6526a59b744b62e303039a81e42cfbbdc171c91a8cc2f9446"}, + {file = "coverage-7.4.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:316543f71025a6565677d84bc4df2114e9b6a615aa39fb165d697dba06a54af9"}, + {file = "coverage-7.4.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:bb1de682da0b824411e00a0d4da5a784ec6496b6850fdf8c865c1d68c0e318dd"}, + {file = "coverage-7.4.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:0e8d06778e8fbffccfe96331a3946237f87b1e1d359d7fbe8b06b96c95a5407a"}, + {file = "coverage-7.4.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a56de34db7b7ff77056a37aedded01b2b98b508227d2d0979d373a9b5d353daa"}, + {file = "coverage-7.4.0-cp312-cp312-win32.whl", hash = "sha256:51456e6fa099a8d9d91497202d9563a320513fcf59f33991b0661a4a6f2ad450"}, + {file = "coverage-7.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:cd3c1e4cb2ff0083758f09be0f77402e1bdf704adb7f89108007300a6da587d0"}, + {file = "coverage-7.4.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:e9d1bf53c4c8de58d22e0e956a79a5b37f754ed1ffdbf1a260d9dcfa2d8a325e"}, + {file = "coverage-7.4.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:109f5985182b6b81fe33323ab4707011875198c41964f014579cf82cebf2bb85"}, + {file = "coverage-7.4.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3cc9d4bc55de8003663ec94c2f215d12d42ceea128da8f0f4036235a119c88ac"}, + {file = "coverage-7.4.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cc6d65b21c219ec2072c1293c505cf36e4e913a3f936d80028993dd73c7906b1"}, + {file = "coverage-7.4.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5a10a4920def78bbfff4eff8a05c51be03e42f1c3735be42d851f199144897ba"}, + {file = "coverage-7.4.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b8e99f06160602bc64da35158bb76c73522a4010f0649be44a4e167ff8555952"}, + {file = "coverage-7.4.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:7d360587e64d006402b7116623cebf9d48893329ef035278969fa3bbf75b697e"}, + {file = "coverage-7.4.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:29f3abe810930311c0b5d1a7140f6395369c3db1be68345638c33eec07535105"}, + {file = "coverage-7.4.0-cp38-cp38-win32.whl", hash = "sha256:5040148f4ec43644702e7b16ca864c5314ccb8ee0751ef617d49aa0e2d6bf4f2"}, + {file = "coverage-7.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:9864463c1c2f9cb3b5db2cf1ff475eed2f0b4285c2aaf4d357b69959941aa555"}, + {file = "coverage-7.4.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:936d38794044b26c99d3dd004d8af0035ac535b92090f7f2bb5aa9c8e2f5cd42"}, + {file = "coverage-7.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:799c8f873794a08cdf216aa5d0531c6a3747793b70c53f70e98259720a6fe2d7"}, + {file = "coverage-7.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e7defbb9737274023e2d7af02cac77043c86ce88a907c58f42b580a97d5bcca9"}, + {file = "coverage-7.4.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a1526d265743fb49363974b7aa8d5899ff64ee07df47dd8d3e37dcc0818f09ed"}, + {file = "coverage-7.4.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf635a52fc1ea401baf88843ae8708591aa4adff875e5c23220de43b1ccf575c"}, + {file = "coverage-7.4.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:756ded44f47f330666843b5781be126ab57bb57c22adbb07d83f6b519783b870"}, + {file = "coverage-7.4.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:0eb3c2f32dabe3a4aaf6441dde94f35687224dfd7eb2a7f47f3fd9428e421058"}, + {file = "coverage-7.4.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:bfd5db349d15c08311702611f3dccbef4b4e2ec148fcc636cf8739519b4a5c0f"}, + {file = "coverage-7.4.0-cp39-cp39-win32.whl", hash = "sha256:53d7d9158ee03956e0eadac38dfa1ec8068431ef8058fe6447043db1fb40d932"}, + {file = "coverage-7.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:cfd2a8b6b0d8e66e944d47cdec2f47c48fef2ba2f2dff5a9a75757f64172857e"}, + {file = "coverage-7.4.0-pp38.pp39.pp310-none-any.whl", hash = "sha256:c530833afc4707fe48524a44844493f36d8727f04dcce91fb978c414a8556cc6"}, + {file = "coverage-7.4.0.tar.gz", hash = "sha256:707c0f58cb1712b8809ece32b68996ee1e609f71bd14615bd8f87a1293cb610e"}, ] [package.dependencies] @@ -731,13 +732,13 @@ tests = ["asttokens (>=2.1.0)", "coverage", "coverage-enable-subprocess", "ipyth [[package]] name = "fastjsonschema" -version = "2.19.0" +version = "2.19.1" description = "Fastest Python implementation of JSON schema" optional = false python-versions = "*" files = [ - {file = "fastjsonschema-2.19.0-py3-none-any.whl", hash = "sha256:b9fd1a2dd6971dbc7fee280a95bd199ae0dd9ce22beb91cc75e9c1c528a5170e"}, - {file = "fastjsonschema-2.19.0.tar.gz", hash = "sha256:e25df6647e1bc4a26070b700897b07b542ec898dd4f1f6ea013e7f6a88417225"}, + {file = "fastjsonschema-2.19.1-py3-none-any.whl", hash = "sha256:3672b47bc94178c9f23dbb654bf47440155d4db9df5f7bc47643315f9c405cd0"}, + {file = "fastjsonschema-2.19.1.tar.gz", hash = "sha256:e3126a94bdc4623d3de4485f8d468a12f02a67921315ddc87836d6e456dc789d"}, ] [package.extras] @@ -756,72 +757,88 @@ files = [ [[package]] name = "frozenlist" -version = "1.4.0" +version = "1.4.1" description = "A list-like structure which implements collections.abc.MutableSequence" optional = false python-versions = ">=3.8" files = [ - {file = "frozenlist-1.4.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:764226ceef3125e53ea2cb275000e309c0aa5464d43bd72abd661e27fffc26ab"}, - {file = "frozenlist-1.4.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d6484756b12f40003c6128bfcc3fa9f0d49a687e171186c2d85ec82e3758c559"}, - {file = "frozenlist-1.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9ac08e601308e41eb533f232dbf6b7e4cea762f9f84f6357136eed926c15d12c"}, - {file = "frozenlist-1.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d081f13b095d74b67d550de04df1c756831f3b83dc9881c38985834387487f1b"}, - {file = "frozenlist-1.4.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:71932b597f9895f011f47f17d6428252fc728ba2ae6024e13c3398a087c2cdea"}, - {file = "frozenlist-1.4.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:981b9ab5a0a3178ff413bca62526bb784249421c24ad7381e39d67981be2c326"}, - {file = "frozenlist-1.4.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e41f3de4df3e80de75845d3e743b3f1c4c8613c3997a912dbf0229fc61a8b963"}, - {file = "frozenlist-1.4.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6918d49b1f90821e93069682c06ffde41829c346c66b721e65a5c62b4bab0300"}, - {file = "frozenlist-1.4.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0e5c8764c7829343d919cc2dfc587a8db01c4f70a4ebbc49abde5d4b158b007b"}, - {file = "frozenlist-1.4.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:8d0edd6b1c7fb94922bf569c9b092ee187a83f03fb1a63076e7774b60f9481a8"}, - {file = "frozenlist-1.4.0-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:e29cda763f752553fa14c68fb2195150bfab22b352572cb36c43c47bedba70eb"}, - {file = "frozenlist-1.4.0-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:0c7c1b47859ee2cac3846fde1c1dc0f15da6cec5a0e5c72d101e0f83dcb67ff9"}, - {file = "frozenlist-1.4.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:901289d524fdd571be1c7be054f48b1f88ce8dddcbdf1ec698b27d4b8b9e5d62"}, - {file = "frozenlist-1.4.0-cp310-cp310-win32.whl", hash = "sha256:1a0848b52815006ea6596c395f87449f693dc419061cc21e970f139d466dc0a0"}, - {file = "frozenlist-1.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:b206646d176a007466358aa21d85cd8600a415c67c9bd15403336c331a10d956"}, - {file = "frozenlist-1.4.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:de343e75f40e972bae1ef6090267f8260c1446a1695e77096db6cfa25e759a95"}, - {file = "frozenlist-1.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ad2a9eb6d9839ae241701d0918f54c51365a51407fd80f6b8289e2dfca977cc3"}, - {file = "frozenlist-1.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bd7bd3b3830247580de99c99ea2a01416dfc3c34471ca1298bccabf86d0ff4dc"}, - {file = "frozenlist-1.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bdf1847068c362f16b353163391210269e4f0569a3c166bc6a9f74ccbfc7e839"}, - {file = "frozenlist-1.4.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:38461d02d66de17455072c9ba981d35f1d2a73024bee7790ac2f9e361ef1cd0c"}, - {file = "frozenlist-1.4.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d5a32087d720c608f42caed0ef36d2b3ea61a9d09ee59a5142d6070da9041b8f"}, - {file = "frozenlist-1.4.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dd65632acaf0d47608190a71bfe46b209719bf2beb59507db08ccdbe712f969b"}, - {file = "frozenlist-1.4.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:261b9f5d17cac914531331ff1b1d452125bf5daa05faf73b71d935485b0c510b"}, - {file = "frozenlist-1.4.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:b89ac9768b82205936771f8d2eb3ce88503b1556324c9f903e7156669f521472"}, - {file = "frozenlist-1.4.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:008eb8b31b3ea6896da16c38c1b136cb9fec9e249e77f6211d479db79a4eaf01"}, - {file = "frozenlist-1.4.0-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:e74b0506fa5aa5598ac6a975a12aa8928cbb58e1f5ac8360792ef15de1aa848f"}, - {file = "frozenlist-1.4.0-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:490132667476f6781b4c9458298b0c1cddf237488abd228b0b3650e5ecba7467"}, - {file = "frozenlist-1.4.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:76d4711f6f6d08551a7e9ef28c722f4a50dd0fc204c56b4bcd95c6cc05ce6fbb"}, - {file = "frozenlist-1.4.0-cp311-cp311-win32.whl", hash = "sha256:a02eb8ab2b8f200179b5f62b59757685ae9987996ae549ccf30f983f40602431"}, - {file = "frozenlist-1.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:515e1abc578dd3b275d6a5114030b1330ba044ffba03f94091842852f806f1c1"}, - {file = "frozenlist-1.4.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:f0ed05f5079c708fe74bf9027e95125334b6978bf07fd5ab923e9e55e5fbb9d3"}, - {file = "frozenlist-1.4.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ca265542ca427bf97aed183c1676e2a9c66942e822b14dc6e5f42e038f92a503"}, - {file = "frozenlist-1.4.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:491e014f5c43656da08958808588cc6c016847b4360e327a62cb308c791bd2d9"}, - {file = "frozenlist-1.4.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:17ae5cd0f333f94f2e03aaf140bb762c64783935cc764ff9c82dff626089bebf"}, - {file = "frozenlist-1.4.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1e78fb68cf9c1a6aa4a9a12e960a5c9dfbdb89b3695197aa7064705662515de2"}, - {file = "frozenlist-1.4.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d5655a942f5f5d2c9ed93d72148226d75369b4f6952680211972a33e59b1dfdc"}, - {file = "frozenlist-1.4.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c11b0746f5d946fecf750428a95f3e9ebe792c1ee3b1e96eeba145dc631a9672"}, - {file = "frozenlist-1.4.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e66d2a64d44d50d2543405fb183a21f76b3b5fd16f130f5c99187c3fb4e64919"}, - {file = "frozenlist-1.4.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:88f7bc0fcca81f985f78dd0fa68d2c75abf8272b1f5c323ea4a01a4d7a614efc"}, - {file = "frozenlist-1.4.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:5833593c25ac59ede40ed4de6d67eb42928cca97f26feea219f21d0ed0959b79"}, - {file = "frozenlist-1.4.0-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:fec520865f42e5c7f050c2a79038897b1c7d1595e907a9e08e3353293ffc948e"}, - {file = "frozenlist-1.4.0-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:b826d97e4276750beca7c8f0f1a4938892697a6bcd8ec8217b3312dad6982781"}, - {file = "frozenlist-1.4.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:ceb6ec0a10c65540421e20ebd29083c50e6d1143278746a4ef6bcf6153171eb8"}, - {file = "frozenlist-1.4.0-cp38-cp38-win32.whl", hash = "sha256:2b8bcf994563466db019fab287ff390fffbfdb4f905fc77bc1c1d604b1c689cc"}, - {file = "frozenlist-1.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:a6c8097e01886188e5be3e6b14e94ab365f384736aa1fca6a0b9e35bd4a30bc7"}, - {file = "frozenlist-1.4.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:6c38721585f285203e4b4132a352eb3daa19121a035f3182e08e437cface44bf"}, - {file = "frozenlist-1.4.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a0c6da9aee33ff0b1a451e867da0c1f47408112b3391dd43133838339e410963"}, - {file = "frozenlist-1.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:93ea75c050c5bb3d98016b4ba2497851eadf0ac154d88a67d7a6816206f6fa7f"}, - {file = "frozenlist-1.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f61e2dc5ad442c52b4887f1fdc112f97caeff4d9e6ebe78879364ac59f1663e1"}, - {file = "frozenlist-1.4.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aa384489fefeb62321b238e64c07ef48398fe80f9e1e6afeff22e140e0850eef"}, - {file = "frozenlist-1.4.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:10ff5faaa22786315ef57097a279b833ecab1a0bfb07d604c9cbb1c4cdc2ed87"}, - {file = "frozenlist-1.4.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:007df07a6e3eb3e33e9a1fe6a9db7af152bbd8a185f9aaa6ece10a3529e3e1c6"}, - {file = "frozenlist-1.4.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f4f399d28478d1f604c2ff9119907af9726aed73680e5ed1ca634d377abb087"}, - {file = "frozenlist-1.4.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:c5374b80521d3d3f2ec5572e05adc94601985cc526fb276d0c8574a6d749f1b3"}, - {file = "frozenlist-1.4.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:ce31ae3e19f3c902de379cf1323d90c649425b86de7bbdf82871b8a2a0615f3d"}, - {file = "frozenlist-1.4.0-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:7211ef110a9194b6042449431e08c4d80c0481e5891e58d429df5899690511c2"}, - {file = "frozenlist-1.4.0-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:556de4430ce324c836789fa4560ca62d1591d2538b8ceb0b4f68fb7b2384a27a"}, - {file = "frozenlist-1.4.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:7645a8e814a3ee34a89c4a372011dcd817964ce8cb273c8ed6119d706e9613e3"}, - {file = "frozenlist-1.4.0-cp39-cp39-win32.whl", hash = "sha256:19488c57c12d4e8095a922f328df3f179c820c212940a498623ed39160bc3c2f"}, - {file = "frozenlist-1.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:6221d84d463fb110bdd7619b69cb43878a11d51cbb9394ae3105d082d5199167"}, - {file = "frozenlist-1.4.0.tar.gz", hash = "sha256:09163bdf0b2907454042edb19f887c6d33806adc71fbd54afc14908bfdc22251"}, + {file = "frozenlist-1.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:f9aa1878d1083b276b0196f2dfbe00c9b7e752475ed3b682025ff20c1c1f51ac"}, + {file = "frozenlist-1.4.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:29acab3f66f0f24674b7dc4736477bcd4bc3ad4b896f5f45379a67bce8b96868"}, + {file = "frozenlist-1.4.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:74fb4bee6880b529a0c6560885fce4dc95936920f9f20f53d99a213f7bf66776"}, + {file = "frozenlist-1.4.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:590344787a90ae57d62511dd7c736ed56b428f04cd8c161fcc5e7232c130c69a"}, + {file = "frozenlist-1.4.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:068b63f23b17df8569b7fdca5517edef76171cf3897eb68beb01341131fbd2ad"}, + {file = "frozenlist-1.4.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5c849d495bf5154cd8da18a9eb15db127d4dba2968d88831aff6f0331ea9bd4c"}, + {file = "frozenlist-1.4.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9750cc7fe1ae3b1611bb8cfc3f9ec11d532244235d75901fb6b8e42ce9229dfe"}, + {file = "frozenlist-1.4.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a9b2de4cf0cdd5bd2dee4c4f63a653c61d2408055ab77b151c1957f221cabf2a"}, + {file = "frozenlist-1.4.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0633c8d5337cb5c77acbccc6357ac49a1770b8c487e5b3505c57b949b4b82e98"}, + {file = "frozenlist-1.4.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:27657df69e8801be6c3638054e202a135c7f299267f1a55ed3a598934f6c0d75"}, + {file = "frozenlist-1.4.1-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:f9a3ea26252bd92f570600098783d1371354d89d5f6b7dfd87359d669f2109b5"}, + {file = "frozenlist-1.4.1-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:4f57dab5fe3407b6c0c1cc907ac98e8a189f9e418f3b6e54d65a718aaafe3950"}, + {file = "frozenlist-1.4.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:e02a0e11cf6597299b9f3bbd3f93d79217cb90cfd1411aec33848b13f5c656cc"}, + {file = "frozenlist-1.4.1-cp310-cp310-win32.whl", hash = "sha256:a828c57f00f729620a442881cc60e57cfcec6842ba38e1b19fd3e47ac0ff8dc1"}, + {file = "frozenlist-1.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:f56e2333dda1fe0f909e7cc59f021eba0d2307bc6f012a1ccf2beca6ba362439"}, + {file = "frozenlist-1.4.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:a0cb6f11204443f27a1628b0e460f37fb30f624be6051d490fa7d7e26d4af3d0"}, + {file = "frozenlist-1.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b46c8ae3a8f1f41a0d2ef350c0b6e65822d80772fe46b653ab6b6274f61d4a49"}, + {file = "frozenlist-1.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fde5bd59ab5357e3853313127f4d3565fc7dad314a74d7b5d43c22c6a5ed2ced"}, + {file = "frozenlist-1.4.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:722e1124aec435320ae01ee3ac7bec11a5d47f25d0ed6328f2273d287bc3abb0"}, + {file = "frozenlist-1.4.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2471c201b70d58a0f0c1f91261542a03d9a5e088ed3dc6c160d614c01649c106"}, + {file = "frozenlist-1.4.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c757a9dd70d72b076d6f68efdbb9bc943665ae954dad2801b874c8c69e185068"}, + {file = "frozenlist-1.4.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f146e0911cb2f1da549fc58fc7bcd2b836a44b79ef871980d605ec392ff6b0d2"}, + {file = "frozenlist-1.4.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f9c515e7914626b2a2e1e311794b4c35720a0be87af52b79ff8e1429fc25f19"}, + {file = "frozenlist-1.4.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:c302220494f5c1ebeb0912ea782bcd5e2f8308037b3c7553fad0e48ebad6ad82"}, + {file = "frozenlist-1.4.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:442acde1e068288a4ba7acfe05f5f343e19fac87bfc96d89eb886b0363e977ec"}, + {file = "frozenlist-1.4.1-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:1b280e6507ea8a4fa0c0a7150b4e526a8d113989e28eaaef946cc77ffd7efc0a"}, + {file = "frozenlist-1.4.1-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:fe1a06da377e3a1062ae5fe0926e12b84eceb8a50b350ddca72dc85015873f74"}, + {file = "frozenlist-1.4.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:db9e724bebd621d9beca794f2a4ff1d26eed5965b004a97f1f1685a173b869c2"}, + {file = "frozenlist-1.4.1-cp311-cp311-win32.whl", hash = "sha256:e774d53b1a477a67838a904131c4b0eef6b3d8a651f8b138b04f748fccfefe17"}, + {file = "frozenlist-1.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:fb3c2db03683b5767dedb5769b8a40ebb47d6f7f45b1b3e3b4b51ec8ad9d9825"}, + {file = "frozenlist-1.4.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:1979bc0aeb89b33b588c51c54ab0161791149f2461ea7c7c946d95d5f93b56ae"}, + {file = "frozenlist-1.4.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:cc7b01b3754ea68a62bd77ce6020afaffb44a590c2289089289363472d13aedb"}, + {file = "frozenlist-1.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c9c92be9fd329ac801cc420e08452b70e7aeab94ea4233a4804f0915c14eba9b"}, + {file = "frozenlist-1.4.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c3894db91f5a489fc8fa6a9991820f368f0b3cbdb9cd8849547ccfab3392d86"}, + {file = "frozenlist-1.4.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ba60bb19387e13597fb059f32cd4d59445d7b18b69a745b8f8e5db0346f33480"}, + {file = "frozenlist-1.4.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8aefbba5f69d42246543407ed2461db31006b0f76c4e32dfd6f42215a2c41d09"}, + {file = "frozenlist-1.4.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:780d3a35680ced9ce682fbcf4cb9c2bad3136eeff760ab33707b71db84664e3a"}, + {file = "frozenlist-1.4.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9acbb16f06fe7f52f441bb6f413ebae6c37baa6ef9edd49cdd567216da8600cd"}, + {file = "frozenlist-1.4.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:23b701e65c7b36e4bf15546a89279bd4d8675faabc287d06bbcfac7d3c33e1e6"}, + {file = "frozenlist-1.4.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:3e0153a805a98f5ada7e09826255ba99fb4f7524bb81bf6b47fb702666484ae1"}, + {file = "frozenlist-1.4.1-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:dd9b1baec094d91bf36ec729445f7769d0d0cf6b64d04d86e45baf89e2b9059b"}, + {file = "frozenlist-1.4.1-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:1a4471094e146b6790f61b98616ab8e44f72661879cc63fa1049d13ef711e71e"}, + {file = "frozenlist-1.4.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:5667ed53d68d91920defdf4035d1cdaa3c3121dc0b113255124bcfada1cfa1b8"}, + {file = "frozenlist-1.4.1-cp312-cp312-win32.whl", hash = "sha256:beee944ae828747fd7cb216a70f120767fc9f4f00bacae8543c14a6831673f89"}, + {file = "frozenlist-1.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:64536573d0a2cb6e625cf309984e2d873979709f2cf22839bf2d61790b448ad5"}, + {file = "frozenlist-1.4.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:20b51fa3f588ff2fe658663db52a41a4f7aa6c04f6201449c6c7c476bd255c0d"}, + {file = "frozenlist-1.4.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:410478a0c562d1a5bcc2f7ea448359fcb050ed48b3c6f6f4f18c313a9bdb1826"}, + {file = "frozenlist-1.4.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c6321c9efe29975232da3bd0af0ad216800a47e93d763ce64f291917a381b8eb"}, + {file = "frozenlist-1.4.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:48f6a4533887e189dae092f1cf981f2e3885175f7a0f33c91fb5b7b682b6bab6"}, + {file = "frozenlist-1.4.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6eb73fa5426ea69ee0e012fb59cdc76a15b1283d6e32e4f8dc4482ec67d1194d"}, + {file = "frozenlist-1.4.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fbeb989b5cc29e8daf7f976b421c220f1b8c731cbf22b9130d8815418ea45887"}, + {file = "frozenlist-1.4.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:32453c1de775c889eb4e22f1197fe3bdfe457d16476ea407472b9442e6295f7a"}, + {file = "frozenlist-1.4.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:693945278a31f2086d9bf3df0fe8254bbeaef1fe71e1351c3bd730aa7d31c41b"}, + {file = "frozenlist-1.4.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:1d0ce09d36d53bbbe566fe296965b23b961764c0bcf3ce2fa45f463745c04701"}, + {file = "frozenlist-1.4.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:3a670dc61eb0d0eb7080890c13de3066790f9049b47b0de04007090807c776b0"}, + {file = "frozenlist-1.4.1-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:dca69045298ce5c11fd539682cff879cc1e664c245d1c64da929813e54241d11"}, + {file = "frozenlist-1.4.1-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:a06339f38e9ed3a64e4c4e43aec7f59084033647f908e4259d279a52d3757d09"}, + {file = "frozenlist-1.4.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b7f2f9f912dca3934c1baec2e4585a674ef16fe00218d833856408c48d5beee7"}, + {file = "frozenlist-1.4.1-cp38-cp38-win32.whl", hash = "sha256:e7004be74cbb7d9f34553a5ce5fb08be14fb33bc86f332fb71cbe5216362a497"}, + {file = "frozenlist-1.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:5a7d70357e7cee13f470c7883a063aae5fe209a493c57d86eb7f5a6f910fae09"}, + {file = "frozenlist-1.4.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:bfa4a17e17ce9abf47a74ae02f32d014c5e9404b6d9ac7f729e01562bbee601e"}, + {file = "frozenlist-1.4.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b7e3ed87d4138356775346e6845cccbe66cd9e207f3cd11d2f0b9fd13681359d"}, + {file = "frozenlist-1.4.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c99169d4ff810155ca50b4da3b075cbde79752443117d89429595c2e8e37fed8"}, + {file = "frozenlist-1.4.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:edb678da49d9f72c9f6c609fbe41a5dfb9a9282f9e6a2253d5a91e0fc382d7c0"}, + {file = "frozenlist-1.4.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6db4667b187a6742b33afbbaf05a7bc551ffcf1ced0000a571aedbb4aa42fc7b"}, + {file = "frozenlist-1.4.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:55fdc093b5a3cb41d420884cdaf37a1e74c3c37a31f46e66286d9145d2063bd0"}, + {file = "frozenlist-1.4.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:82e8211d69a4f4bc360ea22cd6555f8e61a1bd211d1d5d39d3d228b48c83a897"}, + {file = "frozenlist-1.4.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:89aa2c2eeb20957be2d950b85974b30a01a762f3308cd02bb15e1ad632e22dc7"}, + {file = "frozenlist-1.4.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9d3e0c25a2350080e9319724dede4f31f43a6c9779be48021a7f4ebde8b2d742"}, + {file = "frozenlist-1.4.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7268252af60904bf52c26173cbadc3a071cece75f873705419c8681f24d3edea"}, + {file = "frozenlist-1.4.1-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:0c250a29735d4f15321007fb02865f0e6b6a41a6b88f1f523ca1596ab5f50bd5"}, + {file = "frozenlist-1.4.1-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:96ec70beabbd3b10e8bfe52616a13561e58fe84c0101dd031dc78f250d5128b9"}, + {file = "frozenlist-1.4.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:23b2d7679b73fe0e5a4560b672a39f98dfc6f60df63823b0a9970525325b95f6"}, + {file = "frozenlist-1.4.1-cp39-cp39-win32.whl", hash = "sha256:a7496bfe1da7fb1a4e1cc23bb67c58fab69311cc7d32b5a99c2007b4b2a0e932"}, + {file = "frozenlist-1.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:e6a20a581f9ce92d389a8c7d7c3dd47c81fd5d6e655c8dddf341e14aa48659d0"}, + {file = "frozenlist-1.4.1-py3-none-any.whl", hash = "sha256:04ced3e6a46b4cfffe20f9ae482818e34eba9b5fb0ce4056e4cc9b6e212d09b7"}, + {file = "frozenlist-1.4.1.tar.gz", hash = "sha256:c037a86e8513059a2613aaba4d817bb90b9d9b6b69aace3ce9c877e8c8ed402b"}, ] [[package]] @@ -964,20 +981,20 @@ files = [ [[package]] name = "importlib-metadata" -version = "6.8.0" +version = "7.0.1" description = "Read metadata from Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "importlib_metadata-6.8.0-py3-none-any.whl", hash = "sha256:3ebb78df84a805d7698245025b975d9d67053cd94c79245ba4b3eb694abe68bb"}, - {file = "importlib_metadata-6.8.0.tar.gz", hash = "sha256:dbace7892d8c0c4ac1ad096662232f831d4e64f4c4545bd53016a3e9d4654743"}, + {file = "importlib_metadata-7.0.1-py3-none-any.whl", hash = "sha256:4805911c3a4ec7c3966410053e9ec6a1fecd629117df5adee56dfc9432a1081e"}, + {file = "importlib_metadata-7.0.1.tar.gz", hash = "sha256:f238736bb06590ae52ac1fab06a3a9ef1d8dce2b7a35b5ab329371d6c8f5d2cc"}, ] [package.dependencies] zipp = ">=0.5" [package.extras] -docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-lint"] perf = ["ipython"] testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)", "pytest-ruff"] @@ -1012,13 +1029,13 @@ files = [ [[package]] name = "ipykernel" -version = "6.27.1" +version = "6.28.0" description = "IPython Kernel for Jupyter" optional = false python-versions = ">=3.8" files = [ - {file = "ipykernel-6.27.1-py3-none-any.whl", hash = "sha256:dab88b47f112f9f7df62236511023c9bdeef67abc73af7c652e4ce4441601686"}, - {file = "ipykernel-6.27.1.tar.gz", hash = "sha256:7d5d594b6690654b4d299edba5e872dc17bb7396a8d0609c97cb7b8a1c605de6"}, + {file = "ipykernel-6.28.0-py3-none-any.whl", hash = "sha256:c6e9a9c63a7f4095c0a22a79f765f079f9ec7be4f2430a898ddea889e8665661"}, + {file = "ipykernel-6.28.0.tar.gz", hash = "sha256:69c11403d26de69df02225916f916b37ea4b9af417da0a8c827f84328d88e5f3"}, ] [package.dependencies] @@ -1032,7 +1049,7 @@ matplotlib-inline = ">=0.1" nest-asyncio = "*" packaging = "*" psutil = "*" -pyzmq = ">=20" +pyzmq = ">=24" tornado = ">=6.1" traitlets = ">=5.4.0" @@ -1225,13 +1242,13 @@ format-nongpl = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339- [[package]] name = "jsonschema-specifications" -version = "2023.11.1" +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.11.1-py3-none-any.whl", hash = "sha256:f596778ab612b3fd29f72ea0d990393d0540a5aab18bf0407a46632eab540779"}, - {file = "jsonschema_specifications-2023.11.1.tar.gz", hash = "sha256:c9b234904ffe02f079bf91b14d79987faa685fd4b39c377a0996954c0090b9ca"}, + {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] @@ -1307,13 +1324,13 @@ test = ["flaky", "pexpect", "pytest"] [[package]] name = "jupyter-core" -version = "5.5.0" +version = "5.6.1" description = "Jupyter core package. A base package on which Jupyter projects rely." optional = false python-versions = ">=3.8" files = [ - {file = "jupyter_core-5.5.0-py3-none-any.whl", hash = "sha256:e11e02cd8ae0a9de5c6c44abf5727df9f2581055afe00b22183f621ba3585805"}, - {file = "jupyter_core-5.5.0.tar.gz", hash = "sha256:880b86053bf298a8724994f95e99b99130659022a4f7f45f563084b6223861d3"}, + {file = "jupyter_core-5.6.1-py3-none-any.whl", hash = "sha256:3d16aec2e1ec84b69f7794e49c32830c1d950ad149526aec954c100047c5f3a7"}, + {file = "jupyter_core-5.6.1.tar.gz", hash = "sha256:5139be639404f7f80f3db6f687f47b8a8ec97286b4fa063c984024720e7224dc"}, ] [package.dependencies] @@ -1367,13 +1384,13 @@ jupyter-server = ">=1.1.2" [[package]] name = "jupyter-server" -version = "2.11.1" +version = "2.12.1" description = "The backend—i.e. core services, APIs, and REST endpoints—to Jupyter web applications." optional = false python-versions = ">=3.8" files = [ - {file = "jupyter_server-2.11.1-py3-none-any.whl", hash = "sha256:4b3a16e3ed16fd202588890f10b8ca589bd3e29405d128beb95935f059441373"}, - {file = "jupyter_server-2.11.1.tar.gz", hash = "sha256:fe80bab96493acf5f7d6cd9a1575af8fbd253dc2591aa4d015131a1e03b5799a"}, + {file = "jupyter_server-2.12.1-py3-none-any.whl", hash = "sha256:fd030dd7be1ca572e4598203f718df6630c12bd28a599d7f1791c4d7938e1010"}, + {file = "jupyter_server-2.12.1.tar.gz", hash = "sha256:dc77b7dcc5fc0547acba2b2844f01798008667201eea27c6319ff9257d700a6d"}, ] [package.dependencies] @@ -1403,13 +1420,13 @@ test = ["flaky", "ipykernel", "pre-commit", "pytest (>=7.0)", "pytest-console-sc [[package]] name = "jupyter-server-terminals" -version = "0.4.4" +version = "0.5.1" description = "A Jupyter Server Extension Providing Terminals." optional = false python-versions = ">=3.8" files = [ - {file = "jupyter_server_terminals-0.4.4-py3-none-any.whl", hash = "sha256:75779164661cec02a8758a5311e18bb8eb70c4e86c6b699403100f1585a12a36"}, - {file = "jupyter_server_terminals-0.4.4.tar.gz", hash = "sha256:57ab779797c25a7ba68e97bcfb5d7740f2b5e8a83b5e8102b10438041a7eac5d"}, + {file = "jupyter_server_terminals-0.5.1-py3-none-any.whl", hash = "sha256:5e63e947ddd97bb2832db5ef837a258d9ccd4192cd608c1270850ad947ae5dd7"}, + {file = "jupyter_server_terminals-0.5.1.tar.gz", hash = "sha256:16d3be9cf48be6a1f943f3a6c93c033be259cf4779184c66421709cf63dccfea"}, ] [package.dependencies] @@ -1417,18 +1434,18 @@ pywinpty = {version = ">=2.0.3", markers = "os_name == \"nt\""} terminado = ">=0.8.3" [package.extras] -docs = ["jinja2", "jupyter-server", "mistune (<3.0)", "myst-parser", "nbformat", "packaging", "pydata-sphinx-theme", "sphinxcontrib-github-alt", "sphinxcontrib-openapi", "sphinxcontrib-spelling", "sphinxemoji", "tornado"] -test = ["coverage", "jupyter-server (>=2.0.0)", "pytest (>=7.0)", "pytest-cov", "pytest-jupyter[server] (>=0.5.3)", "pytest-timeout"] +docs = ["jinja2", "jupyter-server", "mistune (<4.0)", "myst-parser", "nbformat", "packaging", "pydata-sphinx-theme", "sphinxcontrib-github-alt", "sphinxcontrib-openapi", "sphinxcontrib-spelling", "sphinxemoji", "tornado"] +test = ["jupyter-server (>=2.0.0)", "pytest (>=7.0)", "pytest-jupyter[server] (>=0.5.3)", "pytest-timeout"] [[package]] name = "jupyterlab" -version = "4.0.9" +version = "4.0.10" description = "JupyterLab computational environment" optional = false python-versions = ">=3.8" files = [ - {file = "jupyterlab-4.0.9-py3-none-any.whl", hash = "sha256:9f6f8e36d543fdbcc3df961a1d6a3f524b4a4001be0327a398f68fa4e534107c"}, - {file = "jupyterlab-4.0.9.tar.gz", hash = "sha256:9ebada41d52651f623c0c9f069ddb8a21d6848e4c887d8e5ddc0613166ed5c0b"}, + {file = "jupyterlab-4.0.10-py3-none-any.whl", hash = "sha256:fe010ad9e37017488b468632ef2ead255fc7c671c5b64d9ca13e1f7b7e665c37"}, + {file = "jupyterlab-4.0.10.tar.gz", hash = "sha256:46177eb8ede70dc73be922ac99f8ef943bdc2dfbc6a31b353c4bde848a35dee1"}, ] [package.dependencies] @@ -1448,7 +1465,7 @@ tornado = ">=6.2.0" traitlets = "*" [package.extras] -dev = ["black[jupyter] (==23.10.1)", "build", "bump2version", "coverage", "hatch", "pre-commit", "pytest-cov", "ruff (==0.1.4)"] +dev = ["build", "bump2version", "coverage", "hatch", "pre-commit", "pytest-cov", "ruff (==0.1.6)"] docs = ["jsx-lexer", "myst-parser", "pydata-sphinx-theme (>=0.13.0)", "pytest", "pytest-check-links", "pytest-tornasync", "sphinx (>=1.8,<7.2.0)", "sphinx-copybutton"] docs-screenshots = ["altair (==5.0.1)", "ipython (==8.14.0)", "ipywidgets (==8.0.6)", "jupyterlab-geojson (==3.4.0)", "jupyterlab-language-pack-zh-cn (==4.0.post0)", "matplotlib (==3.7.1)", "nbconvert (>=7.0.0)", "pandas (==2.0.2)", "scipy (==1.10.1)", "vega-datasets (==0.9.0)"] test = ["coverage", "pytest (>=7.0)", "pytest-check-links (>=0.7)", "pytest-console-scripts", "pytest-cov", "pytest-jupyter (>=0.5.3)", "pytest-timeout", "pytest-tornasync", "requests", "requests-cache", "virtualenv"] @@ -1503,13 +1520,13 @@ files = [ [[package]] name = "langchain" -version = "0.0.352" +version = "0.0.353" description = "Building applications with LLMs through composability" optional = false python-versions = ">=3.8.1,<4.0" files = [ - {file = "langchain-0.0.352-py3-none-any.whl", hash = "sha256:43ab580e1223e5d7c3495b3c0cb79e2f3a0ecb52caf8126271fb10d42cede2d0"}, - {file = "langchain-0.0.352.tar.gz", hash = "sha256:8928d7b63d73af9681fe1b2a2b99b84238efef61ed537de666160fd001f41efd"}, + {file = "langchain-0.0.353-py3-none-any.whl", hash = "sha256:54cac8b74fbefacddcdf0c443619a7331d6b59fe94fa2a48a4d7da2b59cf1f63"}, + {file = "langchain-0.0.353.tar.gz", hash = "sha256:a095ea819f13a3606ced699182a8369eb2d77034ec8c913983675d6dd9a98196"}, ] [package.dependencies] @@ -1518,7 +1535,7 @@ async-timeout = {version = ">=4.0.0,<5.0.0", markers = "python_version < \"3.11\ dataclasses-json = ">=0.5.7,<0.7" jsonpatch = ">=1.33,<2.0" langchain-community = ">=0.0.2,<0.1" -langchain-core = ">=0.1,<0.2" +langchain-core = ">=0.1.4,<0.2" langsmith = ">=0.0.70,<0.1.0" numpy = ">=1,<2" pydantic = ">=1,<3" @@ -1543,13 +1560,13 @@ text-helpers = ["chardet (>=5.1.0,<6.0.0)"] [[package]] name = "langchain-community" -version = "0.0.6" +version = "0.0.7" description = "Community contributed LangChain integrations." optional = false python-versions = ">=3.8.1,<4.0" files = [ - {file = "langchain_community-0.0.6-py3-none-any.whl", hash = "sha256:13b16da0f89c328df456911ff03069e4d919f647c7dd3bfc5062525cf956ed82"}, - {file = "langchain_community-0.0.6.tar.gz", hash = "sha256:b7deb63fd8205d54b51cf8b1702de15d1da77987f8465c356b158a65adff378c"}, + {file = "langchain_community-0.0.7-py3-none-any.whl", hash = "sha256:468af187bfffe753426cc4548132824be7df9404d38ceef2f873087290d8ff0e"}, + {file = "langchain_community-0.0.7.tar.gz", hash = "sha256:cfbeb25cac7dff3c021f3c82aa243fc80f80082d6f6fdcc79daf36b1408828cc"}, ] [package.dependencies] @@ -1565,17 +1582,17 @@ tenacity = ">=8.1.0,<9.0.0" [package.extras] cli = ["typer (>=0.9.0,<0.10.0)"] -extended-testing = ["aiosqlite (>=0.19.0,<0.20.0)", "aleph-alpha-client (>=2.15.0,<3.0.0)", "anthropic (>=0.3.11,<0.4.0)", "arxiv (>=1.4,<2.0)", "assemblyai (>=0.17.0,<0.18.0)", "atlassian-python-api (>=3.36.0,<4.0.0)", "beautifulsoup4 (>=4,<5)", "bibtexparser (>=1.4.0,<2.0.0)", "cassio (>=0.1.0,<0.2.0)", "chardet (>=5.1.0,<6.0.0)", "cohere (>=4,<5)", "dashvector (>=1.0.1,<2.0.0)", "databricks-vectorsearch (>=0.21,<0.22)", "datasets (>=2.15.0,<3.0.0)", "dgml-utils (>=0.3.0,<0.4.0)", "esprima (>=4.0.1,<5.0.0)", "faiss-cpu (>=1,<2)", "feedparser (>=6.0.10,<7.0.0)", "fireworks-ai (>=0.9.0,<0.10.0)", "geopandas (>=0.13.1,<0.14.0)", "gitpython (>=3.1.32,<4.0.0)", "google-cloud-documentai (>=2.20.1,<3.0.0)", "gql (>=3.4.1,<4.0.0)", "gradientai (>=1.4.0,<2.0.0)", "hologres-vector (>=0.0.6,<0.0.7)", "html2text (>=2020.1.16,<2021.0.0)", "javelin-sdk (>=0.1.8,<0.2.0)", "jinja2 (>=3,<4)", "jq (>=1.4.1,<2.0.0)", "jsonschema (>1)", "lxml (>=4.9.2,<5.0.0)", "markdownify (>=0.11.6,<0.12.0)", "motor (>=3.3.1,<4.0.0)", "msal (>=1.25.0,<2.0.0)", "mwparserfromhell (>=0.6.4,<0.7.0)", "mwxml (>=0.3.3,<0.4.0)", "newspaper3k (>=0.2.8,<0.3.0)", "numexpr (>=2.8.6,<3.0.0)", "openai (<2)", "openapi-pydantic (>=0.3.2,<0.4.0)", "oracle-ads (>=2.9.1,<3.0.0)", "pandas (>=2.0.1,<3.0.0)", "pdfminer-six (>=20221105,<20221106)", "pgvector (>=0.1.6,<0.2.0)", "praw (>=7.7.1,<8.0.0)", "psychicapi (>=0.8.0,<0.9.0)", "py-trello (>=0.19.0,<0.20.0)", "pymupdf (>=1.22.3,<2.0.0)", "pypdf (>=3.4.0,<4.0.0)", "pypdfium2 (>=4.10.0,<5.0.0)", "pyspark (>=3.4.0,<4.0.0)", "rank-bm25 (>=0.2.2,<0.3.0)", "rapidfuzz (>=3.1.1,<4.0.0)", "rapidocr-onnxruntime (>=1.3.2,<2.0.0)", "requests-toolbelt (>=1.0.0,<2.0.0)", "rspace_client (>=2.5.0,<3.0.0)", "scikit-learn (>=1.2.2,<2.0.0)", "sqlite-vss (>=0.1.2,<0.2.0)", "streamlit (>=1.18.0,<2.0.0)", "sympy (>=1.12,<2.0)", "telethon (>=1.28.5,<2.0.0)", "timescale-vector (>=0.0.1,<0.0.2)", "tqdm (>=4.48.0)", "upstash-redis (>=0.15.0,<0.16.0)", "xata (>=1.0.0a7,<2.0.0)", "xmltodict (>=0.13.0,<0.14.0)"] +extended-testing = ["aiosqlite (>=0.19.0,<0.20.0)", "aleph-alpha-client (>=2.15.0,<3.0.0)", "anthropic (>=0.3.11,<0.4.0)", "arxiv (>=1.4,<2.0)", "assemblyai (>=0.17.0,<0.18.0)", "atlassian-python-api (>=3.36.0,<4.0.0)", "azure-ai-documentintelligence (>=1.0.0b1,<2.0.0)", "beautifulsoup4 (>=4,<5)", "bibtexparser (>=1.4.0,<2.0.0)", "cassio (>=0.1.0,<0.2.0)", "chardet (>=5.1.0,<6.0.0)", "cohere (>=4,<5)", "dashvector (>=1.0.1,<2.0.0)", "databricks-vectorsearch (>=0.21,<0.22)", "datasets (>=2.15.0,<3.0.0)", "dgml-utils (>=0.3.0,<0.4.0)", "esprima (>=4.0.1,<5.0.0)", "faiss-cpu (>=1,<2)", "feedparser (>=6.0.10,<7.0.0)", "fireworks-ai (>=0.9.0,<0.10.0)", "geopandas (>=0.13.1,<0.14.0)", "gitpython (>=3.1.32,<4.0.0)", "google-cloud-documentai (>=2.20.1,<3.0.0)", "gql (>=3.4.1,<4.0.0)", "gradientai (>=1.4.0,<2.0.0)", "hologres-vector (>=0.0.6,<0.0.7)", "html2text (>=2020.1.16,<2021.0.0)", "javelin-sdk (>=0.1.8,<0.2.0)", "jinja2 (>=3,<4)", "jq (>=1.4.1,<2.0.0)", "jsonschema (>1)", "lxml (>=4.9.2,<5.0.0)", "markdownify (>=0.11.6,<0.12.0)", "motor (>=3.3.1,<4.0.0)", "msal (>=1.25.0,<2.0.0)", "mwparserfromhell (>=0.6.4,<0.7.0)", "mwxml (>=0.3.3,<0.4.0)", "newspaper3k (>=0.2.8,<0.3.0)", "numexpr (>=2.8.6,<3.0.0)", "openai (<2)", "openapi-pydantic (>=0.3.2,<0.4.0)", "oracle-ads (>=2.9.1,<3.0.0)", "pandas (>=2.0.1,<3.0.0)", "pdfminer-six (>=20221105,<20221106)", "pgvector (>=0.1.6,<0.2.0)", "praw (>=7.7.1,<8.0.0)", "psychicapi (>=0.8.0,<0.9.0)", "py-trello (>=0.19.0,<0.20.0)", "pymupdf (>=1.22.3,<2.0.0)", "pypdf (>=3.4.0,<4.0.0)", "pypdfium2 (>=4.10.0,<5.0.0)", "pyspark (>=3.4.0,<4.0.0)", "rank-bm25 (>=0.2.2,<0.3.0)", "rapidfuzz (>=3.1.1,<4.0.0)", "rapidocr-onnxruntime (>=1.3.2,<2.0.0)", "requests-toolbelt (>=1.0.0,<2.0.0)", "rspace_client (>=2.5.0,<3.0.0)", "scikit-learn (>=1.2.2,<2.0.0)", "sqlite-vss (>=0.1.2,<0.2.0)", "streamlit (>=1.18.0,<2.0.0)", "sympy (>=1.12,<2.0)", "telethon (>=1.28.5,<2.0.0)", "timescale-vector (>=0.0.1,<0.0.2)", "tqdm (>=4.48.0)", "upstash-redis (>=0.15.0,<0.16.0)", "xata (>=1.0.0a7,<2.0.0)", "xmltodict (>=0.13.0,<0.14.0)"] [[package]] name = "langchain-core" -version = "0.1.3" +version = "0.1.4" description = "Building applications with LLMs through composability" optional = false python-versions = ">=3.8.1,<4.0" files = [ - {file = "langchain_core-0.1.3-py3-none-any.whl", hash = "sha256:bfbbc5dfeb06cfe3fd078e7a12db3a4cfb9d28b715b200a64f7abb7ae1976b17"}, - {file = "langchain_core-0.1.3.tar.gz", hash = "sha256:d8898254dfea1c4ab614f470db40909969604775f7524175f6d9167ea58050c9"}, + {file = "langchain_core-0.1.4-py3-none-any.whl", hash = "sha256:c62bd362d5abf5359436a99b29629e12a4d1ede9f1704dc958cdb8530a791efd"}, + {file = "langchain_core-0.1.4.tar.gz", hash = "sha256:f700138689c9014e23d3c29796a892dccf7f2a42901cb8817671823e1a24724c"}, ] [package.dependencies] @@ -1591,6 +1608,21 @@ tenacity = ">=8.1.0,<9.0.0" [package.extras] extended-testing = ["jinja2 (>=3,<4)"] +[[package]] +name = "langchainhub" +version = "0.1.14" +description = "" +optional = false +python-versions = ">=3.8.1,<4.0" +files = [ + {file = "langchainhub-0.1.14-py3-none-any.whl", hash = "sha256:3d58a050a3a70684bca2e049a2425a2418d199d0b14e3c8aa318123b7f18b21a"}, + {file = "langchainhub-0.1.14.tar.gz", hash = "sha256:c1aeda38d66df1146f9e60e47bde7fb12bad902eb19dba78ac02f89e0f1f1867"}, +] + +[package.dependencies] +requests = ">=2,<3" +types-requests = ">=2.31.0.2,<3.0.0.0" + [[package]] name = "langsmith" version = "0.0.75" @@ -1805,38 +1837,38 @@ files = [ [[package]] name = "mypy" -version = "1.7.1" +version = "1.8.0" description = "Optional static typing for Python" optional = false python-versions = ">=3.8" files = [ - {file = "mypy-1.7.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:12cce78e329838d70a204293e7b29af9faa3ab14899aec397798a4b41be7f340"}, - {file = "mypy-1.7.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1484b8fa2c10adf4474f016e09d7a159602f3239075c7bf9f1627f5acf40ad49"}, - {file = "mypy-1.7.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:31902408f4bf54108bbfb2e35369877c01c95adc6192958684473658c322c8a5"}, - {file = "mypy-1.7.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f2c2521a8e4d6d769e3234350ba7b65ff5d527137cdcde13ff4d99114b0c8e7d"}, - {file = "mypy-1.7.1-cp310-cp310-win_amd64.whl", hash = "sha256:fcd2572dd4519e8a6642b733cd3a8cfc1ef94bafd0c1ceed9c94fe736cb65b6a"}, - {file = "mypy-1.7.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4b901927f16224d0d143b925ce9a4e6b3a758010673eeded9b748f250cf4e8f7"}, - {file = "mypy-1.7.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2f7f6985d05a4e3ce8255396df363046c28bea790e40617654e91ed580ca7c51"}, - {file = "mypy-1.7.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:944bdc21ebd620eafefc090cdf83158393ec2b1391578359776c00de00e8907a"}, - {file = "mypy-1.7.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9c7ac372232c928fff0645d85f273a726970c014749b924ce5710d7d89763a28"}, - {file = "mypy-1.7.1-cp311-cp311-win_amd64.whl", hash = "sha256:f6efc9bd72258f89a3816e3a98c09d36f079c223aa345c659622f056b760ab42"}, - {file = "mypy-1.7.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:6dbdec441c60699288adf051f51a5d512b0d818526d1dcfff5a41f8cd8b4aaf1"}, - {file = "mypy-1.7.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4fc3d14ee80cd22367caaaf6e014494415bf440980a3045bf5045b525680ac33"}, - {file = "mypy-1.7.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2c6e4464ed5f01dc44dc9821caf67b60a4e5c3b04278286a85c067010653a0eb"}, - {file = "mypy-1.7.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:d9b338c19fa2412f76e17525c1b4f2c687a55b156320acb588df79f2e6fa9fea"}, - {file = "mypy-1.7.1-cp312-cp312-win_amd64.whl", hash = "sha256:204e0d6de5fd2317394a4eff62065614c4892d5a4d1a7ee55b765d7a3d9e3f82"}, - {file = "mypy-1.7.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:84860e06ba363d9c0eeabd45ac0fde4b903ad7aa4f93cd8b648385a888e23200"}, - {file = "mypy-1.7.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:8c5091ebd294f7628eb25ea554852a52058ac81472c921150e3a61cdd68f75a7"}, - {file = "mypy-1.7.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40716d1f821b89838589e5b3106ebbc23636ffdef5abc31f7cd0266db936067e"}, - {file = "mypy-1.7.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:5cf3f0c5ac72139797953bd50bc6c95ac13075e62dbfcc923571180bebb662e9"}, - {file = "mypy-1.7.1-cp38-cp38-win_amd64.whl", hash = "sha256:78e25b2fd6cbb55ddfb8058417df193f0129cad5f4ee75d1502248e588d9e0d7"}, - {file = "mypy-1.7.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:75c4d2a6effd015786c87774e04331b6da863fc3fc4e8adfc3b40aa55ab516fe"}, - {file = "mypy-1.7.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2643d145af5292ee956aa0a83c2ce1038a3bdb26e033dadeb2f7066fb0c9abce"}, - {file = "mypy-1.7.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75aa828610b67462ffe3057d4d8a4112105ed211596b750b53cbfe182f44777a"}, - {file = "mypy-1.7.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ee5d62d28b854eb61889cde4e1dbc10fbaa5560cb39780c3995f6737f7e82120"}, - {file = "mypy-1.7.1-cp39-cp39-win_amd64.whl", hash = "sha256:72cf32ce7dd3562373f78bd751f73c96cfb441de147cc2448a92c1a308bd0ca6"}, - {file = "mypy-1.7.1-py3-none-any.whl", hash = "sha256:f7c5d642db47376a0cc130f0de6d055056e010debdaf0707cd2b0fc7e7ef30ea"}, - {file = "mypy-1.7.1.tar.gz", hash = "sha256:fcb6d9afb1b6208b4c712af0dafdc650f518836065df0d4fb1d800f5d6773db2"}, + {file = "mypy-1.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:485a8942f671120f76afffff70f259e1cd0f0cfe08f81c05d8816d958d4577d3"}, + {file = "mypy-1.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:df9824ac11deaf007443e7ed2a4a26bebff98d2bc43c6da21b2b64185da011c4"}, + {file = "mypy-1.8.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2afecd6354bbfb6e0160f4e4ad9ba6e4e003b767dd80d85516e71f2e955ab50d"}, + {file = "mypy-1.8.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8963b83d53ee733a6e4196954502b33567ad07dfd74851f32be18eb932fb1cb9"}, + {file = "mypy-1.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:e46f44b54ebddbeedbd3d5b289a893219065ef805d95094d16a0af6630f5d410"}, + {file = "mypy-1.8.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:855fe27b80375e5c5878492f0729540db47b186509c98dae341254c8f45f42ae"}, + {file = "mypy-1.8.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4c886c6cce2d070bd7df4ec4a05a13ee20c0aa60cb587e8d1265b6c03cf91da3"}, + {file = "mypy-1.8.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d19c413b3c07cbecf1f991e2221746b0d2a9410b59cb3f4fb9557f0365a1a817"}, + {file = "mypy-1.8.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9261ed810972061388918c83c3f5cd46079d875026ba97380f3e3978a72f503d"}, + {file = "mypy-1.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:51720c776d148bad2372ca21ca29256ed483aa9a4cdefefcef49006dff2a6835"}, + {file = "mypy-1.8.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:52825b01f5c4c1c4eb0db253ec09c7aa17e1a7304d247c48b6f3599ef40db8bd"}, + {file = "mypy-1.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f5ac9a4eeb1ec0f1ccdc6f326bcdb464de5f80eb07fb38b5ddd7b0de6bc61e55"}, + {file = "mypy-1.8.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afe3fe972c645b4632c563d3f3eff1cdca2fa058f730df2b93a35e3b0c538218"}, + {file = "mypy-1.8.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:42c6680d256ab35637ef88891c6bd02514ccb7e1122133ac96055ff458f93fc3"}, + {file = "mypy-1.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:720a5ca70e136b675af3af63db533c1c8c9181314d207568bbe79051f122669e"}, + {file = "mypy-1.8.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:028cf9f2cae89e202d7b6593cd98db6759379f17a319b5faf4f9978d7084cdc6"}, + {file = "mypy-1.8.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4e6d97288757e1ddba10dd9549ac27982e3e74a49d8d0179fc14d4365c7add66"}, + {file = "mypy-1.8.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f1478736fcebb90f97e40aff11a5f253af890c845ee0c850fe80aa060a267c6"}, + {file = "mypy-1.8.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:42419861b43e6962a649068a61f4a4839205a3ef525b858377a960b9e2de6e0d"}, + {file = "mypy-1.8.0-cp38-cp38-win_amd64.whl", hash = "sha256:2b5b6c721bd4aabaadead3a5e6fa85c11c6c795e0c81a7215776ef8afc66de02"}, + {file = "mypy-1.8.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5c1538c38584029352878a0466f03a8ee7547d7bd9f641f57a0f3017a7c905b8"}, + {file = "mypy-1.8.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4ef4be7baf08a203170f29e89d79064463b7fc7a0908b9d0d5114e8009c3a259"}, + {file = "mypy-1.8.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7178def594014aa6c35a8ff411cf37d682f428b3b5617ca79029d8ae72f5402b"}, + {file = "mypy-1.8.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ab3c84fa13c04aeeeabb2a7f67a25ef5d77ac9d6486ff33ded762ef353aa5592"}, + {file = "mypy-1.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:99b00bc72855812a60d253420d8a2eae839b0afa4938f09f4d2aa9bb4654263a"}, + {file = "mypy-1.8.0-py3-none-any.whl", hash = "sha256:538fd81bb5e430cc1381a443971c0475582ff9f434c16cd46d2c66763ce85d9d"}, + {file = "mypy-1.8.0.tar.gz", hash = "sha256:6ff8b244d7085a0b425b56d327b480c3b29cafbd2eff27316a004f9a7391ae07"}, ] [package.dependencies] @@ -1885,13 +1917,13 @@ test = ["flaky", "ipykernel (>=6.19.3)", "ipython", "ipywidgets", "nbconvert (>= [[package]] name = "nbconvert" -version = "7.11.0" +version = "7.14.0" description = "Converting Jupyter Notebooks" optional = false python-versions = ">=3.8" files = [ - {file = "nbconvert-7.11.0-py3-none-any.whl", hash = "sha256:d1d417b7f34a4e38887f8da5bdfd12372adf3b80f995d57556cb0972c68909fe"}, - {file = "nbconvert-7.11.0.tar.gz", hash = "sha256:abedc01cf543177ffde0bfc2a69726d5a478f6af10a332fc1bf29fcb4f0cf000"}, + {file = "nbconvert-7.14.0-py3-none-any.whl", hash = "sha256:483dde47facdaa4875903d651305ad53cd76e2255ae3c61efe412a95f2d22a24"}, + {file = "nbconvert-7.14.0.tar.gz", hash = "sha256:92b9a44b63e5a7fb4f6fa0ef41261e35c16925046ccd1c04a5c8099bf100476e"}, ] [package.dependencies] @@ -1918,7 +1950,7 @@ docs = ["ipykernel", "ipython", "myst-parser", "nbsphinx (>=0.2.12)", "pydata-sp qtpdf = ["nbconvert[qtpng]"] qtpng = ["pyqtwebengine (>=5.15)"] serve = ["tornado (>=6.1)"] -test = ["flaky", "ipykernel", "ipywidgets (>=7)", "pytest"] +test = ["flaky", "ipykernel", "ipywidgets (>=7.5)", "pytest"] webpdf = ["playwright"] [[package]] @@ -2138,13 +2170,13 @@ files = [ [[package]] name = "platformdirs" -version = "4.0.0" +version = "4.1.0" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "platformdirs-4.0.0-py3-none-any.whl", hash = "sha256:118c954d7e949b35437270383a3f2531e99dd93cf7ce4dc8340d3356d30f173b"}, - {file = "platformdirs-4.0.0.tar.gz", hash = "sha256:cb633b2bcf10c51af60beb0ab06d2f1d69064b43abf4c185ca6b28865f3f9731"}, + {file = "platformdirs-4.1.0-py3-none-any.whl", hash = "sha256:11c8f37bcca40db96d8144522d925583bdb7a31f7b0e37e3ed4318400a8e2380"}, + {file = "platformdirs-4.1.0.tar.gz", hash = "sha256:906d548203468492d432bcb294d4bc2fff751bf84971fbb2c10918cc206ee420"}, ] [package.extras] @@ -2182,13 +2214,13 @@ twisted = ["twisted"] [[package]] name = "prompt-toolkit" -version = "3.0.41" +version = "3.0.43" description = "Library for building powerful interactive command lines in Python" optional = false python-versions = ">=3.7.0" files = [ - {file = "prompt_toolkit-3.0.41-py3-none-any.whl", hash = "sha256:f36fe301fafb7470e86aaf90f036eef600a3210be4decf461a5b1ca8403d3cb2"}, - {file = "prompt_toolkit-3.0.41.tar.gz", hash = "sha256:941367d97fc815548822aa26c2a269fdc4eb21e9ec05fc5d447cf09bad5d75f0"}, + {file = "prompt_toolkit-3.0.43-py3-none-any.whl", hash = "sha256:a11a29cb3bf0a28a387fe5122cdb649816a957cd9261dcedf8c9f1fef33eacf6"}, + {file = "prompt_toolkit-3.0.43.tar.gz", hash = "sha256:3527b7af26106cbc65a040bcc84839a3566ec1b051bb0bfe953631e704b0ff7d"}, ] [package.dependencies] @@ -2196,27 +2228,27 @@ wcwidth = "*" [[package]] name = "psutil" -version = "5.9.6" +version = "5.9.7" description = "Cross-platform lib for process and system monitoring in Python." optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" files = [ - {file = "psutil-5.9.6-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:fb8a697f11b0f5994550555fcfe3e69799e5b060c8ecf9e2f75c69302cc35c0d"}, - {file = "psutil-5.9.6-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:91ecd2d9c00db9817a4b4192107cf6954addb5d9d67a969a4f436dbc9200f88c"}, - {file = "psutil-5.9.6-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:10e8c17b4f898d64b121149afb136c53ea8b68c7531155147867b7b1ac9e7e28"}, - {file = "psutil-5.9.6-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:18cd22c5db486f33998f37e2bb054cc62fd06646995285e02a51b1e08da97017"}, - {file = "psutil-5.9.6-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:ca2780f5e038379e520281e4c032dddd086906ddff9ef0d1b9dcf00710e5071c"}, - {file = "psutil-5.9.6-cp27-none-win32.whl", hash = "sha256:70cb3beb98bc3fd5ac9ac617a327af7e7f826373ee64c80efd4eb2856e5051e9"}, - {file = "psutil-5.9.6-cp27-none-win_amd64.whl", hash = "sha256:51dc3d54607c73148f63732c727856f5febec1c7c336f8f41fcbd6315cce76ac"}, - {file = "psutil-5.9.6-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:c69596f9fc2f8acd574a12d5f8b7b1ba3765a641ea5d60fb4736bf3c08a8214a"}, - {file = "psutil-5.9.6-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:92e0cc43c524834af53e9d3369245e6cc3b130e78e26100d1f63cdb0abeb3d3c"}, - {file = "psutil-5.9.6-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:748c9dd2583ed86347ed65d0035f45fa8c851e8d90354c122ab72319b5f366f4"}, - {file = "psutil-5.9.6-cp36-cp36m-win32.whl", hash = "sha256:3ebf2158c16cc69db777e3c7decb3c0f43a7af94a60d72e87b2823aebac3d602"}, - {file = "psutil-5.9.6-cp36-cp36m-win_amd64.whl", hash = "sha256:ff18b8d1a784b810df0b0fff3bcb50ab941c3b8e2c8de5726f9c71c601c611aa"}, - {file = "psutil-5.9.6-cp37-abi3-win32.whl", hash = "sha256:a6f01f03bf1843280f4ad16f4bde26b817847b4c1a0db59bf6419807bc5ce05c"}, - {file = "psutil-5.9.6-cp37-abi3-win_amd64.whl", hash = "sha256:6e5fb8dc711a514da83098bc5234264e551ad980cec5f85dabf4d38ed6f15e9a"}, - {file = "psutil-5.9.6-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:daecbcbd29b289aac14ece28eca6a3e60aa361754cf6da3dfb20d4d32b6c7f57"}, - {file = "psutil-5.9.6.tar.gz", hash = "sha256:e4b92ddcd7dd4cdd3f900180ea1e104932c7bce234fb88976e2a3b296441225a"}, + {file = "psutil-5.9.7-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:0bd41bf2d1463dfa535942b2a8f0e958acf6607ac0be52265ab31f7923bcd5e6"}, + {file = "psutil-5.9.7-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:5794944462509e49d4d458f4dbfb92c47539e7d8d15c796f141f474010084056"}, + {file = "psutil-5.9.7-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:fe361f743cb3389b8efda21980d93eb55c1f1e3898269bc9a2a1d0bb7b1f6508"}, + {file = "psutil-5.9.7-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:e469990e28f1ad738f65a42dcfc17adaed9d0f325d55047593cb9033a0ab63df"}, + {file = "psutil-5.9.7-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:3c4747a3e2ead1589e647e64aad601981f01b68f9398ddf94d01e3dc0d1e57c7"}, + {file = "psutil-5.9.7-cp27-none-win32.whl", hash = "sha256:1d4bc4a0148fdd7fd8f38e0498639ae128e64538faa507df25a20f8f7fb2341c"}, + {file = "psutil-5.9.7-cp27-none-win_amd64.whl", hash = "sha256:4c03362e280d06bbbfcd52f29acd79c733e0af33d707c54255d21029b8b32ba6"}, + {file = "psutil-5.9.7-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:ea36cc62e69a13ec52b2f625c27527f6e4479bca2b340b7a452af55b34fcbe2e"}, + {file = "psutil-5.9.7-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1132704b876e58d277168cd729d64750633d5ff0183acf5b3c986b8466cd0284"}, + {file = "psutil-5.9.7-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fe8b7f07948f1304497ce4f4684881250cd859b16d06a1dc4d7941eeb6233bfe"}, + {file = "psutil-5.9.7-cp36-cp36m-win32.whl", hash = "sha256:b27f8fdb190c8c03914f908a4555159327d7481dac2f01008d483137ef3311a9"}, + {file = "psutil-5.9.7-cp36-cp36m-win_amd64.whl", hash = "sha256:44969859757f4d8f2a9bd5b76eba8c3099a2c8cf3992ff62144061e39ba8568e"}, + {file = "psutil-5.9.7-cp37-abi3-win32.whl", hash = "sha256:c727ca5a9b2dd5193b8644b9f0c883d54f1248310023b5ad3e92036c5e2ada68"}, + {file = "psutil-5.9.7-cp37-abi3-win_amd64.whl", hash = "sha256:f37f87e4d73b79e6c5e749440c3113b81d1ee7d26f21c19c47371ddea834f414"}, + {file = "psutil-5.9.7-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:032f4f2c909818c86cea4fe2cc407f1c0f0cde8e6c6d702b28b8ce0c0d143340"}, + {file = "psutil-5.9.7.tar.gz", hash = "sha256:3f02134e82cfb5d089fddf20bb2e03fd5cd52395321d1c8458a9e58500ff417c"}, ] [package.extras] @@ -2260,18 +2292,18 @@ files = [ [[package]] name = "pydantic" -version = "2.5.2" +version = "2.5.3" description = "Data validation using Python type hints" optional = false python-versions = ">=3.7" files = [ - {file = "pydantic-2.5.2-py3-none-any.whl", hash = "sha256:80c50fb8e3dcecfddae1adbcc00ec5822918490c99ab31f6cf6140ca1c1429f0"}, - {file = "pydantic-2.5.2.tar.gz", hash = "sha256:ff177ba64c6faf73d7afa2e8cad38fd456c0dbe01c9954e71038001cd15a6edd"}, + {file = "pydantic-2.5.3-py3-none-any.whl", hash = "sha256:d0caf5954bee831b6bfe7e338c32b9e30c85dfe080c843680783ac2b631673b4"}, + {file = "pydantic-2.5.3.tar.gz", hash = "sha256:b3ef57c62535b0941697cce638c08900d87fcb67e29cfa99e8a68f747f393f7a"}, ] [package.dependencies] annotated-types = ">=0.4.0" -pydantic-core = "2.14.5" +pydantic-core = "2.14.6" typing-extensions = ">=4.6.1" [package.extras] @@ -2279,116 +2311,116 @@ email = ["email-validator (>=2.0.0)"] [[package]] name = "pydantic-core" -version = "2.14.5" +version = "2.14.6" description = "" optional = false python-versions = ">=3.7" files = [ - {file = "pydantic_core-2.14.5-cp310-cp310-macosx_10_7_x86_64.whl", hash = "sha256:7e88f5696153dc516ba6e79f82cc4747e87027205f0e02390c21f7cb3bd8abfd"}, - {file = "pydantic_core-2.14.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4641e8ad4efb697f38a9b64ca0523b557c7931c5f84e0fd377a9a3b05121f0de"}, - {file = "pydantic_core-2.14.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:774de879d212db5ce02dfbf5b0da9a0ea386aeba12b0b95674a4ce0593df3d07"}, - {file = "pydantic_core-2.14.5-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ebb4e035e28f49b6f1a7032920bb9a0c064aedbbabe52c543343d39341a5b2a3"}, - {file = "pydantic_core-2.14.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b53e9ad053cd064f7e473a5f29b37fc4cc9dc6d35f341e6afc0155ea257fc911"}, - {file = "pydantic_core-2.14.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8aa1768c151cf562a9992462239dfc356b3d1037cc5a3ac829bb7f3bda7cc1f9"}, - {file = "pydantic_core-2.14.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eac5c82fc632c599f4639a5886f96867ffced74458c7db61bc9a66ccb8ee3113"}, - {file = "pydantic_core-2.14.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d2ae91f50ccc5810b2f1b6b858257c9ad2e08da70bf890dee02de1775a387c66"}, - {file = "pydantic_core-2.14.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:6b9ff467ffbab9110e80e8c8de3bcfce8e8b0fd5661ac44a09ae5901668ba997"}, - {file = "pydantic_core-2.14.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:61ea96a78378e3bd5a0be99b0e5ed00057b71f66115f5404d0dae4819f495093"}, - {file = "pydantic_core-2.14.5-cp310-none-win32.whl", hash = "sha256:bb4c2eda937a5e74c38a41b33d8c77220380a388d689bcdb9b187cf6224c9720"}, - {file = "pydantic_core-2.14.5-cp310-none-win_amd64.whl", hash = "sha256:b7851992faf25eac90bfcb7bfd19e1f5ffa00afd57daec8a0042e63c74a4551b"}, - {file = "pydantic_core-2.14.5-cp311-cp311-macosx_10_7_x86_64.whl", hash = "sha256:4e40f2bd0d57dac3feb3a3aed50f17d83436c9e6b09b16af271b6230a2915459"}, - {file = "pydantic_core-2.14.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ab1cdb0f14dc161ebc268c09db04d2c9e6f70027f3b42446fa11c153521c0e88"}, - {file = "pydantic_core-2.14.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aae7ea3a1c5bb40c93cad361b3e869b180ac174656120c42b9fadebf685d121b"}, - {file = "pydantic_core-2.14.5-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:60b7607753ba62cf0739177913b858140f11b8af72f22860c28eabb2f0a61937"}, - {file = "pydantic_core-2.14.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2248485b0322c75aee7565d95ad0e16f1c67403a470d02f94da7344184be770f"}, - {file = "pydantic_core-2.14.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:823fcc638f67035137a5cd3f1584a4542d35a951c3cc68c6ead1df7dac825c26"}, - {file = "pydantic_core-2.14.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:96581cfefa9123accc465a5fd0cc833ac4d75d55cc30b633b402e00e7ced00a6"}, - {file = "pydantic_core-2.14.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a33324437018bf6ba1bb0f921788788641439e0ed654b233285b9c69704c27b4"}, - {file = "pydantic_core-2.14.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:9bd18fee0923ca10f9a3ff67d4851c9d3e22b7bc63d1eddc12f439f436f2aada"}, - {file = "pydantic_core-2.14.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:853a2295c00f1d4429db4c0fb9475958543ee80cfd310814b5c0ef502de24dda"}, - {file = "pydantic_core-2.14.5-cp311-none-win32.whl", hash = "sha256:cb774298da62aea5c80a89bd58c40205ab4c2abf4834453b5de207d59d2e1651"}, - {file = "pydantic_core-2.14.5-cp311-none-win_amd64.whl", hash = "sha256:e87fc540c6cac7f29ede02e0f989d4233f88ad439c5cdee56f693cc9c1c78077"}, - {file = "pydantic_core-2.14.5-cp311-none-win_arm64.whl", hash = "sha256:57d52fa717ff445cb0a5ab5237db502e6be50809b43a596fb569630c665abddf"}, - {file = "pydantic_core-2.14.5-cp312-cp312-macosx_10_7_x86_64.whl", hash = "sha256:e60f112ac88db9261ad3a52032ea46388378034f3279c643499edb982536a093"}, - {file = "pydantic_core-2.14.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6e227c40c02fd873c2a73a98c1280c10315cbebe26734c196ef4514776120aeb"}, - {file = "pydantic_core-2.14.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f0cbc7fff06a90bbd875cc201f94ef0ee3929dfbd5c55a06674b60857b8b85ed"}, - {file = "pydantic_core-2.14.5-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:103ef8d5b58596a731b690112819501ba1db7a36f4ee99f7892c40da02c3e189"}, - {file = "pydantic_core-2.14.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c949f04ecad823f81b1ba94e7d189d9dfb81edbb94ed3f8acfce41e682e48cef"}, - {file = "pydantic_core-2.14.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c1452a1acdf914d194159439eb21e56b89aa903f2e1c65c60b9d874f9b950e5d"}, - {file = "pydantic_core-2.14.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cb4679d4c2b089e5ef89756bc73e1926745e995d76e11925e3e96a76d5fa51fc"}, - {file = "pydantic_core-2.14.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cf9d3fe53b1ee360e2421be95e62ca9b3296bf3f2fb2d3b83ca49ad3f925835e"}, - {file = "pydantic_core-2.14.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:70f4b4851dbb500129681d04cc955be2a90b2248d69273a787dda120d5cf1f69"}, - {file = "pydantic_core-2.14.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:59986de5710ad9613ff61dd9b02bdd2f615f1a7052304b79cc8fa2eb4e336d2d"}, - {file = "pydantic_core-2.14.5-cp312-none-win32.whl", hash = "sha256:699156034181e2ce106c89ddb4b6504c30db8caa86e0c30de47b3e0654543260"}, - {file = "pydantic_core-2.14.5-cp312-none-win_amd64.whl", hash = "sha256:5baab5455c7a538ac7e8bf1feec4278a66436197592a9bed538160a2e7d11e36"}, - {file = "pydantic_core-2.14.5-cp312-none-win_arm64.whl", hash = "sha256:e47e9a08bcc04d20975b6434cc50bf82665fbc751bcce739d04a3120428f3e27"}, - {file = "pydantic_core-2.14.5-cp37-cp37m-macosx_10_7_x86_64.whl", hash = "sha256:af36f36538418f3806048f3b242a1777e2540ff9efaa667c27da63d2749dbce0"}, - {file = "pydantic_core-2.14.5-cp37-cp37m-macosx_11_0_arm64.whl", hash = "sha256:45e95333b8418ded64745f14574aa9bfc212cb4fbeed7a687b0c6e53b5e188cd"}, - {file = "pydantic_core-2.14.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e47a76848f92529879ecfc417ff88a2806438f57be4a6a8bf2961e8f9ca9ec7"}, - {file = "pydantic_core-2.14.5-cp37-cp37m-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d81e6987b27bc7d101c8597e1cd2bcaa2fee5e8e0f356735c7ed34368c471550"}, - {file = "pydantic_core-2.14.5-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:34708cc82c330e303f4ce87758828ef6e457681b58ce0e921b6e97937dd1e2a3"}, - {file = "pydantic_core-2.14.5-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:652c1988019752138b974c28f43751528116bcceadad85f33a258869e641d753"}, - {file = "pydantic_core-2.14.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e4d090e73e0725b2904fdbdd8d73b8802ddd691ef9254577b708d413bf3006e"}, - {file = "pydantic_core-2.14.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5c7d5b5005f177764e96bd584d7bf28d6e26e96f2a541fdddb934c486e36fd59"}, - {file = "pydantic_core-2.14.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:a71891847f0a73b1b9eb86d089baee301477abef45f7eaf303495cd1473613e4"}, - {file = "pydantic_core-2.14.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:a717aef6971208f0851a2420b075338e33083111d92041157bbe0e2713b37325"}, - {file = "pydantic_core-2.14.5-cp37-none-win32.whl", hash = "sha256:de790a3b5aa2124b8b78ae5faa033937a72da8efe74b9231698b5a1dd9be3405"}, - {file = "pydantic_core-2.14.5-cp37-none-win_amd64.whl", hash = "sha256:6c327e9cd849b564b234da821236e6bcbe4f359a42ee05050dc79d8ed2a91588"}, - {file = "pydantic_core-2.14.5-cp38-cp38-macosx_10_7_x86_64.whl", hash = "sha256:ef98ca7d5995a82f43ec0ab39c4caf6a9b994cb0b53648ff61716370eadc43cf"}, - {file = "pydantic_core-2.14.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c6eae413494a1c3f89055da7a5515f32e05ebc1a234c27674a6956755fb2236f"}, - {file = "pydantic_core-2.14.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dcf4e6d85614f7a4956c2de5a56531f44efb973d2fe4a444d7251df5d5c4dcfd"}, - {file = "pydantic_core-2.14.5-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6637560562134b0e17de333d18e69e312e0458ee4455bdad12c37100b7cad706"}, - {file = "pydantic_core-2.14.5-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:77fa384d8e118b3077cccfcaf91bf83c31fe4dc850b5e6ee3dc14dc3d61bdba1"}, - {file = "pydantic_core-2.14.5-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:16e29bad40bcf97aac682a58861249ca9dcc57c3f6be22f506501833ddb8939c"}, - {file = "pydantic_core-2.14.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:531f4b4252fac6ca476fbe0e6f60f16f5b65d3e6b583bc4d87645e4e5ddde331"}, - {file = "pydantic_core-2.14.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:074f3d86f081ce61414d2dc44901f4f83617329c6f3ab49d2bc6c96948b2c26b"}, - {file = "pydantic_core-2.14.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:c2adbe22ab4babbca99c75c5d07aaf74f43c3195384ec07ccbd2f9e3bddaecec"}, - {file = "pydantic_core-2.14.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:0f6116a558fd06d1b7c2902d1c4cf64a5bd49d67c3540e61eccca93f41418124"}, - {file = "pydantic_core-2.14.5-cp38-none-win32.whl", hash = "sha256:fe0a5a1025eb797752136ac8b4fa21aa891e3d74fd340f864ff982d649691867"}, - {file = "pydantic_core-2.14.5-cp38-none-win_amd64.whl", hash = "sha256:079206491c435b60778cf2b0ee5fd645e61ffd6e70c47806c9ed51fc75af078d"}, - {file = "pydantic_core-2.14.5-cp39-cp39-macosx_10_7_x86_64.whl", hash = "sha256:a6a16f4a527aae4f49c875da3cdc9508ac7eef26e7977952608610104244e1b7"}, - {file = "pydantic_core-2.14.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:abf058be9517dc877227ec3223f0300034bd0e9f53aebd63cf4456c8cb1e0863"}, - {file = "pydantic_core-2.14.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:49b08aae5013640a3bfa25a8eebbd95638ec3f4b2eaf6ed82cf0c7047133f03b"}, - {file = "pydantic_core-2.14.5-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c2d97e906b4ff36eb464d52a3bc7d720bd6261f64bc4bcdbcd2c557c02081ed2"}, - {file = "pydantic_core-2.14.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3128e0bbc8c091ec4375a1828d6118bc20404883169ac95ffa8d983b293611e6"}, - {file = "pydantic_core-2.14.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:88e74ab0cdd84ad0614e2750f903bb0d610cc8af2cc17f72c28163acfcf372a4"}, - {file = "pydantic_core-2.14.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c339dabd8ee15f8259ee0f202679b6324926e5bc9e9a40bf981ce77c038553db"}, - {file = "pydantic_core-2.14.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3387277f1bf659caf1724e1afe8ee7dbc9952a82d90f858ebb931880216ea955"}, - {file = "pydantic_core-2.14.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ba6b6b3846cfc10fdb4c971980a954e49d447cd215ed5a77ec8190bc93dd7bc5"}, - {file = "pydantic_core-2.14.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ca61d858e4107ce5e1330a74724fe757fc7135190eb5ce5c9d0191729f033209"}, - {file = "pydantic_core-2.14.5-cp39-none-win32.whl", hash = "sha256:ec1e72d6412f7126eb7b2e3bfca42b15e6e389e1bc88ea0069d0cc1742f477c6"}, - {file = "pydantic_core-2.14.5-cp39-none-win_amd64.whl", hash = "sha256:c0b97ec434041827935044bbbe52b03d6018c2897349670ff8fe11ed24d1d4ab"}, - {file = "pydantic_core-2.14.5-pp310-pypy310_pp73-macosx_10_7_x86_64.whl", hash = "sha256:79e0a2cdbdc7af3f4aee3210b1172ab53d7ddb6a2d8c24119b5706e622b346d0"}, - {file = "pydantic_core-2.14.5-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:678265f7b14e138d9a541ddabbe033012a2953315739f8cfa6d754cc8063e8ca"}, - {file = "pydantic_core-2.14.5-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:95b15e855ae44f0c6341ceb74df61b606e11f1087e87dcb7482377374aac6abe"}, - {file = "pydantic_core-2.14.5-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:09b0e985fbaf13e6b06a56d21694d12ebca6ce5414b9211edf6f17738d82b0f8"}, - {file = "pydantic_core-2.14.5-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3ad873900297bb36e4b6b3f7029d88ff9829ecdc15d5cf20161775ce12306f8a"}, - {file = "pydantic_core-2.14.5-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:2d0ae0d8670164e10accbeb31d5ad45adb71292032d0fdb9079912907f0085f4"}, - {file = "pydantic_core-2.14.5-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:d37f8ec982ead9ba0a22a996129594938138a1503237b87318392a48882d50b7"}, - {file = "pydantic_core-2.14.5-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:35613015f0ba7e14c29ac6c2483a657ec740e5ac5758d993fdd5870b07a61d8b"}, - {file = "pydantic_core-2.14.5-pp37-pypy37_pp73-macosx_10_7_x86_64.whl", hash = "sha256:ab4ea451082e684198636565224bbb179575efc1658c48281b2c866bfd4ddf04"}, - {file = "pydantic_core-2.14.5-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4ce601907e99ea5b4adb807ded3570ea62186b17f88e271569144e8cca4409c7"}, - {file = "pydantic_core-2.14.5-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fb2ed8b3fe4bf4506d6dab3b93b83bbc22237e230cba03866d561c3577517d18"}, - {file = "pydantic_core-2.14.5-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:70f947628e074bb2526ba1b151cee10e4c3b9670af4dbb4d73bc8a89445916b5"}, - {file = "pydantic_core-2.14.5-pp37-pypy37_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:4bc536201426451f06f044dfbf341c09f540b4ebdb9fd8d2c6164d733de5e634"}, - {file = "pydantic_core-2.14.5-pp37-pypy37_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f4791cf0f8c3104ac668797d8c514afb3431bc3305f5638add0ba1a5a37e0d88"}, - {file = "pydantic_core-2.14.5-pp38-pypy38_pp73-macosx_10_7_x86_64.whl", hash = "sha256:038c9f763e650712b899f983076ce783175397c848da04985658e7628cbe873b"}, - {file = "pydantic_core-2.14.5-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:27548e16c79702f1e03f5628589c6057c9ae17c95b4c449de3c66b589ead0520"}, - {file = "pydantic_core-2.14.5-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c97bee68898f3f4344eb02fec316db93d9700fb1e6a5b760ffa20d71d9a46ce3"}, - {file = "pydantic_core-2.14.5-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b9b759b77f5337b4ea024f03abc6464c9f35d9718de01cfe6bae9f2e139c397e"}, - {file = "pydantic_core-2.14.5-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:439c9afe34638ace43a49bf72d201e0ffc1a800295bed8420c2a9ca8d5e3dbb3"}, - {file = "pydantic_core-2.14.5-pp38-pypy38_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:ba39688799094c75ea8a16a6b544eb57b5b0f3328697084f3f2790892510d144"}, - {file = "pydantic_core-2.14.5-pp38-pypy38_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:ccd4d5702bb90b84df13bd491be8d900b92016c5a455b7e14630ad7449eb03f8"}, - {file = "pydantic_core-2.14.5-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:81982d78a45d1e5396819bbb4ece1fadfe5f079335dd28c4ab3427cd95389944"}, - {file = "pydantic_core-2.14.5-pp39-pypy39_pp73-macosx_10_7_x86_64.whl", hash = "sha256:7f8210297b04e53bc3da35db08b7302a6a1f4889c79173af69b72ec9754796b8"}, - {file = "pydantic_core-2.14.5-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:8c8a8812fe6f43a3a5b054af6ac2d7b8605c7bcab2804a8a7d68b53f3cd86e00"}, - {file = "pydantic_core-2.14.5-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:206ed23aecd67c71daf5c02c3cd19c0501b01ef3cbf7782db9e4e051426b3d0d"}, - {file = "pydantic_core-2.14.5-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c2027d05c8aebe61d898d4cffd774840a9cb82ed356ba47a90d99ad768f39789"}, - {file = "pydantic_core-2.14.5-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:40180930807ce806aa71eda5a5a5447abb6b6a3c0b4b3b1b1962651906484d68"}, - {file = "pydantic_core-2.14.5-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:615a0a4bff11c45eb3c1996ceed5bdaa2f7b432425253a7c2eed33bb86d80abc"}, - {file = "pydantic_core-2.14.5-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f5e412d717366e0677ef767eac93566582518fe8be923361a5c204c1a62eaafe"}, - {file = "pydantic_core-2.14.5-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:513b07e99c0a267b1d954243845d8a833758a6726a3b5d8948306e3fe14675e3"}, - {file = "pydantic_core-2.14.5.tar.gz", hash = "sha256:6d30226dfc816dd0fdf120cae611dd2215117e4f9b124af8c60ab9093b6e8e71"}, + {file = "pydantic_core-2.14.6-cp310-cp310-macosx_10_7_x86_64.whl", hash = "sha256:72f9a942d739f09cd42fffe5dc759928217649f070056f03c70df14f5770acf9"}, + {file = "pydantic_core-2.14.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6a31d98c0d69776c2576dda4b77b8e0c69ad08e8b539c25c7d0ca0dc19a50d6c"}, + {file = "pydantic_core-2.14.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5aa90562bc079c6c290f0512b21768967f9968e4cfea84ea4ff5af5d917016e4"}, + {file = "pydantic_core-2.14.6-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:370ffecb5316ed23b667d99ce4debe53ea664b99cc37bfa2af47bc769056d534"}, + {file = "pydantic_core-2.14.6-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f85f3843bdb1fe80e8c206fe6eed7a1caeae897e496542cee499c374a85c6e08"}, + {file = "pydantic_core-2.14.6-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9862bf828112e19685b76ca499b379338fd4c5c269d897e218b2ae8fcb80139d"}, + {file = "pydantic_core-2.14.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:036137b5ad0cb0004c75b579445a1efccd072387a36c7f217bb8efd1afbe5245"}, + {file = "pydantic_core-2.14.6-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:92879bce89f91f4b2416eba4429c7b5ca22c45ef4a499c39f0c5c69257522c7c"}, + {file = "pydantic_core-2.14.6-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0c08de15d50fa190d577e8591f0329a643eeaed696d7771760295998aca6bc66"}, + {file = "pydantic_core-2.14.6-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:36099c69f6b14fc2c49d7996cbf4f87ec4f0e66d1c74aa05228583225a07b590"}, + {file = "pydantic_core-2.14.6-cp310-none-win32.whl", hash = "sha256:7be719e4d2ae6c314f72844ba9d69e38dff342bc360379f7c8537c48e23034b7"}, + {file = "pydantic_core-2.14.6-cp310-none-win_amd64.whl", hash = "sha256:36fa402dcdc8ea7f1b0ddcf0df4254cc6b2e08f8cd80e7010d4c4ae6e86b2a87"}, + {file = "pydantic_core-2.14.6-cp311-cp311-macosx_10_7_x86_64.whl", hash = "sha256:dea7fcd62915fb150cdc373212141a30037e11b761fbced340e9db3379b892d4"}, + {file = "pydantic_core-2.14.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ffff855100bc066ff2cd3aa4a60bc9534661816b110f0243e59503ec2df38421"}, + {file = "pydantic_core-2.14.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1b027c86c66b8627eb90e57aee1f526df77dc6d8b354ec498be9a757d513b92b"}, + {file = "pydantic_core-2.14.6-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:00b1087dabcee0b0ffd104f9f53d7d3eaddfaa314cdd6726143af6bc713aa27e"}, + {file = "pydantic_core-2.14.6-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:75ec284328b60a4e91010c1acade0c30584f28a1f345bc8f72fe8b9e46ec6a96"}, + {file = "pydantic_core-2.14.6-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7e1f4744eea1501404b20b0ac059ff7e3f96a97d3e3f48ce27a139e053bb370b"}, + {file = "pydantic_core-2.14.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b2602177668f89b38b9f84b7b3435d0a72511ddef45dc14446811759b82235a1"}, + {file = "pydantic_core-2.14.6-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6c8edaea3089bf908dd27da8f5d9e395c5b4dc092dbcce9b65e7156099b4b937"}, + {file = "pydantic_core-2.14.6-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:478e9e7b360dfec451daafe286998d4a1eeaecf6d69c427b834ae771cad4b622"}, + {file = "pydantic_core-2.14.6-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:b6ca36c12a5120bad343eef193cc0122928c5c7466121da7c20f41160ba00ba2"}, + {file = "pydantic_core-2.14.6-cp311-none-win32.whl", hash = "sha256:2b8719037e570639e6b665a4050add43134d80b687288ba3ade18b22bbb29dd2"}, + {file = "pydantic_core-2.14.6-cp311-none-win_amd64.whl", hash = "sha256:78ee52ecc088c61cce32b2d30a826f929e1708f7b9247dc3b921aec367dc1b23"}, + {file = "pydantic_core-2.14.6-cp311-none-win_arm64.whl", hash = "sha256:a19b794f8fe6569472ff77602437ec4430f9b2b9ec7a1105cfd2232f9ba355e6"}, + {file = "pydantic_core-2.14.6-cp312-cp312-macosx_10_7_x86_64.whl", hash = "sha256:667aa2eac9cd0700af1ddb38b7b1ef246d8cf94c85637cbb03d7757ca4c3fdec"}, + {file = "pydantic_core-2.14.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:cdee837710ef6b56ebd20245b83799fce40b265b3b406e51e8ccc5b85b9099b7"}, + {file = "pydantic_core-2.14.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2c5bcf3414367e29f83fd66f7de64509a8fd2368b1edf4351e862910727d3e51"}, + {file = "pydantic_core-2.14.6-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:26a92ae76f75d1915806b77cf459811e772d8f71fd1e4339c99750f0e7f6324f"}, + {file = "pydantic_core-2.14.6-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a983cca5ed1dd9a35e9e42ebf9f278d344603bfcb174ff99a5815f953925140a"}, + {file = "pydantic_core-2.14.6-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cb92f9061657287eded380d7dc455bbf115430b3aa4741bdc662d02977e7d0af"}, + {file = "pydantic_core-2.14.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4ace1e220b078c8e48e82c081e35002038657e4b37d403ce940fa679e57113b"}, + {file = "pydantic_core-2.14.6-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ef633add81832f4b56d3b4c9408b43d530dfca29e68fb1b797dcb861a2c734cd"}, + {file = "pydantic_core-2.14.6-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7e90d6cc4aad2cc1f5e16ed56e46cebf4877c62403a311af20459c15da76fd91"}, + {file = "pydantic_core-2.14.6-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:e8a5ac97ea521d7bde7621d86c30e86b798cdecd985723c4ed737a2aa9e77d0c"}, + {file = "pydantic_core-2.14.6-cp312-none-win32.whl", hash = "sha256:f27207e8ca3e5e021e2402ba942e5b4c629718e665c81b8b306f3c8b1ddbb786"}, + {file = "pydantic_core-2.14.6-cp312-none-win_amd64.whl", hash = "sha256:b3e5fe4538001bb82e2295b8d2a39356a84694c97cb73a566dc36328b9f83b40"}, + {file = "pydantic_core-2.14.6-cp312-none-win_arm64.whl", hash = "sha256:64634ccf9d671c6be242a664a33c4acf12882670b09b3f163cd00a24cffbd74e"}, + {file = "pydantic_core-2.14.6-cp37-cp37m-macosx_10_7_x86_64.whl", hash = "sha256:24368e31be2c88bd69340fbfe741b405302993242ccb476c5c3ff48aeee1afe0"}, + {file = "pydantic_core-2.14.6-cp37-cp37m-macosx_11_0_arm64.whl", hash = "sha256:e33b0834f1cf779aa839975f9d8755a7c2420510c0fa1e9fa0497de77cd35d2c"}, + {file = "pydantic_core-2.14.6-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6af4b3f52cc65f8a0bc8b1cd9676f8c21ef3e9132f21fed250f6958bd7223bed"}, + {file = "pydantic_core-2.14.6-cp37-cp37m-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d15687d7d7f40333bd8266f3814c591c2e2cd263fa2116e314f60d82086e353a"}, + {file = "pydantic_core-2.14.6-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:095b707bb287bfd534044166ab767bec70a9bba3175dcdc3371782175c14e43c"}, + {file = "pydantic_core-2.14.6-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:94fc0e6621e07d1e91c44e016cc0b189b48db053061cc22d6298a611de8071bb"}, + {file = "pydantic_core-2.14.6-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ce830e480f6774608dedfd4a90c42aac4a7af0a711f1b52f807130c2e434c06"}, + {file = "pydantic_core-2.14.6-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a306cdd2ad3a7d795d8e617a58c3a2ed0f76c8496fb7621b6cd514eb1532cae8"}, + {file = "pydantic_core-2.14.6-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:2f5fa187bde8524b1e37ba894db13aadd64faa884657473b03a019f625cee9a8"}, + {file = "pydantic_core-2.14.6-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:438027a975cc213a47c5d70672e0d29776082155cfae540c4e225716586be75e"}, + {file = "pydantic_core-2.14.6-cp37-none-win32.whl", hash = "sha256:f96ae96a060a8072ceff4cfde89d261837b4294a4f28b84a28765470d502ccc6"}, + {file = "pydantic_core-2.14.6-cp37-none-win_amd64.whl", hash = "sha256:e646c0e282e960345314f42f2cea5e0b5f56938c093541ea6dbf11aec2862391"}, + {file = "pydantic_core-2.14.6-cp38-cp38-macosx_10_7_x86_64.whl", hash = "sha256:db453f2da3f59a348f514cfbfeb042393b68720787bbef2b4c6068ea362c8149"}, + {file = "pydantic_core-2.14.6-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:3860c62057acd95cc84044e758e47b18dcd8871a328ebc8ccdefd18b0d26a21b"}, + {file = "pydantic_core-2.14.6-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:36026d8f99c58d7044413e1b819a67ca0e0b8ebe0f25e775e6c3d1fabb3c38fb"}, + {file = "pydantic_core-2.14.6-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8ed1af8692bd8d2a29d702f1a2e6065416d76897d726e45a1775b1444f5928a7"}, + {file = "pydantic_core-2.14.6-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:314ccc4264ce7d854941231cf71b592e30d8d368a71e50197c905874feacc8a8"}, + {file = "pydantic_core-2.14.6-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:982487f8931067a32e72d40ab6b47b1628a9c5d344be7f1a4e668fb462d2da42"}, + {file = "pydantic_core-2.14.6-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2dbe357bc4ddda078f79d2a36fc1dd0494a7f2fad83a0a684465b6f24b46fe80"}, + {file = "pydantic_core-2.14.6-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2f6ffc6701a0eb28648c845f4945a194dc7ab3c651f535b81793251e1185ac3d"}, + {file = "pydantic_core-2.14.6-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:7f5025db12fc6de7bc1104d826d5aee1d172f9ba6ca936bf6474c2148ac336c1"}, + {file = "pydantic_core-2.14.6-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:dab03ed811ed1c71d700ed08bde8431cf429bbe59e423394f0f4055f1ca0ea60"}, + {file = "pydantic_core-2.14.6-cp38-none-win32.whl", hash = "sha256:dfcbebdb3c4b6f739a91769aea5ed615023f3c88cb70df812849aef634c25fbe"}, + {file = "pydantic_core-2.14.6-cp38-none-win_amd64.whl", hash = "sha256:99b14dbea2fdb563d8b5a57c9badfcd72083f6006caf8e126b491519c7d64ca8"}, + {file = "pydantic_core-2.14.6-cp39-cp39-macosx_10_7_x86_64.whl", hash = "sha256:4ce8299b481bcb68e5c82002b96e411796b844d72b3e92a3fbedfe8e19813eab"}, + {file = "pydantic_core-2.14.6-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b9a9d92f10772d2a181b5ca339dee066ab7d1c9a34ae2421b2a52556e719756f"}, + {file = "pydantic_core-2.14.6-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fd9e98b408384989ea4ab60206b8e100d8687da18b5c813c11e92fd8212a98e0"}, + {file = "pydantic_core-2.14.6-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4f86f1f318e56f5cbb282fe61eb84767aee743ebe32c7c0834690ebea50c0a6b"}, + {file = "pydantic_core-2.14.6-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:86ce5fcfc3accf3a07a729779d0b86c5d0309a4764c897d86c11089be61da160"}, + {file = "pydantic_core-2.14.6-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3dcf1978be02153c6a31692d4fbcc2a3f1db9da36039ead23173bc256ee3b91b"}, + {file = "pydantic_core-2.14.6-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eedf97be7bc3dbc8addcef4142f4b4164066df0c6f36397ae4aaed3eb187d8ab"}, + {file = "pydantic_core-2.14.6-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d5f916acf8afbcab6bacbb376ba7dc61f845367901ecd5e328fc4d4aef2fcab0"}, + {file = "pydantic_core-2.14.6-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:8a14c192c1d724c3acbfb3f10a958c55a2638391319ce8078cb36c02283959b9"}, + {file = "pydantic_core-2.14.6-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0348b1dc6b76041516e8a854ff95b21c55f5a411c3297d2ca52f5528e49d8411"}, + {file = "pydantic_core-2.14.6-cp39-none-win32.whl", hash = "sha256:de2a0645a923ba57c5527497daf8ec5df69c6eadf869e9cd46e86349146e5975"}, + {file = "pydantic_core-2.14.6-cp39-none-win_amd64.whl", hash = "sha256:aca48506a9c20f68ee61c87f2008f81f8ee99f8d7f0104bff3c47e2d148f89d9"}, + {file = "pydantic_core-2.14.6-pp310-pypy310_pp73-macosx_10_7_x86_64.whl", hash = "sha256:d5c28525c19f5bb1e09511669bb57353d22b94cf8b65f3a8d141c389a55dec95"}, + {file = "pydantic_core-2.14.6-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:78d0768ee59baa3de0f4adac9e3748b4b1fffc52143caebddfd5ea2961595277"}, + {file = "pydantic_core-2.14.6-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b93785eadaef932e4fe9c6e12ba67beb1b3f1e5495631419c784ab87e975670"}, + {file = "pydantic_core-2.14.6-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a874f21f87c485310944b2b2734cd6d318765bcbb7515eead33af9641816506e"}, + {file = "pydantic_core-2.14.6-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b89f4477d915ea43b4ceea6756f63f0288941b6443a2b28c69004fe07fde0d0d"}, + {file = "pydantic_core-2.14.6-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:172de779e2a153d36ee690dbc49c6db568d7b33b18dc56b69a7514aecbcf380d"}, + {file = "pydantic_core-2.14.6-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:dfcebb950aa7e667ec226a442722134539e77c575f6cfaa423f24371bb8d2e94"}, + {file = "pydantic_core-2.14.6-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:55a23dcd98c858c0db44fc5c04fc7ed81c4b4d33c653a7c45ddaebf6563a2f66"}, + {file = "pydantic_core-2.14.6-pp37-pypy37_pp73-macosx_10_7_x86_64.whl", hash = "sha256:4241204e4b36ab5ae466ecec5c4c16527a054c69f99bba20f6f75232a6a534e2"}, + {file = "pydantic_core-2.14.6-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e574de99d735b3fc8364cba9912c2bec2da78775eba95cbb225ef7dda6acea24"}, + {file = "pydantic_core-2.14.6-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1302a54f87b5cd8528e4d6d1bf2133b6aa7c6122ff8e9dc5220fbc1e07bffebd"}, + {file = "pydantic_core-2.14.6-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f8e81e4b55930e5ffab4a68db1af431629cf2e4066dbdbfef65348b8ab804ea8"}, + {file = "pydantic_core-2.14.6-pp37-pypy37_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:c99462ffc538717b3e60151dfaf91125f637e801f5ab008f81c402f1dff0cd0f"}, + {file = "pydantic_core-2.14.6-pp37-pypy37_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:e4cf2d5829f6963a5483ec01578ee76d329eb5caf330ecd05b3edd697e7d768a"}, + {file = "pydantic_core-2.14.6-pp38-pypy38_pp73-macosx_10_7_x86_64.whl", hash = "sha256:cf10b7d58ae4a1f07fccbf4a0a956d705356fea05fb4c70608bb6fa81d103cda"}, + {file = "pydantic_core-2.14.6-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:399ac0891c284fa8eb998bcfa323f2234858f5d2efca3950ae58c8f88830f145"}, + {file = "pydantic_core-2.14.6-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9c6a5c79b28003543db3ba67d1df336f253a87d3112dac3a51b94f7d48e4c0e1"}, + {file = "pydantic_core-2.14.6-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:599c87d79cab2a6a2a9df4aefe0455e61e7d2aeede2f8577c1b7c0aec643ee8e"}, + {file = "pydantic_core-2.14.6-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:43e166ad47ba900f2542a80d83f9fc65fe99eb63ceec4debec160ae729824052"}, + {file = "pydantic_core-2.14.6-pp38-pypy38_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:3a0b5db001b98e1c649dd55afa928e75aa4087e587b9524a4992316fa23c9fba"}, + {file = "pydantic_core-2.14.6-pp38-pypy38_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:747265448cb57a9f37572a488a57d873fd96bf51e5bb7edb52cfb37124516da4"}, + {file = "pydantic_core-2.14.6-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:7ebe3416785f65c28f4f9441e916bfc8a54179c8dea73c23023f7086fa601c5d"}, + {file = "pydantic_core-2.14.6-pp39-pypy39_pp73-macosx_10_7_x86_64.whl", hash = "sha256:86c963186ca5e50d5c8287b1d1c9d3f8f024cbe343d048c5bd282aec2d8641f2"}, + {file = "pydantic_core-2.14.6-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:e0641b506486f0b4cd1500a2a65740243e8670a2549bb02bc4556a83af84ae03"}, + {file = "pydantic_core-2.14.6-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71d72ca5eaaa8d38c8df16b7deb1a2da4f650c41b58bb142f3fb75d5ad4a611f"}, + {file = "pydantic_core-2.14.6-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:27e524624eace5c59af499cd97dc18bb201dc6a7a2da24bfc66ef151c69a5f2a"}, + {file = "pydantic_core-2.14.6-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a3dde6cac75e0b0902778978d3b1646ca9f438654395a362cb21d9ad34b24acf"}, + {file = "pydantic_core-2.14.6-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:00646784f6cd993b1e1c0e7b0fdcbccc375d539db95555477771c27555e3c556"}, + {file = "pydantic_core-2.14.6-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:23598acb8ccaa3d1d875ef3b35cb6376535095e9405d91a3d57a8c7db5d29341"}, + {file = "pydantic_core-2.14.6-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7f41533d7e3cf9520065f610b41ac1c76bc2161415955fbcead4981b22c7611e"}, + {file = "pydantic_core-2.14.6.tar.gz", hash = "sha256:1fd0c1d395372843fba13a51c28e3bb9d59bd7aebfeb17358ffaaa1e4dbbe948"}, ] [package.dependencies] @@ -2411,13 +2443,13 @@ windows-terminal = ["colorama (>=0.4.6)"] [[package]] name = "pytest" -version = "7.4.3" +version = "7.4.4" description = "pytest: simple powerful testing with Python" optional = false python-versions = ">=3.7" files = [ - {file = "pytest-7.4.3-py3-none-any.whl", hash = "sha256:0d009c083ea859a71b76adf7c1d502e4bc170b80a8ef002da5806527b9591fac"}, - {file = "pytest-7.4.3.tar.gz", hash = "sha256:d989d136982de4e3b29dabcc838ad581c64e8ed52c11fbe86ddebd9da0818cd5"}, + {file = "pytest-7.4.4-py3-none-any.whl", hash = "sha256:b090cdf5ed60bf4c45261be03239c2c1c22df034fbffe691abe93cd80cea01d8"}, + {file = "pytest-7.4.4.tar.gz", hash = "sha256:2cf0005922c6ace4a3e2ec8b4080eb0d9753fdc93107415332f50ce9e7994280"}, ] [package.dependencies] @@ -2664,104 +2696,104 @@ files = [ [[package]] name = "pyzmq" -version = "25.1.1" +version = "25.1.2" description = "Python bindings for 0MQ" optional = false python-versions = ">=3.6" files = [ - {file = "pyzmq-25.1.1-cp310-cp310-macosx_10_15_universal2.whl", hash = "sha256:381469297409c5adf9a0e884c5eb5186ed33137badcbbb0560b86e910a2f1e76"}, - {file = "pyzmq-25.1.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:955215ed0604dac5b01907424dfa28b40f2b2292d6493445dd34d0dfa72586a8"}, - {file = "pyzmq-25.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:985bbb1316192b98f32e25e7b9958088431d853ac63aca1d2c236f40afb17c83"}, - {file = "pyzmq-25.1.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:afea96f64efa98df4da6958bae37f1cbea7932c35878b185e5982821bc883369"}, - {file = "pyzmq-25.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:76705c9325d72a81155bb6ab48d4312e0032bf045fb0754889133200f7a0d849"}, - {file = "pyzmq-25.1.1-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:77a41c26205d2353a4c94d02be51d6cbdf63c06fbc1295ea57dad7e2d3381b71"}, - {file = "pyzmq-25.1.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:12720a53e61c3b99d87262294e2b375c915fea93c31fc2336898c26d7aed34cd"}, - {file = "pyzmq-25.1.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:57459b68e5cd85b0be8184382cefd91959cafe79ae019e6b1ae6e2ba8a12cda7"}, - {file = "pyzmq-25.1.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:292fe3fc5ad4a75bc8df0dfaee7d0babe8b1f4ceb596437213821f761b4589f9"}, - {file = "pyzmq-25.1.1-cp310-cp310-win32.whl", hash = "sha256:35b5ab8c28978fbbb86ea54958cd89f5176ce747c1fb3d87356cf698048a7790"}, - {file = "pyzmq-25.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:11baebdd5fc5b475d484195e49bae2dc64b94a5208f7c89954e9e354fc609d8f"}, - {file = "pyzmq-25.1.1-cp311-cp311-macosx_10_15_universal2.whl", hash = "sha256:d20a0ddb3e989e8807d83225a27e5c2eb2260eaa851532086e9e0fa0d5287d83"}, - {file = "pyzmq-25.1.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:e1c1be77bc5fb77d923850f82e55a928f8638f64a61f00ff18a67c7404faf008"}, - {file = "pyzmq-25.1.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d89528b4943d27029a2818f847c10c2cecc79fa9590f3cb1860459a5be7933eb"}, - {file = "pyzmq-25.1.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:90f26dc6d5f241ba358bef79be9ce06de58d477ca8485e3291675436d3827cf8"}, - {file = "pyzmq-25.1.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c2b92812bd214018e50b6380ea3ac0c8bb01ac07fcc14c5f86a5bb25e74026e9"}, - {file = "pyzmq-25.1.1-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:2f957ce63d13c28730f7fd6b72333814221c84ca2421298f66e5143f81c9f91f"}, - {file = "pyzmq-25.1.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:047a640f5c9c6ade7b1cc6680a0e28c9dd5a0825135acbd3569cc96ea00b2505"}, - {file = "pyzmq-25.1.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:7f7e58effd14b641c5e4dec8c7dab02fb67a13df90329e61c869b9cc607ef752"}, - {file = "pyzmq-25.1.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:c2910967e6ab16bf6fbeb1f771c89a7050947221ae12a5b0b60f3bca2ee19bca"}, - {file = "pyzmq-25.1.1-cp311-cp311-win32.whl", hash = "sha256:76c1c8efb3ca3a1818b837aea423ff8a07bbf7aafe9f2f6582b61a0458b1a329"}, - {file = "pyzmq-25.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:44e58a0554b21fc662f2712814a746635ed668d0fbc98b7cb9d74cb798d202e6"}, - {file = "pyzmq-25.1.1-cp312-cp312-macosx_10_15_universal2.whl", hash = "sha256:e1ffa1c924e8c72778b9ccd386a7067cddf626884fd8277f503c48bb5f51c762"}, - {file = "pyzmq-25.1.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:1af379b33ef33757224da93e9da62e6471cf4a66d10078cf32bae8127d3d0d4a"}, - {file = "pyzmq-25.1.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cff084c6933680d1f8b2f3b4ff5bbb88538a4aac00d199ac13f49d0698727ecb"}, - {file = "pyzmq-25.1.1-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e2400a94f7dd9cb20cd012951a0cbf8249e3d554c63a9c0cdfd5cbb6c01d2dec"}, - {file = "pyzmq-25.1.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2d81f1ddae3858b8299d1da72dd7d19dd36aab654c19671aa8a7e7fb02f6638a"}, - {file = "pyzmq-25.1.1-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:255ca2b219f9e5a3a9ef3081512e1358bd4760ce77828e1028b818ff5610b87b"}, - {file = "pyzmq-25.1.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:a882ac0a351288dd18ecae3326b8a49d10c61a68b01419f3a0b9a306190baf69"}, - {file = "pyzmq-25.1.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:724c292bb26365659fc434e9567b3f1adbdb5e8d640c936ed901f49e03e5d32e"}, - {file = "pyzmq-25.1.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ca1ed0bb2d850aa8471387882247c68f1e62a4af0ce9c8a1dbe0d2bf69e41fb"}, - {file = "pyzmq-25.1.1-cp312-cp312-win32.whl", hash = "sha256:b3451108ab861040754fa5208bca4a5496c65875710f76789a9ad27c801a0075"}, - {file = "pyzmq-25.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:eadbefd5e92ef8a345f0525b5cfd01cf4e4cc651a2cffb8f23c0dd184975d787"}, - {file = "pyzmq-25.1.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:db0b2af416ba735c6304c47f75d348f498b92952f5e3e8bff449336d2728795d"}, - {file = "pyzmq-25.1.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c7c133e93b405eb0d36fa430c94185bdd13c36204a8635470cccc200723c13bb"}, - {file = "pyzmq-25.1.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:273bc3959bcbff3f48606b28229b4721716598d76b5aaea2b4a9d0ab454ec062"}, - {file = "pyzmq-25.1.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:cbc8df5c6a88ba5ae385d8930da02201165408dde8d8322072e3e5ddd4f68e22"}, - {file = "pyzmq-25.1.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:18d43df3f2302d836f2a56f17e5663e398416e9dd74b205b179065e61f1a6edf"}, - {file = "pyzmq-25.1.1-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:73461eed88a88c866656e08f89299720a38cb4e9d34ae6bf5df6f71102570f2e"}, - {file = "pyzmq-25.1.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:34c850ce7976d19ebe7b9d4b9bb8c9dfc7aac336c0958e2651b88cbd46682123"}, - {file = "pyzmq-25.1.1-cp36-cp36m-win32.whl", hash = "sha256:d2045d6d9439a0078f2a34b57c7b18c4a6aef0bee37f22e4ec9f32456c852c71"}, - {file = "pyzmq-25.1.1-cp36-cp36m-win_amd64.whl", hash = "sha256:458dea649f2f02a0b244ae6aef8dc29325a2810aa26b07af8374dc2a9faf57e3"}, - {file = "pyzmq-25.1.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:7cff25c5b315e63b07a36f0c2bab32c58eafbe57d0dce61b614ef4c76058c115"}, - {file = "pyzmq-25.1.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b1579413ae492b05de5a6174574f8c44c2b9b122a42015c5292afa4be2507f28"}, - {file = "pyzmq-25.1.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3d0a409d3b28607cc427aa5c30a6f1e4452cc44e311f843e05edb28ab5e36da0"}, - {file = "pyzmq-25.1.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:21eb4e609a154a57c520e3d5bfa0d97e49b6872ea057b7c85257b11e78068222"}, - {file = "pyzmq-25.1.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:034239843541ef7a1aee0c7b2cb7f6aafffb005ede965ae9cbd49d5ff4ff73cf"}, - {file = "pyzmq-25.1.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:f8115e303280ba09f3898194791a153862cbf9eef722ad8f7f741987ee2a97c7"}, - {file = "pyzmq-25.1.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:1a5d26fe8f32f137e784f768143728438877d69a586ddeaad898558dc971a5ae"}, - {file = "pyzmq-25.1.1-cp37-cp37m-win32.whl", hash = "sha256:f32260e556a983bc5c7ed588d04c942c9a8f9c2e99213fec11a031e316874c7e"}, - {file = "pyzmq-25.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:abf34e43c531bbb510ae7e8f5b2b1f2a8ab93219510e2b287a944432fad135f3"}, - {file = "pyzmq-25.1.1-cp38-cp38-macosx_10_15_universal2.whl", hash = "sha256:87e34f31ca8f168c56d6fbf99692cc8d3b445abb5bfd08c229ae992d7547a92a"}, - {file = "pyzmq-25.1.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:c9c6c9b2c2f80747a98f34ef491c4d7b1a8d4853937bb1492774992a120f475d"}, - {file = "pyzmq-25.1.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:5619f3f5a4db5dbb572b095ea3cb5cc035335159d9da950830c9c4db2fbb6995"}, - {file = "pyzmq-25.1.1-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:5a34d2395073ef862b4032343cf0c32a712f3ab49d7ec4f42c9661e0294d106f"}, - {file = "pyzmq-25.1.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25f0e6b78220aba09815cd1f3a32b9c7cb3e02cb846d1cfc526b6595f6046618"}, - {file = "pyzmq-25.1.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:3669cf8ee3520c2f13b2e0351c41fea919852b220988d2049249db10046a7afb"}, - {file = "pyzmq-25.1.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:2d163a18819277e49911f7461567bda923461c50b19d169a062536fffe7cd9d2"}, - {file = "pyzmq-25.1.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:df27ffddff4190667d40de7beba4a950b5ce78fe28a7dcc41d6f8a700a80a3c0"}, - {file = "pyzmq-25.1.1-cp38-cp38-win32.whl", hash = "sha256:a382372898a07479bd34bda781008e4a954ed8750f17891e794521c3e21c2e1c"}, - {file = "pyzmq-25.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:52533489f28d62eb1258a965f2aba28a82aa747202c8fa5a1c7a43b5db0e85c1"}, - {file = "pyzmq-25.1.1-cp39-cp39-macosx_10_15_universal2.whl", hash = "sha256:03b3f49b57264909aacd0741892f2aecf2f51fb053e7d8ac6767f6c700832f45"}, - {file = "pyzmq-25.1.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:330f9e188d0d89080cde66dc7470f57d1926ff2fb5576227f14d5be7ab30b9fa"}, - {file = "pyzmq-25.1.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:2ca57a5be0389f2a65e6d3bb2962a971688cbdd30b4c0bd188c99e39c234f414"}, - {file = "pyzmq-25.1.1-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:d457aed310f2670f59cc5b57dcfced452aeeed77f9da2b9763616bd57e4dbaae"}, - {file = "pyzmq-25.1.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c56d748ea50215abef7030c72b60dd723ed5b5c7e65e7bc2504e77843631c1a6"}, - {file = "pyzmq-25.1.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:8f03d3f0d01cb5a018debeb412441996a517b11c5c17ab2001aa0597c6d6882c"}, - {file = "pyzmq-25.1.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:820c4a08195a681252f46926de10e29b6bbf3e17b30037bd4250d72dd3ddaab8"}, - {file = "pyzmq-25.1.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:17ef5f01d25b67ca8f98120d5fa1d21efe9611604e8eb03a5147360f517dd1e2"}, - {file = "pyzmq-25.1.1-cp39-cp39-win32.whl", hash = "sha256:04ccbed567171579ec2cebb9c8a3e30801723c575601f9a990ab25bcac6b51e2"}, - {file = "pyzmq-25.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:e61f091c3ba0c3578411ef505992d356a812fb200643eab27f4f70eed34a29ef"}, - {file = "pyzmq-25.1.1-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:ade6d25bb29c4555d718ac6d1443a7386595528c33d6b133b258f65f963bb0f6"}, - {file = "pyzmq-25.1.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e0c95ddd4f6e9fca4e9e3afaa4f9df8552f0ba5d1004e89ef0a68e1f1f9807c7"}, - {file = "pyzmq-25.1.1-pp310-pypy310_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:48e466162a24daf86f6b5ca72444d2bf39a5e58da5f96370078be67c67adc978"}, - {file = "pyzmq-25.1.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:abc719161780932c4e11aaebb203be3d6acc6b38d2f26c0f523b5b59d2fc1996"}, - {file = "pyzmq-25.1.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:1ccf825981640b8c34ae54231b7ed00271822ea1c6d8ba1090ebd4943759abf5"}, - {file = "pyzmq-25.1.1-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:c2f20ce161ebdb0091a10c9ca0372e023ce24980d0e1f810f519da6f79c60800"}, - {file = "pyzmq-25.1.1-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:deee9ca4727f53464daf089536e68b13e6104e84a37820a88b0a057b97bba2d2"}, - {file = "pyzmq-25.1.1-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:aa8d6cdc8b8aa19ceb319aaa2b660cdaccc533ec477eeb1309e2a291eaacc43a"}, - {file = "pyzmq-25.1.1-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:019e59ef5c5256a2c7378f2fb8560fc2a9ff1d315755204295b2eab96b254d0a"}, - {file = "pyzmq-25.1.1-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:b9af3757495c1ee3b5c4e945c1df7be95562277c6e5bccc20a39aec50f826cd0"}, - {file = "pyzmq-25.1.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:548d6482dc8aadbe7e79d1b5806585c8120bafa1ef841167bc9090522b610fa6"}, - {file = "pyzmq-25.1.1-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:057e824b2aae50accc0f9a0570998adc021b372478a921506fddd6c02e60308e"}, - {file = "pyzmq-25.1.1-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:2243700cc5548cff20963f0ca92d3e5e436394375ab8a354bbea2b12911b20b0"}, - {file = "pyzmq-25.1.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:79986f3b4af059777111409ee517da24a529bdbd46da578b33f25580adcff728"}, - {file = "pyzmq-25.1.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:11d58723d44d6ed4dd677c5615b2ffb19d5c426636345567d6af82be4dff8a55"}, - {file = "pyzmq-25.1.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:49d238cf4b69652257db66d0c623cd3e09b5d2e9576b56bc067a396133a00d4a"}, - {file = "pyzmq-25.1.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fedbdc753827cf014c01dbbee9c3be17e5a208dcd1bf8641ce2cd29580d1f0d4"}, - {file = "pyzmq-25.1.1-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bc16ac425cc927d0a57d242589f87ee093884ea4804c05a13834d07c20db203c"}, - {file = "pyzmq-25.1.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:11c1d2aed9079c6b0c9550a7257a836b4a637feb334904610f06d70eb44c56d2"}, - {file = "pyzmq-25.1.1-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:e8a701123029cc240cea61dd2d16ad57cab4691804143ce80ecd9286b464d180"}, - {file = "pyzmq-25.1.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:61706a6b6c24bdece85ff177fec393545a3191eeda35b07aaa1458a027ad1304"}, - {file = "pyzmq-25.1.1.tar.gz", hash = "sha256:259c22485b71abacdfa8bf79720cd7bcf4b9d128b30ea554f01ae71fdbfdaa23"}, + {file = "pyzmq-25.1.2-cp310-cp310-macosx_10_15_universal2.whl", hash = "sha256:e624c789359f1a16f83f35e2c705d07663ff2b4d4479bad35621178d8f0f6ea4"}, + {file = "pyzmq-25.1.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:49151b0efece79f6a79d41a461d78535356136ee70084a1c22532fc6383f4ad0"}, + {file = "pyzmq-25.1.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d9a5f194cf730f2b24d6af1f833c14c10f41023da46a7f736f48b6d35061e76e"}, + {file = "pyzmq-25.1.2-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:faf79a302f834d9e8304fafdc11d0d042266667ac45209afa57e5efc998e3872"}, + {file = "pyzmq-25.1.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f51a7b4ead28d3fca8dda53216314a553b0f7a91ee8fc46a72b402a78c3e43d"}, + {file = "pyzmq-25.1.2-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:0ddd6d71d4ef17ba5a87becf7ddf01b371eaba553c603477679ae817a8d84d75"}, + {file = "pyzmq-25.1.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:246747b88917e4867e2367b005fc8eefbb4a54b7db363d6c92f89d69abfff4b6"}, + {file = "pyzmq-25.1.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:00c48ae2fd81e2a50c3485de1b9d5c7c57cd85dc8ec55683eac16846e57ac979"}, + {file = "pyzmq-25.1.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:5a68d491fc20762b630e5db2191dd07ff89834086740f70e978bb2ef2668be08"}, + {file = "pyzmq-25.1.2-cp310-cp310-win32.whl", hash = "sha256:09dfe949e83087da88c4a76767df04b22304a682d6154de2c572625c62ad6886"}, + {file = "pyzmq-25.1.2-cp310-cp310-win_amd64.whl", hash = "sha256:fa99973d2ed20417744fca0073390ad65ce225b546febb0580358e36aa90dba6"}, + {file = "pyzmq-25.1.2-cp311-cp311-macosx_10_15_universal2.whl", hash = "sha256:82544e0e2d0c1811482d37eef297020a040c32e0687c1f6fc23a75b75db8062c"}, + {file = "pyzmq-25.1.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:01171fc48542348cd1a360a4b6c3e7d8f46cdcf53a8d40f84db6707a6768acc1"}, + {file = "pyzmq-25.1.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bc69c96735ab501419c432110016329bf0dea8898ce16fab97c6d9106dc0b348"}, + {file = "pyzmq-25.1.2-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3e124e6b1dd3dfbeb695435dff0e383256655bb18082e094a8dd1f6293114642"}, + {file = "pyzmq-25.1.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7598d2ba821caa37a0f9d54c25164a4fa351ce019d64d0b44b45540950458840"}, + {file = "pyzmq-25.1.2-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:d1299d7e964c13607efd148ca1f07dcbf27c3ab9e125d1d0ae1d580a1682399d"}, + {file = "pyzmq-25.1.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:4e6f689880d5ad87918430957297c975203a082d9a036cc426648fcbedae769b"}, + {file = "pyzmq-25.1.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:cc69949484171cc961e6ecd4a8911b9ce7a0d1f738fcae717177c231bf77437b"}, + {file = "pyzmq-25.1.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9880078f683466b7f567b8624bfc16cad65077be046b6e8abb53bed4eeb82dd3"}, + {file = "pyzmq-25.1.2-cp311-cp311-win32.whl", hash = "sha256:4e5837af3e5aaa99a091302df5ee001149baff06ad22b722d34e30df5f0d9097"}, + {file = "pyzmq-25.1.2-cp311-cp311-win_amd64.whl", hash = "sha256:25c2dbb97d38b5ac9fd15586e048ec5eb1e38f3d47fe7d92167b0c77bb3584e9"}, + {file = "pyzmq-25.1.2-cp312-cp312-macosx_10_15_universal2.whl", hash = "sha256:11e70516688190e9c2db14fcf93c04192b02d457b582a1f6190b154691b4c93a"}, + {file = "pyzmq-25.1.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:313c3794d650d1fccaaab2df942af9f2c01d6217c846177cfcbc693c7410839e"}, + {file = "pyzmq-25.1.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1b3cbba2f47062b85fe0ef9de5b987612140a9ba3a9c6d2543c6dec9f7c2ab27"}, + {file = "pyzmq-25.1.2-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fc31baa0c32a2ca660784d5af3b9487e13b61b3032cb01a115fce6588e1bed30"}, + {file = "pyzmq-25.1.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:02c9087b109070c5ab0b383079fa1b5f797f8d43e9a66c07a4b8b8bdecfd88ee"}, + {file = "pyzmq-25.1.2-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:f8429b17cbb746c3e043cb986328da023657e79d5ed258b711c06a70c2ea7537"}, + {file = "pyzmq-25.1.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:5074adeacede5f810b7ef39607ee59d94e948b4fd954495bdb072f8c54558181"}, + {file = "pyzmq-25.1.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:7ae8f354b895cbd85212da245f1a5ad8159e7840e37d78b476bb4f4c3f32a9fe"}, + {file = "pyzmq-25.1.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:b264bf2cc96b5bc43ce0e852be995e400376bd87ceb363822e2cb1964fcdc737"}, + {file = "pyzmq-25.1.2-cp312-cp312-win32.whl", hash = "sha256:02bbc1a87b76e04fd780b45e7f695471ae6de747769e540da909173d50ff8e2d"}, + {file = "pyzmq-25.1.2-cp312-cp312-win_amd64.whl", hash = "sha256:ced111c2e81506abd1dc142e6cd7b68dd53747b3b7ae5edbea4578c5eeff96b7"}, + {file = "pyzmq-25.1.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:7b6d09a8962a91151f0976008eb7b29b433a560fde056ec7a3db9ec8f1075438"}, + {file = "pyzmq-25.1.2-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:967668420f36878a3c9ecb5ab33c9d0ff8d054f9c0233d995a6d25b0e95e1b6b"}, + {file = "pyzmq-25.1.2-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5edac3f57c7ddaacdb4d40f6ef2f9e299471fc38d112f4bc6d60ab9365445fb0"}, + {file = "pyzmq-25.1.2-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:0dabfb10ef897f3b7e101cacba1437bd3a5032ee667b7ead32bbcdd1a8422fe7"}, + {file = "pyzmq-25.1.2-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:2c6441e0398c2baacfe5ba30c937d274cfc2dc5b55e82e3749e333aabffde561"}, + {file = "pyzmq-25.1.2-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:16b726c1f6c2e7625706549f9dbe9b06004dfbec30dbed4bf50cbdfc73e5b32a"}, + {file = "pyzmq-25.1.2-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:a86c2dd76ef71a773e70551a07318b8e52379f58dafa7ae1e0a4be78efd1ff16"}, + {file = "pyzmq-25.1.2-cp36-cp36m-win32.whl", hash = "sha256:359f7f74b5d3c65dae137f33eb2bcfa7ad9ebefd1cab85c935f063f1dbb245cc"}, + {file = "pyzmq-25.1.2-cp36-cp36m-win_amd64.whl", hash = "sha256:55875492f820d0eb3417b51d96fea549cde77893ae3790fd25491c5754ea2f68"}, + {file = "pyzmq-25.1.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b8c8a419dfb02e91b453615c69568442e897aaf77561ee0064d789705ff37a92"}, + {file = "pyzmq-25.1.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8807c87fa893527ae8a524c15fc505d9950d5e856f03dae5921b5e9aa3b8783b"}, + {file = "pyzmq-25.1.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5e319ed7d6b8f5fad9b76daa0a68497bc6f129858ad956331a5835785761e003"}, + {file = "pyzmq-25.1.2-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:3c53687dde4d9d473c587ae80cc328e5b102b517447456184b485587ebd18b62"}, + {file = "pyzmq-25.1.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:9add2e5b33d2cd765ad96d5eb734a5e795a0755f7fc49aa04f76d7ddda73fd70"}, + {file = "pyzmq-25.1.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:e690145a8c0c273c28d3b89d6fb32c45e0d9605b2293c10e650265bf5c11cfec"}, + {file = "pyzmq-25.1.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:00a06faa7165634f0cac1abb27e54d7a0b3b44eb9994530b8ec73cf52e15353b"}, + {file = "pyzmq-25.1.2-cp37-cp37m-win32.whl", hash = "sha256:0f97bc2f1f13cb16905a5f3e1fbdf100e712d841482b2237484360f8bc4cb3d7"}, + {file = "pyzmq-25.1.2-cp37-cp37m-win_amd64.whl", hash = "sha256:6cc0020b74b2e410287e5942e1e10886ff81ac77789eb20bec13f7ae681f0fdd"}, + {file = "pyzmq-25.1.2-cp38-cp38-macosx_10_15_universal2.whl", hash = "sha256:bef02cfcbded83473bdd86dd8d3729cd82b2e569b75844fb4ea08fee3c26ae41"}, + {file = "pyzmq-25.1.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:e10a4b5a4b1192d74853cc71a5e9fd022594573926c2a3a4802020360aa719d8"}, + {file = "pyzmq-25.1.2-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:8c5f80e578427d4695adac6fdf4370c14a2feafdc8cb35549c219b90652536ae"}, + {file = "pyzmq-25.1.2-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:5dde6751e857910c1339890f3524de74007958557593b9e7e8c5f01cd919f8a7"}, + {file = "pyzmq-25.1.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ea1608dd169da230a0ad602d5b1ebd39807ac96cae1845c3ceed39af08a5c6df"}, + {file = "pyzmq-25.1.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:0f513130c4c361201da9bc69df25a086487250e16b5571ead521b31ff6b02220"}, + {file = "pyzmq-25.1.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:019744b99da30330798bb37df33549d59d380c78e516e3bab9c9b84f87a9592f"}, + {file = "pyzmq-25.1.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:2e2713ef44be5d52dd8b8e2023d706bf66cb22072e97fc71b168e01d25192755"}, + {file = "pyzmq-25.1.2-cp38-cp38-win32.whl", hash = "sha256:07cd61a20a535524906595e09344505a9bd46f1da7a07e504b315d41cd42eb07"}, + {file = "pyzmq-25.1.2-cp38-cp38-win_amd64.whl", hash = "sha256:eb7e49a17fb8c77d3119d41a4523e432eb0c6932187c37deb6fbb00cc3028088"}, + {file = "pyzmq-25.1.2-cp39-cp39-macosx_10_15_universal2.whl", hash = "sha256:94504ff66f278ab4b7e03e4cba7e7e400cb73bfa9d3d71f58d8972a8dc67e7a6"}, + {file = "pyzmq-25.1.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6dd0d50bbf9dca1d0bdea219ae6b40f713a3fb477c06ca3714f208fd69e16fd8"}, + {file = "pyzmq-25.1.2-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:004ff469d21e86f0ef0369717351073e0e577428e514c47c8480770d5e24a565"}, + {file = "pyzmq-25.1.2-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:c0b5ca88a8928147b7b1e2dfa09f3b6c256bc1135a1338536cbc9ea13d3b7add"}, + {file = "pyzmq-25.1.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2c9a79f1d2495b167119d02be7448bfba57fad2a4207c4f68abc0bab4b92925b"}, + {file = "pyzmq-25.1.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:518efd91c3d8ac9f9b4f7dd0e2b7b8bf1a4fe82a308009016b07eaa48681af82"}, + {file = "pyzmq-25.1.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:1ec23bd7b3a893ae676d0e54ad47d18064e6c5ae1fadc2f195143fb27373f7f6"}, + {file = "pyzmq-25.1.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:db36c27baed588a5a8346b971477b718fdc66cf5b80cbfbd914b4d6d355e44e2"}, + {file = "pyzmq-25.1.2-cp39-cp39-win32.whl", hash = "sha256:39b1067f13aba39d794a24761e385e2eddc26295826530a8c7b6c6c341584289"}, + {file = "pyzmq-25.1.2-cp39-cp39-win_amd64.whl", hash = "sha256:8e9f3fabc445d0ce320ea2c59a75fe3ea591fdbdeebec5db6de530dd4b09412e"}, + {file = "pyzmq-25.1.2-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a8c1d566344aee826b74e472e16edae0a02e2a044f14f7c24e123002dcff1c05"}, + {file = "pyzmq-25.1.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:759cfd391a0996345ba94b6a5110fca9c557ad4166d86a6e81ea526c376a01e8"}, + {file = "pyzmq-25.1.2-pp310-pypy310_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7c61e346ac34b74028ede1c6b4bcecf649d69b707b3ff9dc0fab453821b04d1e"}, + {file = "pyzmq-25.1.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4cb8fc1f8d69b411b8ec0b5f1ffbcaf14c1db95b6bccea21d83610987435f1a4"}, + {file = "pyzmq-25.1.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:3c00c9b7d1ca8165c610437ca0c92e7b5607b2f9076f4eb4b095c85d6e680a1d"}, + {file = "pyzmq-25.1.2-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:df0c7a16ebb94452d2909b9a7b3337940e9a87a824c4fc1c7c36bb4404cb0cde"}, + {file = "pyzmq-25.1.2-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:45999e7f7ed5c390f2e87ece7f6c56bf979fb213550229e711e45ecc7d42ccb8"}, + {file = "pyzmq-25.1.2-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ac170e9e048b40c605358667aca3d94e98f604a18c44bdb4c102e67070f3ac9b"}, + {file = "pyzmq-25.1.2-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d1b604734bec94f05f81b360a272fc824334267426ae9905ff32dc2be433ab96"}, + {file = "pyzmq-25.1.2-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:a793ac733e3d895d96f865f1806f160696422554e46d30105807fdc9841b9f7d"}, + {file = "pyzmq-25.1.2-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:0806175f2ae5ad4b835ecd87f5f85583316b69f17e97786f7443baaf54b9bb98"}, + {file = "pyzmq-25.1.2-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:ef12e259e7bc317c7597d4f6ef59b97b913e162d83b421dd0db3d6410f17a244"}, + {file = "pyzmq-25.1.2-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ea253b368eb41116011add00f8d5726762320b1bda892f744c91997b65754d73"}, + {file = "pyzmq-25.1.2-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1b9b1f2ad6498445a941d9a4fee096d387fee436e45cc660e72e768d3d8ee611"}, + {file = "pyzmq-25.1.2-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:8b14c75979ce932c53b79976a395cb2a8cd3aaf14aef75e8c2cb55a330b9b49d"}, + {file = "pyzmq-25.1.2-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:889370d5174a741a62566c003ee8ddba4b04c3f09a97b8000092b7ca83ec9c49"}, + {file = "pyzmq-25.1.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9a18fff090441a40ffda8a7f4f18f03dc56ae73f148f1832e109f9bffa85df15"}, + {file = "pyzmq-25.1.2-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:99a6b36f95c98839ad98f8c553d8507644c880cf1e0a57fe5e3a3f3969040882"}, + {file = "pyzmq-25.1.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4345c9a27f4310afbb9c01750e9461ff33d6fb74cd2456b107525bbeebcb5be3"}, + {file = "pyzmq-25.1.2-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:3516e0b6224cf6e43e341d56da15fd33bdc37fa0c06af4f029f7d7dfceceabbc"}, + {file = "pyzmq-25.1.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:146b9b1f29ead41255387fb07be56dc29639262c0f7344f570eecdcd8d683314"}, + {file = "pyzmq-25.1.2.tar.gz", hash = "sha256:93f1aa311e8bb912e34f004cf186407a4e90eec4f0ecc0efd26056bf7eda0226"}, ] [package.dependencies] @@ -2811,13 +2843,13 @@ test = ["pytest (>=6,!=7.0.0,!=7.0.1)", "pytest-cov (>=3.0.0)", "pytest-qt"] [[package]] name = "referencing" -version = "0.31.0" +version = "0.32.0" description = "JSON Referencing + Python" optional = false python-versions = ">=3.8" files = [ - {file = "referencing-0.31.0-py3-none-any.whl", hash = "sha256:381b11e53dd93babb55696c71cf42aef2d36b8a150c49bf0bc301e36d536c882"}, - {file = "referencing-0.31.0.tar.gz", hash = "sha256:cc28f2c88fbe7b961a7817a0abc034c09a1e36358f82fedb4ffdf29a25398863"}, + {file = "referencing-0.32.0-py3-none-any.whl", hash = "sha256:bdcd3efb936f82ff86f993093f6da7435c7de69a3b3a5a06678a6050184bee99"}, + {file = "referencing-0.32.0.tar.gz", hash = "sha256:689e64fe121843dcfd57b71933318ef1f91188ffb45367332700a86ac8fd6161"}, ] [package.dependencies] @@ -2872,136 +2904,136 @@ files = [ [[package]] name = "rpds-py" -version = "0.13.1" +version = "0.16.2" description = "Python bindings to Rust's persistent data structures (rpds)" optional = false python-versions = ">=3.8" files = [ - {file = "rpds_py-0.13.1-cp310-cp310-macosx_10_7_x86_64.whl", hash = "sha256:83feb0f682d75a09ddc11aa37ba5c07dd9b824b22915207f6176ea458474ff75"}, - {file = "rpds_py-0.13.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fa84bbe22ffa108f91631935c28a623001e335d66e393438258501e618fb0dde"}, - {file = "rpds_py-0.13.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e04f8c76b8d5c70695b4e8f1d0b391d8ef91df00ef488c6c1ffb910176459bc6"}, - {file = "rpds_py-0.13.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:032c242a595629aacace44128f9795110513ad27217b091e834edec2fb09e800"}, - {file = "rpds_py-0.13.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:91276caef95556faeb4b8f09fe4439670d3d6206fee78d47ddb6e6de837f0b4d"}, - {file = "rpds_py-0.13.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d22f2cb82e0b40e427a74a93c9a4231335bbc548aed79955dde0b64ea7f88146"}, - {file = "rpds_py-0.13.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:63c9e2794329ef070844ff9bfc012004aeddc0468dc26970953709723f76c8a5"}, - {file = "rpds_py-0.13.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c797ea56f36c6f248656f0223b11307fdf4a1886f3555eba371f34152b07677f"}, - {file = "rpds_py-0.13.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:82dbcd6463e580bcfb7561cece35046aaabeac5a9ddb775020160b14e6c58a5d"}, - {file = "rpds_py-0.13.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:736817dbbbd030a69a1faf5413a319976c9c8ba8cdcfa98c022d3b6b2e01eca6"}, - {file = "rpds_py-0.13.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:1f36a1e80ef4ed1996445698fd91e0d3e54738bf597c9995118b92da537d7a28"}, - {file = "rpds_py-0.13.1-cp310-none-win32.whl", hash = "sha256:4f13d3f6585bd07657a603780e99beda96a36c86acaba841f131e81393958336"}, - {file = "rpds_py-0.13.1-cp310-none-win_amd64.whl", hash = "sha256:545e94c84575057d3d5c62634611858dac859702b1519b6ffc58eca7fb1adfcf"}, - {file = "rpds_py-0.13.1-cp311-cp311-macosx_10_7_x86_64.whl", hash = "sha256:6bfe72b249264cc1ff2f3629be240d7d2fdc778d9d298087cdec8524c91cd11f"}, - {file = "rpds_py-0.13.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:edc91c50e17f5cd945d821f0f1af830522dba0c10267c3aab186dc3dbaab8def"}, - {file = "rpds_py-0.13.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2eca04a365be380ca1f8fa48b334462e19e3382c0bb7386444d8ca43aa01c481"}, - {file = "rpds_py-0.13.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3e3ac5b602fea378243f993d8b707189f9061e55ebb4e56cb9fdef8166060f28"}, - {file = "rpds_py-0.13.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dfb5d2ab183c0efe5e7b8917e4eaa2e837aacafad8a69b89aa6bc81550eed857"}, - {file = "rpds_py-0.13.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d9793d46d3e6522ae58e9321032827c9c0df1e56cbe5d3de965facb311aed6aa"}, - {file = "rpds_py-0.13.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9cd935c0220d012a27c20135c140f9cdcbc6249d5954345c81bfb714071b985c"}, - {file = "rpds_py-0.13.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:37b08df45f02ff1866043b95096cbe91ac99de05936dd09d6611987a82a3306a"}, - {file = "rpds_py-0.13.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:ad666a904212aa9a6c77da7dce9d5170008cda76b7776e6731928b3f8a0d40fa"}, - {file = "rpds_py-0.13.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8a6ad8429340e0a4de89353447c6441329def3632e7b2293a7d6e873217d3c2b"}, - {file = "rpds_py-0.13.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:7c40851b659d958c5245c1236e34f0d065cc53dca8d978b49a032c8e0adfda6e"}, - {file = "rpds_py-0.13.1-cp311-none-win32.whl", hash = "sha256:4145172ab59b6c27695db6d78d040795f635cba732cead19c78cede74800949a"}, - {file = "rpds_py-0.13.1-cp311-none-win_amd64.whl", hash = "sha256:46a07a258bda12270de02b34c4884f200f864bba3dcd6e3a37fef36a168b859d"}, - {file = "rpds_py-0.13.1-cp312-cp312-macosx_10_7_x86_64.whl", hash = "sha256:ba4432301ad7eeb1b00848cf46fae0e5fecfd18a8cb5fdcf856c67985f79ecc7"}, - {file = "rpds_py-0.13.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d22e0660de24bd8e9ac82f4230a22a5fe4e397265709289d61d5fb333839ba50"}, - {file = "rpds_py-0.13.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76a8374b294e4ccb39ccaf11d39a0537ed107534139c00b4393ca3b542cc66e5"}, - {file = "rpds_py-0.13.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7d152ec7bb431040af2500e01436c9aa0d993f243346f0594a15755016bf0be1"}, - {file = "rpds_py-0.13.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:74a2044b870df7c9360bb3ce7e12f9ddf8e72e49cd3a353a1528cbf166ad2383"}, - {file = "rpds_py-0.13.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:960e7e460fda2d0af18c75585bbe0c99f90b8f09963844618a621b804f8c3abe"}, - {file = "rpds_py-0.13.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:37f79f4f1f06cc96151f4a187528c3fd4a7e1065538a4af9eb68c642365957f7"}, - {file = "rpds_py-0.13.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cd4ea56c9542ad0091dfdef3e8572ae7a746e1e91eb56c9e08b8d0808b40f1d1"}, - {file = "rpds_py-0.13.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0290712eb5603a725769b5d857f7cf15cf6ca93dda3128065bbafe6fdb709beb"}, - {file = "rpds_py-0.13.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0b70c1f800059c92479dc94dda41288fd6607f741f9b1b8f89a21a86428f6383"}, - {file = "rpds_py-0.13.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3dd5fb7737224e1497c886fb3ca681c15d9c00c76171f53b3c3cc8d16ccfa7fb"}, - {file = "rpds_py-0.13.1-cp312-none-win32.whl", hash = "sha256:74be3b215a5695690a0f1a9f68b1d1c93f8caad52e23242fcb8ba56aaf060281"}, - {file = "rpds_py-0.13.1-cp312-none-win_amd64.whl", hash = "sha256:f47eef55297799956464efc00c74ae55c48a7b68236856d56183fe1ddf866205"}, - {file = "rpds_py-0.13.1-cp38-cp38-macosx_10_7_x86_64.whl", hash = "sha256:e4a45ba34f904062c63049a760790c6a2fa7a4cc4bd160d8af243b12371aaa05"}, - {file = "rpds_py-0.13.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:20147996376be452cd82cd6c17701daba69a849dc143270fa10fe067bb34562a"}, - {file = "rpds_py-0.13.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42b9535aa22ab023704cfc6533e968f7e420affe802d85e956d8a7b4c0b0b5ea"}, - {file = "rpds_py-0.13.1-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d4fa1eeb9bea6d9b64ac91ec51ee94cc4fc744955df5be393e1c923c920db2b0"}, - {file = "rpds_py-0.13.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2b2415d5a7b7ee96aa3a54d4775c1fec140476a17ee12353806297e900eaeddc"}, - {file = "rpds_py-0.13.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:577d40a72550eac1386b77b43836151cb61ff6700adacda2ad4d883ca5a0b6f2"}, - {file = "rpds_py-0.13.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:af2d1648eb625a460eee07d3e1ea3a4a6e84a1fb3a107f6a8e95ac19f7dcce67"}, - {file = "rpds_py-0.13.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5b769396eb358d6b55dbf78f3f7ca631ca1b2fe02136faad5af74f0111b4b6b7"}, - {file = "rpds_py-0.13.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:249c8e0055ca597707d71c5ad85fd2a1c8fdb99386a8c6c257e1b47b67a9bec1"}, - {file = "rpds_py-0.13.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:fe30ef31172bdcf946502a945faad110e8fff88c32c4bec9a593df0280e64d8a"}, - {file = "rpds_py-0.13.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:2647192facf63be9ed2d7a49ceb07efe01dc6cfb083bd2cc53c418437400cb99"}, - {file = "rpds_py-0.13.1-cp38-none-win32.whl", hash = "sha256:4011d5c854aa804c833331d38a2b6f6f2fe58a90c9f615afdb7aa7cf9d31f721"}, - {file = "rpds_py-0.13.1-cp38-none-win_amd64.whl", hash = "sha256:7cfae77da92a20f56cf89739a557b76e5c6edc094f6ad5c090b9e15fbbfcd1a4"}, - {file = "rpds_py-0.13.1-cp39-cp39-macosx_10_7_x86_64.whl", hash = "sha256:e9be1f7c5f9673616f875299339984da9447a40e3aea927750c843d6e5e2e029"}, - {file = "rpds_py-0.13.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:839676475ac2ccd1532d36af3d10d290a2ca149b702ed464131e450a767550df"}, - {file = "rpds_py-0.13.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a90031658805c63fe488f8e9e7a88b260ea121ba3ee9cdabcece9c9ddb50da39"}, - {file = "rpds_py-0.13.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8ba9fbc5d6e36bfeb5292530321cc56c4ef3f98048647fabd8f57543c34174ec"}, - {file = "rpds_py-0.13.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:08832078767545c5ee12561ce980714e1e4c6619b5b1e9a10248de60cddfa1fd"}, - {file = "rpds_py-0.13.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:19f5aa7f5078d35ed8e344bcba40f35bc95f9176dddb33fc4f2084e04289fa63"}, - {file = "rpds_py-0.13.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80080972e1d000ad0341c7cc58b6855c80bd887675f92871221451d13a975072"}, - {file = "rpds_py-0.13.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:181ee352691c4434eb1c01802e9daa5edcc1007ff15023a320e2693fed6a661b"}, - {file = "rpds_py-0.13.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:d20da6b4c7aa9ee75ad0730beaba15d65157f5beeaca54a038bb968f92bf3ce3"}, - {file = "rpds_py-0.13.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:faa12a9f34671a30ea6bb027f04ec4e1fb8fa3fb3ed030893e729d4d0f3a9791"}, - {file = "rpds_py-0.13.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:7cf241dbb50ea71c2e628ab2a32b5bfcd36e199152fc44e5c1edb0b773f1583e"}, - {file = "rpds_py-0.13.1-cp39-none-win32.whl", hash = "sha256:dab979662da1c9fbb464e310c0b06cb5f1d174d09a462553af78f0bfb3e01920"}, - {file = "rpds_py-0.13.1-cp39-none-win_amd64.whl", hash = "sha256:a2b3c79586636f1fa69a7bd59c87c15fca80c0d34b5c003d57f2f326e5276575"}, - {file = "rpds_py-0.13.1-pp310-pypy310_pp73-macosx_10_7_x86_64.whl", hash = "sha256:5967fa631d0ed9f8511dede08bc943a9727c949d05d1efac4ac82b2938024fb7"}, - {file = "rpds_py-0.13.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:8308a8d49d1354278d5c068c888a58d7158a419b2e4d87c7839ed3641498790c"}, - {file = "rpds_py-0.13.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d0580faeb9def6d0beb7aa666294d5604e569c4e24111ada423cf9936768d95c"}, - {file = "rpds_py-0.13.1-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2da81c1492291c1a90987d76a47c7b2d310661bf7c93a9de0511e27b796a8b46"}, - {file = "rpds_py-0.13.1-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1c9a1dc5e898ce30e2f9c0aa57181cddd4532b22b7780549441d6429d22d3b58"}, - {file = "rpds_py-0.13.1-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f4ae6f423cb7d1c6256b7482025ace2825728f53b7ac58bcd574de6ee9d242c2"}, - {file = "rpds_py-0.13.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc3179e0815827cf963e634095ae5715ee73a5af61defbc8d6ca79f1bdae1d1d"}, - {file = "rpds_py-0.13.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0d9f8930092558fd15c9e07198625efb698f7cc00b3dc311c83eeec2540226a8"}, - {file = "rpds_py-0.13.1-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:d1d388d2f5f5a6065cf83c54dd12112b7389095669ff395e632003ae8999c6b8"}, - {file = "rpds_py-0.13.1-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:08b335fb0c45f0a9e2478a9ece6a1bfb00b6f4c4780f9be3cf36479c5d8dd374"}, - {file = "rpds_py-0.13.1-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:d11afdc5992bbd7af60ed5eb519873690d921425299f51d80aa3099ed49f2bcc"}, - {file = "rpds_py-0.13.1-pp38-pypy38_pp73-macosx_10_7_x86_64.whl", hash = "sha256:8c1f6c8df23be165eb0cb78f305483d00c6827a191e3a38394c658d5b9c80bbd"}, - {file = "rpds_py-0.13.1-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:528e2afaa56d815d2601b857644aeb395afe7e59212ab0659906dc29ae68d9a6"}, - {file = "rpds_py-0.13.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:df2af1180b8eeececf4f819d22cc0668bfadadfd038b19a90bd2fb2ee419ec6f"}, - {file = "rpds_py-0.13.1-pp38-pypy38_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:88956c993a20201744282362e3fd30962a9d86dc4f1dcf2bdb31fab27821b61f"}, - {file = "rpds_py-0.13.1-pp38-pypy38_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ee70ee5f4144a45a9e6169000b5b525d82673d5dab9f7587eccc92794814e7ac"}, - {file = "rpds_py-0.13.1-pp38-pypy38_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c5fd099acaee2325f01281a130a39da08d885e4dedf01b84bf156ec2737d78fe"}, - {file = "rpds_py-0.13.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9656a09653b18b80764647d585750df2dff8928e03a706763ab40ec8c4872acc"}, - {file = "rpds_py-0.13.1-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7ba239bb37663b2b4cd08e703e79e13321512dccd8e5f0e9451d9e53a6b8509a"}, - {file = "rpds_py-0.13.1-pp38-pypy38_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:3f55ae773abd96b1de25fc5c3fb356f491bd19116f8f854ba705beffc1ddc3c5"}, - {file = "rpds_py-0.13.1-pp38-pypy38_pp73-musllinux_1_2_i686.whl", hash = "sha256:f4b15a163448ec79241fb2f1bc5a8ae1a4a304f7a48d948d208a2935b26bf8a5"}, - {file = "rpds_py-0.13.1-pp38-pypy38_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:1a3b2583c86bbfbf417304eeb13400ce7f8725376dc7d3efbf35dc5d7052ad48"}, - {file = "rpds_py-0.13.1-pp39-pypy39_pp73-macosx_10_7_x86_64.whl", hash = "sha256:f1059ca9a51c936c9a8d46fbc2c9a6b4c15ab3f13a97f1ad32f024b39666ba85"}, - {file = "rpds_py-0.13.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:f55601fb58f92e4f4f1d05d80c24cb77505dc42103ddfd63ddfdc51d3da46fa2"}, - {file = "rpds_py-0.13.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fcfd5f91b882eedf8d9601bd21261d6ce0e61a8c66a7152d1f5df08d3f643ab1"}, - {file = "rpds_py-0.13.1-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6574f619e8734140d96c59bfa8a6a6e7a3336820ccd1bfd95ffa610673b650a2"}, - {file = "rpds_py-0.13.1-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a4b9d3f5c48bbe8d9e3758e498b3c34863f2c9b1ac57a4e6310183740e59c980"}, - {file = "rpds_py-0.13.1-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cdd6f8738e1f1d9df5b1603bb03cb30e442710e5672262b95d0f9fcb4edb0dab"}, - {file = "rpds_py-0.13.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8c2bf286e5d755a075e5e97ba56b3de08cccdad6b323ab0b21cc98875176b03"}, - {file = "rpds_py-0.13.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b3d4b390ee70ca9263b331ccfaf9819ee20e90dfd0201a295e23eb64a005dbef"}, - {file = "rpds_py-0.13.1-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:db8d0f0ad92f74feb61c4e4a71f1d573ef37c22ef4dc19cab93e501bfdad8cbd"}, - {file = "rpds_py-0.13.1-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:2abd669a39be69cdfe145927c7eb53a875b157740bf1e2d49e9619fc6f43362e"}, - {file = "rpds_py-0.13.1-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:2c173f529666bab8e3f948b74c6d91afa22ea147e6ebae49a48229d9020a47c4"}, - {file = "rpds_py-0.13.1.tar.gz", hash = "sha256:264f3a5906c62b9df3a00ad35f6da1987d321a053895bd85f9d5c708de5c0fbf"}, + {file = "rpds_py-0.16.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:509b617ac787cd1149600e731db9274ebbef094503ca25158e6f23edaba1ca8f"}, + {file = "rpds_py-0.16.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:413b9c17388bbd0d87a329d8e30c1a4c6e44e2bb25457f43725a8e6fe4161e9e"}, + {file = "rpds_py-0.16.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2946b120718eba9af2b4dd103affc1164a87b9e9ebff8c3e4c05d7b7a7e274e2"}, + {file = "rpds_py-0.16.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:35ae5ece284cf36464eb160880018cf6088a9ac5ddc72292a6092b6ef3f4da53"}, + {file = "rpds_py-0.16.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3dc6a7620ba7639a3db6213da61312cb4aa9ac0ca6e00dc1cbbdc21c2aa6eb57"}, + {file = "rpds_py-0.16.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8cb6fe8ecdfffa0e711a75c931fb39f4ba382b4b3ccedeca43f18693864fe850"}, + {file = "rpds_py-0.16.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6dace7b26a13353e24613417ce2239491b40a6ad44e5776a18eaff7733488b44"}, + {file = "rpds_py-0.16.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1bdbc5fcb04a7309074de6b67fa9bc4b418ab3fc435fec1f2779a0eced688d04"}, + {file = "rpds_py-0.16.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f42e25c016927e2a6b1ce748112c3ab134261fc2ddc867e92d02006103e1b1b7"}, + {file = "rpds_py-0.16.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:eab36eae3f3e8e24b05748ec9acc66286662f5d25c52ad70cadab544e034536b"}, + {file = "rpds_py-0.16.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:0474df4ade9a3b4af96c3d36eb81856cb9462e4c6657d4caecfd840d2a13f3c9"}, + {file = "rpds_py-0.16.2-cp310-none-win32.whl", hash = "sha256:84c5a4d1f9dd7e2d2c44097fb09fffe728629bad31eb56caf97719e55575aa82"}, + {file = "rpds_py-0.16.2-cp310-none-win_amd64.whl", hash = "sha256:2bd82db36cd70b3628c0c57d81d2438e8dd4b7b32a6a9f25f24ab0e657cb6c4e"}, + {file = "rpds_py-0.16.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:adc0c3d6fc6ae35fee3e4917628983f6ce630d513cbaad575b4517d47e81b4bb"}, + {file = "rpds_py-0.16.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ec23fcad480e77ede06cf4127a25fc440f7489922e17fc058f426b5256ee0edb"}, + {file = "rpds_py-0.16.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:07aab64e2808c3ebac2a44f67e9dc0543812b715126dfd6fe4264df527556cb6"}, + {file = "rpds_py-0.16.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a4ebb8b20bd09c5ce7884c8f0388801100f5e75e7f733b1b6613c713371feefc"}, + {file = "rpds_py-0.16.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a3d7e2ea25d3517c6d7e5a1cc3702cffa6bd18d9ef8d08d9af6717fc1c700eed"}, + {file = "rpds_py-0.16.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f28ac0e8e7242d140f99402a903a2c596ab71550272ae9247ad78f9a932b5698"}, + {file = "rpds_py-0.16.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:19f00f57fdd38db4bb5ad09f9ead1b535332dbf624200e9029a45f1f35527ebb"}, + {file = "rpds_py-0.16.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3da5a4c56953bdbf6d04447c3410309616c54433146ccdb4a277b9cb499bc10e"}, + {file = "rpds_py-0.16.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:ec2e1cf025b2c0f48ec17ff3e642661da7ee332d326f2e6619366ce8e221f018"}, + {file = "rpds_py-0.16.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e0441fb4fdd39a230477b2ca9be90868af64425bfe7b122b57e61e45737a653b"}, + {file = "rpds_py-0.16.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9f0350ef2fba5f34eb0c9000ea328e51b9572b403d2f7f3b19f24085f6f598e8"}, + {file = "rpds_py-0.16.2-cp311-none-win32.whl", hash = "sha256:5a80e2f83391ad0808b4646732af2a7b67550b98f0cae056cb3b40622a83dbb3"}, + {file = "rpds_py-0.16.2-cp311-none-win_amd64.whl", hash = "sha256:e04e56b4ca7a770593633556e8e9e46579d66ec2ada846b401252a2bdcf70a6d"}, + {file = "rpds_py-0.16.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:5e6caa3809e50690bd92fa490f5c38caa86082c8c3315aa438bce43786d5e90d"}, + {file = "rpds_py-0.16.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2e53b9b25cac9065328901713a7e9e3b12e4f57ef4280b370fbbf6fef2052eef"}, + {file = "rpds_py-0.16.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:af27423662f32d7501a00c5e7342f7dbd1e4a718aea7a239781357d15d437133"}, + {file = "rpds_py-0.16.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:43d4dd5fb16eb3825742bad8339d454054261ab59fed2fbac84e1d84d5aae7ba"}, + {file = "rpds_py-0.16.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e061de3b745fe611e23cd7318aec2c8b0e4153939c25c9202a5811ca911fd733"}, + {file = "rpds_py-0.16.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3b811d182ad17ea294f2ec63c0621e7be92a1141e1012383461872cead87468f"}, + {file = "rpds_py-0.16.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5552f328eaef1a75ff129d4d0c437bf44e43f9436d3996e8eab623ea0f5fcf73"}, + {file = "rpds_py-0.16.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:dcbe1f8dd179e4d69b70b1f1d9bb6fd1e7e1bdc9c9aad345cdeb332e29d40748"}, + {file = "rpds_py-0.16.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8aad80645a011abae487d356e0ceb359f4938dfb6f7bcc410027ed7ae4f7bb8b"}, + {file = "rpds_py-0.16.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b6f5549d6ed1da9bfe3631ca9483ae906f21410be2445b73443fa9f017601c6f"}, + {file = "rpds_py-0.16.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:d452817e0d9c749c431a1121d56a777bd7099b720b3d1c820f1725cb40928f58"}, + {file = "rpds_py-0.16.2-cp312-none-win32.whl", hash = "sha256:888a97002e986eca10d8546e3c8b97da1d47ad8b69726dcfeb3e56348ebb28a3"}, + {file = "rpds_py-0.16.2-cp312-none-win_amd64.whl", hash = "sha256:d8dda2a806dfa4a9b795950c4f5cc56d6d6159f7d68080aedaff3bdc9b5032f5"}, + {file = "rpds_py-0.16.2-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:071980663c273bf3d388fe5c794c547e6f35ba3335477072c713a3176bf14a60"}, + {file = "rpds_py-0.16.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:726ac36e8a3bb8daef2fd482534cabc5e17334052447008405daca7ca04a3108"}, + {file = "rpds_py-0.16.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e9e557db6a177470316c82f023e5d571811c9a4422b5ea084c85da9aa3c035fc"}, + {file = "rpds_py-0.16.2-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:90123853fc8b1747f80b0d354be3d122b4365a93e50fc3aacc9fb4c2488845d6"}, + {file = "rpds_py-0.16.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a61f659665a39a4d17d699ab3593d7116d66e1e2e3f03ef3fb8f484e91908808"}, + {file = "rpds_py-0.16.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cc97f0640e91d7776530f06e6836c546c1c752a52de158720c4224c9e8053cad"}, + {file = "rpds_py-0.16.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:44a54e99a2b9693a37ebf245937fd6e9228b4cbd64b9cc961e1f3391ec6c7391"}, + {file = "rpds_py-0.16.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bd4b677d929cf1f6bac07ad76e0f2d5de367e6373351c01a9c0a39f6b21b4a8b"}, + {file = "rpds_py-0.16.2-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:5ef00873303d678aaf8b0627e111fd434925ca01c657dbb2641410f1cdaef261"}, + {file = "rpds_py-0.16.2-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:349cb40897fd529ca15317c22c0eab67f5ac5178b5bd2c6adc86172045210acc"}, + {file = "rpds_py-0.16.2-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:2ddef620e70eaffebed5932ce754d539c0930f676aae6212f8e16cd9743dd365"}, + {file = "rpds_py-0.16.2-cp38-none-win32.whl", hash = "sha256:882ce6e25e585949c3d9f9abd29202367175e0aab3aba0c58c9abbb37d4982ff"}, + {file = "rpds_py-0.16.2-cp38-none-win_amd64.whl", hash = "sha256:f4bd4578e44f26997e9e56c96dedc5f1af43cc9d16c4daa29c771a00b2a26851"}, + {file = "rpds_py-0.16.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:69ac7ea9897ec201ce68b48582f3eb34a3f9924488a5432a93f177bf76a82a7e"}, + {file = "rpds_py-0.16.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a9880b4656efe36ccad41edc66789e191e5ee19a1ea8811e0aed6f69851a82f4"}, + {file = "rpds_py-0.16.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ee94cb58c0ba2c62ee108c2b7c9131b2c66a29e82746e8fa3aa1a1effbd3dcf1"}, + {file = "rpds_py-0.16.2-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:24f7a2eb3866a9e91f4599851e0c8d39878a470044875c49bd528d2b9b88361c"}, + {file = "rpds_py-0.16.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ca57468da2d9a660bcf8961637c85f2fbb2aa64d9bc3f9484e30c3f9f67b1dd7"}, + {file = "rpds_py-0.16.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ccd4e400309e1f34a5095bf9249d371f0fd60f8a3a5c4a791cad7b99ce1fd38d"}, + {file = "rpds_py-0.16.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80443fe2f7b3ea3934c5d75fb0e04a5dbb4a8e943e5ff2de0dec059202b70a8b"}, + {file = "rpds_py-0.16.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4d6a9f052e72d493efd92a77f861e45bab2f6be63e37fa8ecf0c6fd1a58fedb0"}, + {file = "rpds_py-0.16.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:35953f4f2b3216421af86fd236b7c0c65935936a94ea83ddbd4904ba60757773"}, + {file = "rpds_py-0.16.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:981d135c7cdaf6cd8eadae1c950de43b976de8f09d8e800feed307140d3d6d00"}, + {file = "rpds_py-0.16.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:d0dd7ed2f16df2e129496e7fbe59a34bc2d7fc8db443a606644d069eb69cbd45"}, + {file = "rpds_py-0.16.2-cp39-none-win32.whl", hash = "sha256:703d95c75a72e902544fda08e965885525e297578317989fd15a6ce58414b41d"}, + {file = "rpds_py-0.16.2-cp39-none-win_amd64.whl", hash = "sha256:e93ec1b300acf89730cf27975ef574396bc04edecc358e9bd116fb387a123239"}, + {file = "rpds_py-0.16.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:44627b6ca7308680a70766454db5249105fa6344853af6762eaad4158a2feebe"}, + {file = "rpds_py-0.16.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:3f91df8e6dbb7360e176d1affd5fb0246d2b88d16aa5ebc7db94fd66b68b61da"}, + {file = "rpds_py-0.16.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6d904c5693e08bad240f16d79305edba78276be87061c872a4a15e2c301fa2c0"}, + {file = "rpds_py-0.16.2-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:290a81cfbe4673285cdf140ec5cd1658ffbf63ab359f2b352ebe172e7cfa5bf0"}, + {file = "rpds_py-0.16.2-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b634c5ec0103c5cbebc24ebac4872b045cccb9456fc59efdcf6fe39775365bd2"}, + {file = "rpds_py-0.16.2-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a297a4d08cc67c7466c873c78039d87840fb50d05473db0ec1b7b03d179bf322"}, + {file = "rpds_py-0.16.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b2e75e17bd0bb66ee34a707da677e47c14ee51ccef78ed6a263a4cc965a072a1"}, + {file = "rpds_py-0.16.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f1b9d9260e06ea017feb7172976ab261e011c1dc2f8883c7c274f6b2aabfe01a"}, + {file = "rpds_py-0.16.2-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:162d7cd9cd311c1b0ff1c55a024b8f38bd8aad1876b648821da08adc40e95734"}, + {file = "rpds_py-0.16.2-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:9b32f742ce5b57201305f19c2ef7a184b52f6f9ba6871cc042c2a61f0d6b49b8"}, + {file = "rpds_py-0.16.2-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:ac08472f41ea77cd6a5dae36ae7d4ed3951d6602833af87532b556c1b4601d63"}, + {file = "rpds_py-0.16.2-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:495a14b72bbe217f2695dcd9b5ab14d4f8066a00f5d209ed94f0aca307f85f6e"}, + {file = "rpds_py-0.16.2-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:8d6b6937ae9eac6d6c0ca3c42774d89fa311f55adff3970fb364b34abde6ed3d"}, + {file = "rpds_py-0.16.2-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6a61226465bda9283686db8f17d02569a98e4b13c637be5a26d44aa1f1e361c2"}, + {file = "rpds_py-0.16.2-pp38-pypy38_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5cf6af100ffb5c195beec11ffaa8cf8523057f123afa2944e6571d54da84cdc9"}, + {file = "rpds_py-0.16.2-pp38-pypy38_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6df15846ee3fb2e6397fe25d7ca6624af9f89587f3f259d177b556fed6bebe2c"}, + {file = "rpds_py-0.16.2-pp38-pypy38_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1be2f033df1b8be8c3167ba3c29d5dca425592ee31e35eac52050623afba5772"}, + {file = "rpds_py-0.16.2-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:96f957d6ab25a78b9e7fc9749d754b98eac825a112b4e666525ce89afcbd9ed5"}, + {file = "rpds_py-0.16.2-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:088396c7c70e59872f67462fcac3ecbded5233385797021976a09ebd55961dfe"}, + {file = "rpds_py-0.16.2-pp38-pypy38_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:4c46ad6356e1561f2a54f08367d1d2e70a0a1bb2db2282d2c1972c1d38eafc3b"}, + {file = "rpds_py-0.16.2-pp38-pypy38_pp73-musllinux_1_2_i686.whl", hash = "sha256:47713dc4fce213f5c74ca8a1f6a59b622fc1b90868deb8e8e4d993e421b4b39d"}, + {file = "rpds_py-0.16.2-pp38-pypy38_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:f811771019f063bbd0aa7bb72c8a934bc13ebacb4672d712fc1639cfd314cccc"}, + {file = "rpds_py-0.16.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:f19afcfc0dd0dca35694df441e9b0f95bc231b512f51bded3c3d8ca32153ec19"}, + {file = "rpds_py-0.16.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:a4b682c5775d6a3d21e314c10124599976809455ee67020e8e72df1769b87bc3"}, + {file = "rpds_py-0.16.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c647ca87fc0ebe808a41de912e9a1bfef9acb85257e5d63691364ac16b81c1f0"}, + {file = "rpds_py-0.16.2-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:302bd4983bbd47063e452c38be66153760112f6d3635c7eeefc094299fa400a9"}, + {file = "rpds_py-0.16.2-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bf721ede3eb7b829e4a9b8142bd55db0bdc82902720548a703f7e601ee13bdc3"}, + {file = "rpds_py-0.16.2-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:358dafc89ce3894c7f486c615ba914609f38277ef67f566abc4c854d23b997fa"}, + {file = "rpds_py-0.16.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cad0f59ee3dc35526039f4bc23642d52d5f6616b5f687d846bfc6d0d6d486db0"}, + {file = "rpds_py-0.16.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cffa76b385dfe1e38527662a302b19ffb0e7f5cf7dd5e89186d2c94a22dd9d0c"}, + {file = "rpds_py-0.16.2-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:83640a5d7cd3bff694747d50436b8b541b5b9b9782b0c8c1688931d6ee1a1f2d"}, + {file = "rpds_py-0.16.2-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:ed99b4f7179d2111702020fd7d156e88acd533f5a7d3971353e568b6051d5c97"}, + {file = "rpds_py-0.16.2-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:4022b9dc620e14f30201a8a73898a873c8e910cb642bcd2f3411123bc527f6ac"}, + {file = "rpds_py-0.16.2.tar.gz", hash = "sha256:781ef8bfc091b19960fc0142a23aedadafa826bc32b433fdfe6fd7f964d7ef44"}, ] [[package]] name = "ruff" -version = "0.1.6" +version = "0.1.11" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" files = [ - {file = "ruff-0.1.6-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:88b8cdf6abf98130991cbc9f6438f35f6e8d41a02622cc5ee130a02a0ed28703"}, - {file = "ruff-0.1.6-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:5c549ed437680b6105a1299d2cd30e4964211606eeb48a0ff7a93ef70b902248"}, - {file = "ruff-0.1.6-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1cf5f701062e294f2167e66d11b092bba7af6a057668ed618a9253e1e90cfd76"}, - {file = "ruff-0.1.6-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:05991ee20d4ac4bb78385360c684e4b417edd971030ab12a4fbd075ff535050e"}, - {file = "ruff-0.1.6-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:87455a0c1f739b3c069e2f4c43b66479a54dea0276dd5d4d67b091265f6fd1dc"}, - {file = "ruff-0.1.6-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:683aa5bdda5a48cb8266fcde8eea2a6af4e5700a392c56ea5fb5f0d4bfdc0240"}, - {file = "ruff-0.1.6-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:137852105586dcbf80c1717facb6781555c4e99f520c9c827bd414fac67ddfb6"}, - {file = "ruff-0.1.6-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bd98138a98d48a1c36c394fd6b84cd943ac92a08278aa8ac8c0fdefcf7138f35"}, - {file = "ruff-0.1.6-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a0cd909d25f227ac5c36d4e7e681577275fb74ba3b11d288aff7ec47e3ae745"}, - {file = "ruff-0.1.6-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:e8fd1c62a47aa88a02707b5dd20c5ff20d035d634aa74826b42a1da77861b5ff"}, - {file = "ruff-0.1.6-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:fd89b45d374935829134a082617954120d7a1470a9f0ec0e7f3ead983edc48cc"}, - {file = "ruff-0.1.6-py3-none-musllinux_1_2_i686.whl", hash = "sha256:491262006e92f825b145cd1e52948073c56560243b55fb3b4ecb142f6f0e9543"}, - {file = "ruff-0.1.6-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:ea284789861b8b5ca9d5443591a92a397ac183d4351882ab52f6296b4fdd5462"}, - {file = "ruff-0.1.6-py3-none-win32.whl", hash = "sha256:1610e14750826dfc207ccbcdd7331b6bd285607d4181df9c1c6ae26646d6848a"}, - {file = "ruff-0.1.6-py3-none-win_amd64.whl", hash = "sha256:4558b3e178145491e9bc3b2ee3c4b42f19d19384eaa5c59d10acf6e8f8b57e33"}, - {file = "ruff-0.1.6-py3-none-win_arm64.whl", hash = "sha256:03910e81df0d8db0e30050725a5802441c2022ea3ae4fe0609b76081731accbc"}, - {file = "ruff-0.1.6.tar.gz", hash = "sha256:1b09f29b16c6ead5ea6b097ef2764b42372aebe363722f1605ecbcd2b9207184"}, + {file = "ruff-0.1.11-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:a7f772696b4cdc0a3b2e527fc3c7ccc41cdcb98f5c80fdd4f2b8c50eb1458196"}, + {file = "ruff-0.1.11-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:934832f6ed9b34a7d5feea58972635c2039c7a3b434fe5ba2ce015064cb6e955"}, + {file = "ruff-0.1.11-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ea0d3e950e394c4b332bcdd112aa566010a9f9c95814844a7468325290aabfd9"}, + {file = "ruff-0.1.11-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9bd4025b9c5b429a48280785a2b71d479798a69f5c2919e7d274c5f4b32c3607"}, + {file = "ruff-0.1.11-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e1ad00662305dcb1e987f5ec214d31f7d6a062cae3e74c1cbccef15afd96611d"}, + {file = "ruff-0.1.11-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:4b077ce83f47dd6bea1991af08b140e8b8339f0ba8cb9b7a484c30ebab18a23f"}, + {file = "ruff-0.1.11-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c4a88efecec23c37b11076fe676e15c6cdb1271a38f2b415e381e87fe4517f18"}, + {file = "ruff-0.1.11-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5b25093dad3b055667730a9b491129c42d45e11cdb7043b702e97125bcec48a1"}, + {file = "ruff-0.1.11-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:231d8fb11b2cc7c0366a326a66dafc6ad449d7fcdbc268497ee47e1334f66f77"}, + {file = "ruff-0.1.11-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:09c415716884950080921dd6237767e52e227e397e2008e2bed410117679975b"}, + {file = "ruff-0.1.11-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:0f58948c6d212a6b8d41cd59e349751018797ce1727f961c2fa755ad6208ba45"}, + {file = "ruff-0.1.11-py3-none-musllinux_1_2_i686.whl", hash = "sha256:190a566c8f766c37074d99640cd9ca3da11d8deae2deae7c9505e68a4a30f740"}, + {file = "ruff-0.1.11-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:6464289bd67b2344d2a5d9158d5eb81025258f169e69a46b741b396ffb0cda95"}, + {file = "ruff-0.1.11-py3-none-win32.whl", hash = "sha256:9b8f397902f92bc2e70fb6bebfa2139008dc72ae5177e66c383fa5426cb0bf2c"}, + {file = "ruff-0.1.11-py3-none-win_amd64.whl", hash = "sha256:eb85ee287b11f901037a6683b2374bb0ec82928c5cbc984f575d0437979c521a"}, + {file = "ruff-0.1.11-py3-none-win_arm64.whl", hash = "sha256:97ce4d752f964ba559c7023a86e5f8e97f026d511e48013987623915431c7ea9"}, + {file = "ruff-0.1.11.tar.gz", hash = "sha256:f9d4d88cb6eeb4dfe20f9f0519bd2eaba8119bde87c3d5065c541dbae2b5a2cb"}, ] [[package]] @@ -3020,22 +3052,6 @@ nativelib = ["pyobjc-framework-Cocoa", "pywin32"] objc = ["pyobjc-framework-Cocoa"] win32 = ["pywin32"] -[[package]] -name = "setuptools" -version = "69.0.2" -description = "Easily download, build, install, upgrade, and uninstall Python packages" -optional = false -python-versions = ">=3.8" -files = [ - {file = "setuptools-69.0.2-py3-none-any.whl", hash = "sha256:1e8fdff6797d3865f37397be788a4e3cba233608e9b509382a2777d25ebde7f2"}, - {file = "setuptools-69.0.2.tar.gz", hash = "sha256:735896e78a4742605974de002ac60562d286fa8051a7e2299445e8e8fbb01aa6"}, -] - -[package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] -testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] -testing-integration = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.1)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] - [[package]] name = "six" version = "1.16.0" @@ -3295,13 +3311,13 @@ telegram = ["requests"] [[package]] name = "traitlets" -version = "5.14.0" +version = "5.14.1" description = "Traitlets Python configuration system" optional = false python-versions = ">=3.8" files = [ - {file = "traitlets-5.14.0-py3-none-any.whl", hash = "sha256:f14949d23829023013c47df20b4a76ccd1a85effb786dc060f34de7948361b33"}, - {file = "traitlets-5.14.0.tar.gz", hash = "sha256:fcdaa8ac49c04dfa0ed3ee3384ef6dfdb5d6f3741502be247279407679296772"}, + {file = "traitlets-5.14.1-py3-none-any.whl", hash = "sha256:2e5a030e6eff91737c643231bfcf04a65b0132078dad75e4936700b213652e74"}, + {file = "traitlets-5.14.1.tar.gz", hash = "sha256:8585105b371a04b8316a43d5ce29c098575c2e477850b62b848b964f1444527e"}, ] [package.extras] @@ -3319,15 +3335,29 @@ files = [ {file = "types_python_dateutil-2.8.19.14-py3-none-any.whl", hash = "sha256:f977b8de27787639986b4e28963263fd0e5158942b3ecef91b9335c130cb1ce9"}, ] +[[package]] +name = "types-requests" +version = "2.31.0.20231231" +description = "Typing stubs for requests" +optional = false +python-versions = ">=3.7" +files = [ + {file = "types-requests-2.31.0.20231231.tar.gz", hash = "sha256:0f8c0c9764773384122813548d9eea92a5c4e1f33ed54556b508968ec5065cee"}, + {file = "types_requests-2.31.0.20231231-py3-none-any.whl", hash = "sha256:2e2230c7bc8dd63fa3153c1c0ae335f8a368447f0582fc332f17d54f88e69027"}, +] + +[package.dependencies] +urllib3 = ">=2" + [[package]] name = "typing-extensions" -version = "4.8.0" +version = "4.9.0" description = "Backported and Experimental Type Hints for Python 3.8+" optional = false python-versions = ">=3.8" files = [ - {file = "typing_extensions-4.8.0-py3-none-any.whl", hash = "sha256:8f92fc8806f9a6b641eaa5318da32b44d401efaac0f6678c9bc448ba3605faa0"}, - {file = "typing_extensions-4.8.0.tar.gz", hash = "sha256:df8e4339e9cb77357558cbdbceca33c303714cf861d1eef15e1070055ae8b7ef"}, + {file = "typing_extensions-4.9.0-py3-none-any.whl", hash = "sha256:af72aea155e91adfc61c3ae9e0e342dbc0cba726d6cba4b6c72c1f34e47291cd"}, + {file = "typing_extensions-4.9.0.tar.gz", hash = "sha256:23478f88c37f27d76ac8aee6c905017a143b0b1b886c3c9f66bc2fd94f9f5783"}, ] [[package]] @@ -3453,13 +3483,13 @@ files = [ [[package]] name = "websocket-client" -version = "1.6.4" +version = "1.7.0" description = "WebSocket client for Python with low level API options" optional = false python-versions = ">=3.8" files = [ - {file = "websocket-client-1.6.4.tar.gz", hash = "sha256:b3324019b3c28572086c4a319f91d1dcd44e6e11cd340232978c684a7650d0df"}, - {file = "websocket_client-1.6.4-py3-none-any.whl", hash = "sha256:084072e0a7f5f347ef2ac3d8698a5e0b4ffbfcab607628cadabc650fc9a83a24"}, + {file = "websocket-client-1.7.0.tar.gz", hash = "sha256:10e511ea3a8c744631d3bd77e61eb17ed09304c413ad42cf6ddfa4c7787e8fe6"}, + {file = "websocket_client-1.7.0-py3-none-any.whl", hash = "sha256:f4c3d22fec12a2461427a29957ff07d35098ee2d976d3ba244e688b8b4057588"}, ] [package.extras] @@ -3480,101 +3510,101 @@ files = [ [[package]] name = "yarl" -version = "1.9.3" +version = "1.9.4" description = "Yet another URL library" optional = false python-versions = ">=3.7" files = [ - {file = "yarl-1.9.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:32435d134414e01d937cd9d6cc56e8413a8d4741dea36af5840c7750f04d16ab"}, - {file = "yarl-1.9.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9a5211de242754b5e612557bca701f39f8b1a9408dff73c6db623f22d20f470e"}, - {file = "yarl-1.9.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:525cd69eff44833b01f8ef39aa33a9cc53a99ff7f9d76a6ef6a9fb758f54d0ff"}, - {file = "yarl-1.9.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fc94441bcf9cb8c59f51f23193316afefbf3ff858460cb47b5758bf66a14d130"}, - {file = "yarl-1.9.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e36021db54b8a0475805acc1d6c4bca5d9f52c3825ad29ae2d398a9d530ddb88"}, - {file = "yarl-1.9.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e0f17d1df951336a02afc8270c03c0c6e60d1f9996fcbd43a4ce6be81de0bd9d"}, - {file = "yarl-1.9.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c5f3faeb8100a43adf3e7925d556801d14b5816a0ac9e75e22948e787feec642"}, - {file = "yarl-1.9.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aed37db837ecb5962469fad448aaae0f0ee94ffce2062cf2eb9aed13328b5196"}, - {file = "yarl-1.9.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:721ee3fc292f0d069a04016ef2c3a25595d48c5b8ddc6029be46f6158d129c92"}, - {file = "yarl-1.9.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:b8bc5b87a65a4e64bc83385c05145ea901b613d0d3a434d434b55511b6ab0067"}, - {file = "yarl-1.9.3-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:dd952b9c64f3b21aedd09b8fe958e4931864dba69926d8a90c90d36ac4e28c9a"}, - {file = "yarl-1.9.3-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:c405d482c320a88ab53dcbd98d6d6f32ada074f2d965d6e9bf2d823158fa97de"}, - {file = "yarl-1.9.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:9df9a0d4c5624790a0dea2e02e3b1b3c69aed14bcb8650e19606d9df3719e87d"}, - {file = "yarl-1.9.3-cp310-cp310-win32.whl", hash = "sha256:d34c4f80956227f2686ddea5b3585e109c2733e2d4ef12eb1b8b4e84f09a2ab6"}, - {file = "yarl-1.9.3-cp310-cp310-win_amd64.whl", hash = "sha256:cf7a4e8de7f1092829caef66fd90eaf3710bc5efd322a816d5677b7664893c93"}, - {file = "yarl-1.9.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:d61a0ca95503867d4d627517bcfdc28a8468c3f1b0b06c626f30dd759d3999fd"}, - {file = "yarl-1.9.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:73cc83f918b69110813a7d95024266072d987b903a623ecae673d1e71579d566"}, - {file = "yarl-1.9.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d81657b23e0edb84b37167e98aefb04ae16cbc5352770057893bd222cdc6e45f"}, - {file = "yarl-1.9.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:26a1a8443091c7fbc17b84a0d9f38de34b8423b459fb853e6c8cdfab0eacf613"}, - {file = "yarl-1.9.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fe34befb8c765b8ce562f0200afda3578f8abb159c76de3ab354c80b72244c41"}, - {file = "yarl-1.9.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2c757f64afe53a422e45e3e399e1e3cf82b7a2f244796ce80d8ca53e16a49b9f"}, - {file = "yarl-1.9.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:72a57b41a0920b9a220125081c1e191b88a4cdec13bf9d0649e382a822705c65"}, - {file = "yarl-1.9.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:632c7aeb99df718765adf58eacb9acb9cbc555e075da849c1378ef4d18bf536a"}, - {file = "yarl-1.9.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:b0b8c06afcf2bac5a50b37f64efbde978b7f9dc88842ce9729c020dc71fae4ce"}, - {file = "yarl-1.9.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:1d93461e2cf76c4796355494f15ffcb50a3c198cc2d601ad8d6a96219a10c363"}, - {file = "yarl-1.9.3-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:4003f380dac50328c85e85416aca6985536812c082387255c35292cb4b41707e"}, - {file = "yarl-1.9.3-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4d6d74a97e898c1c2df80339aa423234ad9ea2052f66366cef1e80448798c13d"}, - {file = "yarl-1.9.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:b61e64b06c3640feab73fa4ff9cb64bd8182de52e5dc13038e01cfe674ebc321"}, - {file = "yarl-1.9.3-cp311-cp311-win32.whl", hash = "sha256:29beac86f33d6c7ab1d79bd0213aa7aed2d2f555386856bb3056d5fdd9dab279"}, - {file = "yarl-1.9.3-cp311-cp311-win_amd64.whl", hash = "sha256:f7271d6bd8838c49ba8ae647fc06469137e1c161a7ef97d778b72904d9b68696"}, - {file = "yarl-1.9.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:dd318e6b75ca80bff0b22b302f83a8ee41c62b8ac662ddb49f67ec97e799885d"}, - {file = "yarl-1.9.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c4b1efb11a8acd13246ffb0bee888dd0e8eb057f8bf30112e3e21e421eb82d4a"}, - {file = "yarl-1.9.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c6f034386e5550b5dc8ded90b5e2ff7db21f0f5c7de37b6efc5dac046eb19c10"}, - {file = "yarl-1.9.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cd49a908cb6d387fc26acee8b7d9fcc9bbf8e1aca890c0b2fdfd706057546080"}, - {file = "yarl-1.9.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aa4643635f26052401750bd54db911b6342eb1a9ac3e74f0f8b58a25d61dfe41"}, - {file = "yarl-1.9.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e741bd48e6a417bdfbae02e088f60018286d6c141639359fb8df017a3b69415a"}, - {file = "yarl-1.9.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7c86d0d0919952d05df880a1889a4f0aeb6868e98961c090e335671dea5c0361"}, - {file = "yarl-1.9.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3d5434b34100b504aabae75f0622ebb85defffe7b64ad8f52b8b30ec6ef6e4b9"}, - {file = "yarl-1.9.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:79e1df60f7c2b148722fb6cafebffe1acd95fd8b5fd77795f56247edaf326752"}, - {file = "yarl-1.9.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:44e91a669c43f03964f672c5a234ae0d7a4d49c9b85d1baa93dec28afa28ffbd"}, - {file = "yarl-1.9.3-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:3cfa4dbe17b2e6fca1414e9c3bcc216f6930cb18ea7646e7d0d52792ac196808"}, - {file = "yarl-1.9.3-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:88d2c3cc4b2f46d1ba73d81c51ec0e486f59cc51165ea4f789677f91a303a9a7"}, - {file = "yarl-1.9.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:cccdc02e46d2bd7cb5f38f8cc3d9db0d24951abd082b2f242c9e9f59c0ab2af3"}, - {file = "yarl-1.9.3-cp312-cp312-win32.whl", hash = "sha256:96758e56dceb8a70f8a5cff1e452daaeff07d1cc9f11e9b0c951330f0a2396a7"}, - {file = "yarl-1.9.3-cp312-cp312-win_amd64.whl", hash = "sha256:c4472fe53ebf541113e533971bd8c32728debc4c6d8cc177f2bff31d011ec17e"}, - {file = "yarl-1.9.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:126638ab961633f0940a06e1c9d59919003ef212a15869708dcb7305f91a6732"}, - {file = "yarl-1.9.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c99ddaddb2fbe04953b84d1651149a0d85214780e4d0ee824e610ab549d98d92"}, - {file = "yarl-1.9.3-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8dab30b21bd6fb17c3f4684868c7e6a9e8468078db00f599fb1c14e324b10fca"}, - {file = "yarl-1.9.3-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:828235a2a169160ee73a2fcfb8a000709edf09d7511fccf203465c3d5acc59e4"}, - {file = "yarl-1.9.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc391e3941045fd0987c77484b2799adffd08e4b6735c4ee5f054366a2e1551d"}, - {file = "yarl-1.9.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:51382c72dd5377861b573bd55dcf680df54cea84147c8648b15ac507fbef984d"}, - {file = "yarl-1.9.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:28a108cb92ce6cf867690a962372996ca332d8cda0210c5ad487fe996e76b8bb"}, - {file = "yarl-1.9.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:8f18a7832ff85dfcd77871fe677b169b1bc60c021978c90c3bb14f727596e0ae"}, - {file = "yarl-1.9.3-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:7eaf13af79950142ab2bbb8362f8d8d935be9aaf8df1df89c86c3231e4ff238a"}, - {file = "yarl-1.9.3-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:66a6dbf6ca7d2db03cc61cafe1ee6be838ce0fbc97781881a22a58a7c5efef42"}, - {file = "yarl-1.9.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:1a0a4f3aaa18580038cfa52a7183c8ffbbe7d727fe581300817efc1e96d1b0e9"}, - {file = "yarl-1.9.3-cp37-cp37m-win32.whl", hash = "sha256:946db4511b2d815979d733ac6a961f47e20a29c297be0d55b6d4b77ee4b298f6"}, - {file = "yarl-1.9.3-cp37-cp37m-win_amd64.whl", hash = "sha256:2dad8166d41ebd1f76ce107cf6a31e39801aee3844a54a90af23278b072f1ccf"}, - {file = "yarl-1.9.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:bb72d2a94481e7dc7a0c522673db288f31849800d6ce2435317376a345728225"}, - {file = "yarl-1.9.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9a172c3d5447b7da1680a1a2d6ecdf6f87a319d21d52729f45ec938a7006d5d8"}, - {file = "yarl-1.9.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2dc72e891672343b99db6d497024bf8b985537ad6c393359dc5227ef653b2f17"}, - {file = "yarl-1.9.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b8d51817cf4b8d545963ec65ff06c1b92e5765aa98831678d0e2240b6e9fd281"}, - {file = "yarl-1.9.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:53ec65f7eee8655bebb1f6f1607760d123c3c115a324b443df4f916383482a67"}, - {file = "yarl-1.9.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cfd77e8e5cafba3fb584e0f4b935a59216f352b73d4987be3af51f43a862c403"}, - {file = "yarl-1.9.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e73db54c967eb75037c178a54445c5a4e7461b5203b27c45ef656a81787c0c1b"}, - {file = "yarl-1.9.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:09c19e5f4404574fcfb736efecf75844ffe8610606f3fccc35a1515b8b6712c4"}, - {file = "yarl-1.9.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6280353940f7e5e2efaaabd686193e61351e966cc02f401761c4d87f48c89ea4"}, - {file = "yarl-1.9.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:c25ec06e4241e162f5d1f57c370f4078797ade95c9208bd0c60f484834f09c96"}, - {file = "yarl-1.9.3-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:7217234b10c64b52cc39a8d82550342ae2e45be34f5bff02b890b8c452eb48d7"}, - {file = "yarl-1.9.3-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:4ce77d289f8d40905c054b63f29851ecbfd026ef4ba5c371a158cfe6f623663e"}, - {file = "yarl-1.9.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:5f74b015c99a5eac5ae589de27a1201418a5d9d460e89ccb3366015c6153e60a"}, - {file = "yarl-1.9.3-cp38-cp38-win32.whl", hash = "sha256:8a2538806be846ea25e90c28786136932ec385c7ff3bc1148e45125984783dc6"}, - {file = "yarl-1.9.3-cp38-cp38-win_amd64.whl", hash = "sha256:6465d36381af057d0fab4e0f24ef0e80ba61f03fe43e6eeccbe0056e74aadc70"}, - {file = "yarl-1.9.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:2f3c8822bc8fb4a347a192dd6a28a25d7f0ea3262e826d7d4ef9cc99cd06d07e"}, - {file = "yarl-1.9.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b7831566595fe88ba17ea80e4b61c0eb599f84c85acaa14bf04dd90319a45b90"}, - {file = "yarl-1.9.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ff34cb09a332832d1cf38acd0f604c068665192c6107a439a92abfd8acf90fe2"}, - {file = "yarl-1.9.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fe8080b4f25dfc44a86bedd14bc4f9d469dfc6456e6f3c5d9077e81a5fedfba7"}, - {file = "yarl-1.9.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8535e111a064f3bdd94c0ed443105934d6f005adad68dd13ce50a488a0ad1bf3"}, - {file = "yarl-1.9.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0d155a092bf0ebf4a9f6f3b7a650dc5d9a5bbb585ef83a52ed36ba46f55cc39d"}, - {file = "yarl-1.9.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:778df71c8d0c8c9f1b378624b26431ca80041660d7be7c3f724b2c7a6e65d0d6"}, - {file = "yarl-1.9.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b9f9cafaf031c34d95c1528c16b2fa07b710e6056b3c4e2e34e9317072da5d1a"}, - {file = "yarl-1.9.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ca6b66f69e30f6e180d52f14d91ac854b8119553b524e0e28d5291a724f0f423"}, - {file = "yarl-1.9.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:e0e7e83f31e23c5d00ff618045ddc5e916f9e613d33c5a5823bc0b0a0feb522f"}, - {file = "yarl-1.9.3-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:af52725c7c39b0ee655befbbab5b9a1b209e01bb39128dce0db226a10014aacc"}, - {file = "yarl-1.9.3-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:0ab5baaea8450f4a3e241ef17e3d129b2143e38a685036b075976b9c415ea3eb"}, - {file = "yarl-1.9.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:6d350388ba1129bc867c6af1cd17da2b197dff0d2801036d2d7d83c2d771a682"}, - {file = "yarl-1.9.3-cp39-cp39-win32.whl", hash = "sha256:e2a16ef5fa2382af83bef4a18c1b3bcb4284c4732906aa69422cf09df9c59f1f"}, - {file = "yarl-1.9.3-cp39-cp39-win_amd64.whl", hash = "sha256:d92d897cb4b4bf915fbeb5e604c7911021a8456f0964f3b8ebbe7f9188b9eabb"}, - {file = "yarl-1.9.3-py3-none-any.whl", hash = "sha256:271d63396460b6607b588555ea27a1a02b717ca2e3f2cf53bdde4013d7790929"}, - {file = "yarl-1.9.3.tar.gz", hash = "sha256:4a14907b597ec55740f63e52d7fee0e9ee09d5b9d57a4f399a7423268e457b57"}, + {file = "yarl-1.9.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a8c1df72eb746f4136fe9a2e72b0c9dc1da1cbd23b5372f94b5820ff8ae30e0e"}, + {file = "yarl-1.9.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a3a6ed1d525bfb91b3fc9b690c5a21bb52de28c018530ad85093cc488bee2dd2"}, + {file = "yarl-1.9.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c38c9ddb6103ceae4e4498f9c08fac9b590c5c71b0370f98714768e22ac6fa66"}, + {file = "yarl-1.9.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d9e09c9d74f4566e905a0b8fa668c58109f7624db96a2171f21747abc7524234"}, + {file = "yarl-1.9.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b8477c1ee4bd47c57d49621a062121c3023609f7a13b8a46953eb6c9716ca392"}, + {file = "yarl-1.9.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d5ff2c858f5f6a42c2a8e751100f237c5e869cbde669a724f2062d4c4ef93551"}, + {file = "yarl-1.9.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:357495293086c5b6d34ca9616a43d329317feab7917518bc97a08f9e55648455"}, + {file = "yarl-1.9.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:54525ae423d7b7a8ee81ba189f131054defdb122cde31ff17477951464c1691c"}, + {file = "yarl-1.9.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:801e9264d19643548651b9db361ce3287176671fb0117f96b5ac0ee1c3530d53"}, + {file = "yarl-1.9.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e516dc8baf7b380e6c1c26792610230f37147bb754d6426462ab115a02944385"}, + {file = "yarl-1.9.4-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:7d5aaac37d19b2904bb9dfe12cdb08c8443e7ba7d2852894ad448d4b8f442863"}, + {file = "yarl-1.9.4-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:54beabb809ffcacbd9d28ac57b0db46e42a6e341a030293fb3185c409e626b8b"}, + {file = "yarl-1.9.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:bac8d525a8dbc2a1507ec731d2867025d11ceadcb4dd421423a5d42c56818541"}, + {file = "yarl-1.9.4-cp310-cp310-win32.whl", hash = "sha256:7855426dfbddac81896b6e533ebefc0af2f132d4a47340cee6d22cac7190022d"}, + {file = "yarl-1.9.4-cp310-cp310-win_amd64.whl", hash = "sha256:848cd2a1df56ddbffeb375535fb62c9d1645dde33ca4d51341378b3f5954429b"}, + {file = "yarl-1.9.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:35a2b9396879ce32754bd457d31a51ff0a9d426fd9e0e3c33394bf4b9036b099"}, + {file = "yarl-1.9.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4c7d56b293cc071e82532f70adcbd8b61909eec973ae9d2d1f9b233f3d943f2c"}, + {file = "yarl-1.9.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d8a1c6c0be645c745a081c192e747c5de06e944a0d21245f4cf7c05e457c36e0"}, + {file = "yarl-1.9.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4b3c1ffe10069f655ea2d731808e76e0f452fc6c749bea04781daf18e6039525"}, + {file = "yarl-1.9.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:549d19c84c55d11687ddbd47eeb348a89df9cb30e1993f1b128f4685cd0ebbf8"}, + {file = "yarl-1.9.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a7409f968456111140c1c95301cadf071bd30a81cbd7ab829169fb9e3d72eae9"}, + {file = "yarl-1.9.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e23a6d84d9d1738dbc6e38167776107e63307dfc8ad108e580548d1f2c587f42"}, + {file = "yarl-1.9.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d8b889777de69897406c9fb0b76cdf2fd0f31267861ae7501d93003d55f54fbe"}, + {file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:03caa9507d3d3c83bca08650678e25364e1843b484f19986a527630ca376ecce"}, + {file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:4e9035df8d0880b2f1c7f5031f33f69e071dfe72ee9310cfc76f7b605958ceb9"}, + {file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:c0ec0ed476f77db9fb29bca17f0a8fcc7bc97ad4c6c1d8959c507decb22e8572"}, + {file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:ee04010f26d5102399bd17f8df8bc38dc7ccd7701dc77f4a68c5b8d733406958"}, + {file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:49a180c2e0743d5d6e0b4d1a9e5f633c62eca3f8a86ba5dd3c471060e352ca98"}, + {file = "yarl-1.9.4-cp311-cp311-win32.whl", hash = "sha256:81eb57278deb6098a5b62e88ad8281b2ba09f2f1147c4767522353eaa6260b31"}, + {file = "yarl-1.9.4-cp311-cp311-win_amd64.whl", hash = "sha256:d1d2532b340b692880261c15aee4dc94dd22ca5d61b9db9a8a361953d36410b1"}, + {file = "yarl-1.9.4-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0d2454f0aef65ea81037759be5ca9947539667eecebca092733b2eb43c965a81"}, + {file = "yarl-1.9.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:44d8ffbb9c06e5a7f529f38f53eda23e50d1ed33c6c869e01481d3fafa6b8142"}, + {file = "yarl-1.9.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:aaaea1e536f98754a6e5c56091baa1b6ce2f2700cc4a00b0d49eca8dea471074"}, + {file = "yarl-1.9.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3777ce5536d17989c91696db1d459574e9a9bd37660ea7ee4d3344579bb6f129"}, + {file = "yarl-1.9.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9fc5fc1eeb029757349ad26bbc5880557389a03fa6ada41703db5e068881e5f2"}, + {file = "yarl-1.9.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ea65804b5dc88dacd4a40279af0cdadcfe74b3e5b4c897aa0d81cf86927fee78"}, + {file = "yarl-1.9.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa102d6d280a5455ad6a0f9e6d769989638718e938a6a0a2ff3f4a7ff8c62cc4"}, + {file = "yarl-1.9.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:09efe4615ada057ba2d30df871d2f668af661e971dfeedf0c159927d48bbeff0"}, + {file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:008d3e808d03ef28542372d01057fd09168419cdc8f848efe2804f894ae03e51"}, + {file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:6f5cb257bc2ec58f437da2b37a8cd48f666db96d47b8a3115c29f316313654ff"}, + {file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:992f18e0ea248ee03b5a6e8b3b4738850ae7dbb172cc41c966462801cbf62cf7"}, + {file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:0e9d124c191d5b881060a9e5060627694c3bdd1fe24c5eecc8d5d7d0eb6faabc"}, + {file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:3986b6f41ad22988e53d5778f91855dc0399b043fc8946d4f2e68af22ee9ff10"}, + {file = "yarl-1.9.4-cp312-cp312-win32.whl", hash = "sha256:4b21516d181cd77ebd06ce160ef8cc2a5e9ad35fb1c5930882baff5ac865eee7"}, + {file = "yarl-1.9.4-cp312-cp312-win_amd64.whl", hash = "sha256:a9bd00dc3bc395a662900f33f74feb3e757429e545d831eef5bb280252631984"}, + {file = "yarl-1.9.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:63b20738b5aac74e239622d2fe30df4fca4942a86e31bf47a81a0e94c14df94f"}, + {file = "yarl-1.9.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7d7f7de27b8944f1fee2c26a88b4dabc2409d2fea7a9ed3df79b67277644e17"}, + {file = "yarl-1.9.4-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c74018551e31269d56fab81a728f683667e7c28c04e807ba08f8c9e3bba32f14"}, + {file = "yarl-1.9.4-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ca06675212f94e7a610e85ca36948bb8fc023e458dd6c63ef71abfd482481aa5"}, + {file = "yarl-1.9.4-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5aef935237d60a51a62b86249839b51345f47564208c6ee615ed2a40878dccdd"}, + {file = "yarl-1.9.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2b134fd795e2322b7684155b7855cc99409d10b2e408056db2b93b51a52accc7"}, + {file = "yarl-1.9.4-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d25039a474c4c72a5ad4b52495056f843a7ff07b632c1b92ea9043a3d9950f6e"}, + {file = "yarl-1.9.4-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:f7d6b36dd2e029b6bcb8a13cf19664c7b8e19ab3a58e0fefbb5b8461447ed5ec"}, + {file = "yarl-1.9.4-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:957b4774373cf6f709359e5c8c4a0af9f6d7875db657adb0feaf8d6cb3c3964c"}, + {file = "yarl-1.9.4-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:d7eeb6d22331e2fd42fce928a81c697c9ee2d51400bd1a28803965883e13cead"}, + {file = "yarl-1.9.4-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:6a962e04b8f91f8c4e5917e518d17958e3bdee71fd1d8b88cdce74dd0ebbf434"}, + {file = "yarl-1.9.4-cp37-cp37m-win32.whl", hash = "sha256:f3bc6af6e2b8f92eced34ef6a96ffb248e863af20ef4fde9448cc8c9b858b749"}, + {file = "yarl-1.9.4-cp37-cp37m-win_amd64.whl", hash = "sha256:ad4d7a90a92e528aadf4965d685c17dacff3df282db1121136c382dc0b6014d2"}, + {file = "yarl-1.9.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:ec61d826d80fc293ed46c9dd26995921e3a82146feacd952ef0757236fc137be"}, + {file = "yarl-1.9.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8be9e837ea9113676e5754b43b940b50cce76d9ed7d2461df1af39a8ee674d9f"}, + {file = "yarl-1.9.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:bef596fdaa8f26e3d66af846bbe77057237cb6e8efff8cd7cc8dff9a62278bbf"}, + {file = "yarl-1.9.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2d47552b6e52c3319fede1b60b3de120fe83bde9b7bddad11a69fb0af7db32f1"}, + {file = "yarl-1.9.4-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:84fc30f71689d7fc9168b92788abc977dc8cefa806909565fc2951d02f6b7d57"}, + {file = "yarl-1.9.4-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4aa9741085f635934f3a2583e16fcf62ba835719a8b2b28fb2917bb0537c1dfa"}, + {file = "yarl-1.9.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:206a55215e6d05dbc6c98ce598a59e6fbd0c493e2de4ea6cc2f4934d5a18d130"}, + {file = "yarl-1.9.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07574b007ee20e5c375a8fe4a0789fad26db905f9813be0f9fef5a68080de559"}, + {file = "yarl-1.9.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:5a2e2433eb9344a163aced6a5f6c9222c0786e5a9e9cac2c89f0b28433f56e23"}, + {file = "yarl-1.9.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:6ad6d10ed9b67a382b45f29ea028f92d25bc0bc1daf6c5b801b90b5aa70fb9ec"}, + {file = "yarl-1.9.4-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:6fe79f998a4052d79e1c30eeb7d6c1c1056ad33300f682465e1b4e9b5a188b78"}, + {file = "yarl-1.9.4-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:a825ec844298c791fd28ed14ed1bffc56a98d15b8c58a20e0e08c1f5f2bea1be"}, + {file = "yarl-1.9.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8619d6915b3b0b34420cf9b2bb6d81ef59d984cb0fde7544e9ece32b4b3043c3"}, + {file = "yarl-1.9.4-cp38-cp38-win32.whl", hash = "sha256:686a0c2f85f83463272ddffd4deb5e591c98aac1897d65e92319f729c320eece"}, + {file = "yarl-1.9.4-cp38-cp38-win_amd64.whl", hash = "sha256:a00862fb23195b6b8322f7d781b0dc1d82cb3bcac346d1e38689370cc1cc398b"}, + {file = "yarl-1.9.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:604f31d97fa493083ea21bd9b92c419012531c4e17ea6da0f65cacdcf5d0bd27"}, + {file = "yarl-1.9.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8a854227cf581330ffa2c4824d96e52ee621dd571078a252c25e3a3b3d94a1b1"}, + {file = "yarl-1.9.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ba6f52cbc7809cd8d74604cce9c14868306ae4aa0282016b641c661f981a6e91"}, + {file = "yarl-1.9.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a6327976c7c2f4ee6816eff196e25385ccc02cb81427952414a64811037bbc8b"}, + {file = "yarl-1.9.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8397a3817d7dcdd14bb266283cd1d6fc7264a48c186b986f32e86d86d35fbac5"}, + {file = "yarl-1.9.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e0381b4ce23ff92f8170080c97678040fc5b08da85e9e292292aba67fdac6c34"}, + {file = "yarl-1.9.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:23d32a2594cb5d565d358a92e151315d1b2268bc10f4610d098f96b147370136"}, + {file = "yarl-1.9.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ddb2a5c08a4eaaba605340fdee8fc08e406c56617566d9643ad8bf6852778fc7"}, + {file = "yarl-1.9.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:26a1dc6285e03f3cc9e839a2da83bcbf31dcb0d004c72d0730e755b33466c30e"}, + {file = "yarl-1.9.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:18580f672e44ce1238b82f7fb87d727c4a131f3a9d33a5e0e82b793362bf18b4"}, + {file = "yarl-1.9.4-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:29e0f83f37610f173eb7e7b5562dd71467993495e568e708d99e9d1944f561ec"}, + {file = "yarl-1.9.4-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:1f23e4fe1e8794f74b6027d7cf19dc25f8b63af1483d91d595d4a07eca1fb26c"}, + {file = "yarl-1.9.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:db8e58b9d79200c76956cefd14d5c90af54416ff5353c5bfd7cbe58818e26ef0"}, + {file = "yarl-1.9.4-cp39-cp39-win32.whl", hash = "sha256:c7224cab95645c7ab53791022ae77a4509472613e839dab722a72abe5a684575"}, + {file = "yarl-1.9.4-cp39-cp39-win_amd64.whl", hash = "sha256:824d6c50492add5da9374875ce72db7a0733b29c2394890aef23d533106e2b15"}, + {file = "yarl-1.9.4-py3-none-any.whl", hash = "sha256:928cecb0ef9d5a7946eb6ff58417ad2fe9375762382f1bf5c55e61645f2c43ad"}, + {file = "yarl-1.9.4.tar.gz", hash = "sha256:566db86717cf8080b99b58b083b773a908ae40f06681e87e589a976faf8246bf"}, ] [package.dependencies] @@ -3599,4 +3629,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p [metadata] lock-version = "2.0" python-versions = ">=3.8.1,<4.0" -content-hash = "2777c34c9c1b5c056206649d287e08e55671a647721374fb7c3b6edc711e796e" +content-hash = "4e4d02201942d821f9a687e6c0eb787ed841d537498a0fd118226cd48f8d022c" diff --git a/pyproject.toml b/pyproject.toml index 40536ecf9..88bf3781c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -37,7 +37,8 @@ optional = true [tool.poetry.group.dev.dependencies] jupyter = "^1.0.0" openai = "^0.27.8" -langchain = "^0.0.352" +langchain = "^0.0.353" +langchainhub = "^0.1.14" [tool.ruff] select = [ "E", "F", "I" ] From 51a538c6fc0c1d84d73c34165cd7a0900165da2e Mon Sep 17 00:00:00 2001 From: Jake Rachleff Date: Wed, 3 Jan 2024 10:02:39 -0800 Subject: [PATCH 04/19] update --- examples/langgraph.ipynb | 72 ++++++++++++++++++++++++--------- permchain/langgraph/__init__.py | 22 +++++----- 2 files changed, 65 insertions(+), 29 deletions(-) diff --git a/examples/langgraph.ipynb b/examples/langgraph.ipynb index 3595bc705..8e01fafb5 100644 --- a/examples/langgraph.ipynb +++ b/examples/langgraph.ipynb @@ -64,12 +64,12 @@ "tool_actor = Actor(\"tools\", RunnableLambda(execute_tools))\n", "end = End()\n", "\n", - "workflow.register_node(llm_agent)\n", - "workflow.register_node(tool_actor)\n", + "workflow.add_node(llm_agent)\n", + "workflow.add_node(tool_actor)\n", "\n", "workflow.set_entry_point(llm_agent.key)\n", "\n", - "workflow.register_conditional_edges(\n", + "workflow.add_conditional_edges(\n", " llm_agent.key,\n", " should_continue,\n", " {\n", @@ -77,16 +77,41 @@ " \"exit\": end.key\n", " }\n", ")\n", - "workflow.register_edge(tool_actor.key, llm_agent.key)\n", + "workflow.add_edge(tool_actor.key, llm_agent.key)\n", "chain = workflow.compile()" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 2, "id": "c46bd262-9605-4449-9391-f6b6e0fe440e", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Retrying langchain_community.chat_models.openai.ChatOpenAI.completion_with_retry.._completion_with_retry in 4.0 seconds as it raised ServiceUnavailableError: The server is overloaded or not ready yet..\n", + "Retrying langchain_community.chat_models.openai.ChatOpenAI.completion_with_retry.._completion_with_retry in 4.0 seconds as it raised ServiceUnavailableError: The server is overloaded or not ready yet..\n" + ] + }, + { + "data": { + "text/plain": [ + "{'input': 'what is the weather in sf',\n", + " 'intermediate_steps': [(AgentActionMessageLog(tool='tavily_search_results_json', tool_input={'query': 'weather in San Francisco'}, log=\"\\nInvoking: `tavily_search_results_json` with `{'query': 'weather in San Francisco'}`\\n\\n\\n\", message_log=[AIMessage(content='', additional_kwargs={'function_call': {'name': 'tavily_search_results_json', 'arguments': '{\"query\":\"weather in San Francisco\"}'}})]),\n", + " [{'url': 'https://www.cbsnews.com/sanfrancisco/news/california-begins-2024-with-below-normal-snowpack-a-year-after-one-of-the-best-starts-in-decades/',\n", + " 'content': 'January 2, 2024 / 3:27 PM PST / AP More from CBS News First published on January 2, 2024 / 2:28 PM PST Watch CBS News California begins 2024 with below-normal snowpack a year after one of the best starts in decades between January and April.New storm packing significant rain, strong winds approaches Bay Area 02:16. California is beginning 2024 with a below-normal mountain snowpack a year after it had one of its best starts in decades ...'}]),\n", + " (AgentActionMessageLog(tool='tavily_search_results_json', tool_input={'query': 'current weather in San Francisco'}, log=\"\\nInvoking: `tavily_search_results_json` with `{'query': 'current weather in San Francisco'}`\\nresponded: It seems that the search results did not return the current weather in San Francisco. Let me try another method to fetch the weather information for you.\\n\\n\", message_log=[AIMessage(content='It seems that the search results did not return the current weather in San Francisco. Let me try another method to fetch the weather information for you.', additional_kwargs={'function_call': {'name': 'tavily_search_results_json', 'arguments': '{\"query\":\"current weather in San Francisco\"}'}})]),\n", + " [])],\n", + " 'agent_outcome': AgentFinish(return_values={'output': \"I'm sorry, but it seems that I'm unable to fetch the current weather information for San Francisco at the moment. I recommend using a weather website or app to get the most up-to-date weather forecast for San Francisco.\"}, log=\"I'm sorry, but it seems that I'm unable to fetch the current weather information for San Francisco at the moment. I recommend using a weather website or app to get the most up-to-date weather forecast for San Francisco.\")}" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "chain.invoke({\"input\": \"what is the weather in sf\", \"intermediate_steps\": []})" ] @@ -101,7 +126,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 3, "id": "f6f96e81-4a20-4599-a625-8d18df6fa76d", "metadata": {}, "outputs": [], @@ -235,7 +260,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 4, "id": "7708fa95-547b-4bea-b126-3656de7d5873", "metadata": {}, "outputs": [], @@ -301,10 +326,21 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 5, "id": "d6cdd1cd-e480-4dd7-99b4-9018eb243b4d", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "AgentFinish(return_values={'output': 'The current weather in San Francisco (SF) is characterized by a mild climate with January daytime maximum temperatures averaging around 13°C (55°F). The city experiences microclimates due to its topography and coastal location, leading to significant weather variations across different neighborhoods[1]. Historically, SF has wet winters and dry summers, with average temperatures ranging from the mid-40s to the low 70s Fahrenheit (7-22 degrees Celsius). The warmest months are typically September and October. Fog is frequent, especially in summer, which can lead to cooler temperatures. The rainy season spans from November to March, with an annual average rainfall of about 23 inches (584 mm). Wind is also a notable factor, particularly in coastal areas.\\n\\nReferences:\\n[1] https://www.weather2travel.com/california/san-francisco/january/', 'initial_answer': \"The weather in San Francisco (SF) is characterized by a mild, Mediterranean-like climate with wet winters and dry summers. The city's unique topography and coastal location result in microclimates, where weather conditions can vary significantly from one neighborhood to another. Average temperatures typically range from the mid-40s to the low 70s Fahrenheit (7-22 degrees Celsius), with the warmest months being September and October. Fog is a common occurrence, particularly in the summer, leading to cooler temperatures compared to the surrounding areas. Rainfall is concentrated from November to March, with the city receiving an average of about 23 inches (584 mm) annually. Wind is another factor to consider, as it can be quite strong, especially near the Golden Gate Bridge. It's always advisable to dress in layers when visiting SF due to the potential for rapid weather changes.\"}, log='Reached max steps.')" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "workflow = Graph()\n", "initial_answer_actor = Actor(\"initial\", initial_chain)\n", @@ -312,17 +348,17 @@ "finish_actor = Actor(\"finish\", RunnableLambda(finish))\n", "tool_actor = Actor(\"tools\", RunnableLambda(execute_tools))\n", "\n", - "# Register actors\n", - "workflow.register_node(initial_answer_actor)\n", - "workflow.register_node(next_step_actor)\n", - "workflow.register_node(finish_actor)\n", - "workflow.register_node(tool_actor)\n", + "# add actors\n", + "workflow.add_node(initial_answer_actor)\n", + "workflow.add_node(next_step_actor)\n", + "workflow.add_node(finish_actor)\n", + "workflow.add_node(tool_actor)\n", "\n", "# Enter with initial actor, then loop through tools -> next steps until finished\n", "workflow.set_entry_point(initial_answer_actor.key)\n", "\n", - "workflow.register_edge(initial_answer_actor.key, tool_actor.key)\n", - "workflow.register_conditional_edges(\n", + "workflow.add_edge(initial_answer_actor.key, tool_actor.key)\n", + "workflow.add_conditional_edges(\n", " tool_actor.key,\n", " lambda x: \"exit\" if len(x['intermediate_steps']) >= 2 else \"continue\",\n", " {\n", @@ -330,7 +366,7 @@ " \"exit\": finish_actor.key\n", " }\n", ")\n", - "workflow.register_edge(next_step_actor.key, tool_actor.key)\n", + "workflow.add_edge(next_step_actor.key, tool_actor.key)\n", "workflow.set_finish_point(finish_actor.key)\n", "\n", "chain = workflow.compile()\n", diff --git a/permchain/langgraph/__init__.py b/permchain/langgraph/__init__.py index b513fb175..4876e282c 100644 --- a/permchain/langgraph/__init__.py +++ b/permchain/langgraph/__init__.py @@ -126,17 +126,17 @@ class Graph: # self.branches = {} self.entry_point: Optional[str] = None - def register_node(self, node: Actor): + def add_node(self, node: Actor): if node.key in self.nodes: raise ValueError(f"Actor `{node.key}` already present.") self.nodes[node.key] = node - def register_edge(self, start_key: str, end_key: str): + def add_edge(self, start_key: str, end_key: str): if start_key not in self.nodes: - raise ValueError(f"Need to register_node `{start_key}` first") + raise ValueError(f"Need to add_node `{start_key}` first") if end_key not in self.nodes: - raise ValueError(f"Need to register_node `{end_key}` first") + raise ValueError(f"Need to add_node `{end_key}` first") # TODO: support multiple message passing if start_key in set(edge.start_key for edge in self.edges): @@ -144,7 +144,7 @@ class Graph: self.edges.append(LangGraphEdge(start_key, end_key)) - def register_conditional_edges( + def add_conditional_edges( self, start_key: str, condition: Callable[Any, str], @@ -156,11 +156,11 @@ class Graph: condition ) - self.register_node(conditional_node) - self.register_edge(start_key, conditional_node.key) + self.add_node(conditional_node) + self.add_edge(start_key, conditional_node.key) for branch in conditional_node.branches: - self.register_node(branch) + self.add_node(branch) self.edges.append(ConditionalEdge(conditional_node.key, branch.key)) self.edges.append( BranchEdge(branch.key, conditional_node.conditional_edge_mapping[branch.condition]) @@ -169,13 +169,13 @@ class Graph: def set_entry_point(self, key: str): if key not in self.nodes: - raise ValueError(f"Need to register_node `{node.key}` first") + raise ValueError(f"Need to add_node `{node.key}` first") self.entry_point = key def set_finish_point(self, key: str): if key not in self.nodes: - raise ValueError(f"Need to register_node `{node.key}` first") - self.register_edge(key, "end") + raise ValueError(f"Need to add_node `{node.key}` first") + self.add_edge(key, "end") def compile(self): From 17cd65953335289b264cbf58009acb1269d323a6 Mon Sep 17 00:00:00 2001 From: Nuno Campos Date: Fri, 5 Jan 2024 18:22:46 -0800 Subject: [PATCH 05/19] ... --- examples/.langchain.db | Bin 0 -> 53248 bytes examples/langgraph.ipynb | 94 ++++++------ permchain/__init__.py | 2 + permchain/langgraph/__init__.py | 258 ++++++++++---------------------- permchain/pregel/__init__.py | 2 +- poetry.lock | 38 ++--- pyproject.toml | 2 +- tests/test_graph.py | 0 tests/test_pregel.py | 66 +++++++- tests/test_pregel_async.py | 4 - 10 files changed, 208 insertions(+), 258 deletions(-) create mode 100644 examples/.langchain.db create mode 100644 tests/test_graph.py diff --git a/examples/.langchain.db b/examples/.langchain.db new file mode 100644 index 0000000000000000000000000000000000000000..791e9b4ba8f8727604c9f43d1454fe65ade828f6 GIT binary patch literal 53248 zcmeHQ&2t+^b|<}-DJzz}dr0Zpg$uta?qMsJTyoDL=N$H$WB!ZWQk6@7ucrqXd`O~YRcyEzgk%KI{AU$u^Q?zWED z;r$bK`0&dw>+H(=Q^3p1be2f;chgrwYya?M_s;Io^qJ}nnJ`1GjHsS_aI}BWI(p2$ z*nP~d%Xs6;#?HI%U3;{(y5bmWzD^Lhc6e^J`@T%xwicIq>DxQ2Yu7e5R)4=gg$Lvo z66)@se0ygRmdQ1CykI?e8Hw1Hjo-ZU-nIK1FNI@5 zZl{1^^8FW3GnYx#P*A`6(f`un)#3*ohR;t5fj|9v_3|G-`@Zn3R8 ztJ(2T;II~9YuPN1tj=mUEn}Q~QcJk%M*}Vuoik9+DW{`U7{mL*(DB_ob{C;l|HlZqeggO?F3~36L5K%Vh$BFm#35w%Ts8BhgDlWI<@mqD)$e z5oty&(XF(}j)x+WJsI&N8P^>#W}x#V#v}}%20Ix@b;@{G=XSE7R2oCn_FyJwhI`pV zCI{%fB-gniQma(F@UenF1Zh?vRS?H=XkaDIE#W0os2m_MKcIuBa*`$$=RC5>m~FEm z&n#FEC2{iXYpajF9MH)Hv?87gmJiuT+QEyVYOC9~Z<9>z6}i4 za#Dj$*(cd^H%bMu;)$o|X2b(qGPvt z3*jgydub9YXRod$_?nsNXRG2#}?B`UFsuXAmM z0d1hJ^_UFj-TlKmOeB!kVIsH@O;T47GJvKPPdZaY_5Atsr?00Ip&a3>>KN0|=z1s= zmvpp)3-|G@wLh;Etw^yOxy7QO7&n`nxI5+N9ji};BE7l2xmljegv})MEOd2oj%Fft z+8^4+CylMG%}*P{Oq@wEnoi&0L)keMW8Al7QP?*amG1UB{{DmA!`6PM^&m& zU^E(yC)d}F)x-5VI|L&(UK5_F$$$5L`793Hgl@ ziNXnN4(WoCfHIe`ix~_HL^ppnZWvMpFv;xZCT`Hq2&Xb`e2TAoe2@t> z5E6QIkmW|w!;&NN|ll@ z&#<_D`bfhfR4(o08OX4Bpa<)Np$S}~0=vlw713NU`u(~aSVnomGk}EY?&ZLU?!K2N zV{gTDA7(Lk7NeVI%FwVR6Eq+P&6(0#!7mp)_MS$B;|z;1r`Xq#F=+*z+GTu zAq2#RB?Pyhj+9)Uukk3i%Ix@w;5Uc-3QCS=?tC)Kk67hABD43Yubys8iYdTt^Ejth_uK#mw5vSUbISu8X7 z>6obCCp|*bOag$y|E5!(rA|0zJRnF*ZJzI#b_RqtOm4gOG6pVxVv(1$qPd~ToWIDk z!KDHn5~2=Nfp*5V2k+4gI&gHc&B&!7b5G+Wx(~0uOHPN%5#oNZdIkT!b0u5(@K^XJ zd;$Uifq+0jARrJB2nYlO0s?Owfq(hywZBNzDpo_O0%6DZDpedIJBSphOBlOUAr%39 z=$gAy0);k8j1X2J`a+@#VFE&&q6C3Fd6_1s#6R6S8Dx@DM!1dOgQ@{KLl8;XsL4na zi&wJReqb8B5506i9f0X1gsK}A|aM3MN7mko=y@Ilw#-)2*oe0AsTS_?wWRfVQ zg+LPd3gojyT$!Z7TA++0@g%B~kdd#n*$ zQ=o{@8Edl|37XhfmQb8RM2|>)1A)7u5S2#p1sqx=eH!e^)>AgHc4%(hxPdwd!dlTp z8oL0wxXInN{gT@n4z5ZO=7qc{svbxxR*ODUhRj!vAPjMlXFq;;v`cXMz<8R9pBCcU z3VZ#^KmBISl@i|%+w=Qw&mVgw5$t~7z2N`LH?HKvfB}JkKtLcM5D*9m1Ox&C0fB%( zKp-Fx5C{nTh!CLqKYr;yd;$Uifq+0jARrJB2nYlO0s;YnfIvVXAP^9EixCL%|69!5 zu(W_cKp-Fx5C{ka1Ofs9fq+0jARrJB2ncutLi`^@As`SC2nYlO0s;YnfIvVXAP^7; z2m}NI0&hP8A^v~+c^p<45C{ka1Ofs9fq+0jARrJB2nYlO0s;X6LSU{9+3X*etp3@| z$)65g=w7zaBdhYqEJH`J48VnsVy@j>=qUDc=qMKSYCs?$5D*9m1Ox&C0fB%(Kp-IS zV?`izG@og6PCXbyNAo4k-`nZ|b!wp|GsX&ZJYlXQHxAhr`l7UzZ?o(=sFpoa=Nnpv zF3V`O6S^#iF3WFym*q*1Wma|<4lS0c8}zhy)6ccV@=Swe^zZsX`zt#ehK}uMppAC* zLv*Z1KP?dTLz7i=CiTg)^*l?~Z?W~V$=GN#YI@_keUn;^-B4)FHfZpozuJx5@Ed3% zF0l$F`3=KWqnB|NNfYVyI$Mvlq8{lqDhZ6E#=Vwe0y{IlO~((Z_TzoL2Gj~P4_dNOnY&o z9UEO)7;&aQ_T<4#P=`A9Dq^S^9kl@;9yoaXon9=o3)70f& zxe;gQoR?SjsGz>!2fFC#GayOL>l63%OwT;(4v$uJXv>F=cW6>~s`SWL;Hd3e3B>%e z>+GSD7LOdGdmg&j6Hp}`6@Ow8E~uP#zPZ`mWP455XO24Rp+h(t!_fj`VYy5&Zk5P| zzUWJab$$KbIFv))7e(9m7Xh*U{3&hO+qZAi4+tXK8di&xj2rCWB+(<|c2LnI5sd;B zH5V-FPp%o@T;IVirzV7+pqOgsVQ3fK+r22e$KbDAc_} zISKT_Ou%j1G0{Mz+>z!YVLIA@D|AOF z0j~`H)jT?>Fa{p`a@sH8XiaDIBN>{rwSVBponwZNT?x`Tx4x}TAi!ln^rG0I>?Y15 z^a>|u-wraJ_Xq5ZXD+W@K3GJP2R|% zu%b$hfzhLYq(6;Q5EikUn`m*a5i`V%PjR@%2MF^ALfRtmLVtEd-Npr`uJ1YehEs$Q zW!g^&FyMN-I2z*^*;nYzj%>5pl@=psTZi*0E`_<2*&? zVwP+Q2y_o=3WNnZ!Bs>D2n>i}nrW!2jO|QP927nv=8JQzz3BNK=_Ib+u#;z4p>>+R zmkIc=_|nt;x(lOZlqWocr;BjoUXJLESavT@#!dDJA&A?d^GSykZD7uS7_;7yvV@!>$hj|n-C5fLI z@ej_Bz@>;OiDG0K@(kgVFhdbZx{+u$Lz=S4$qXivG+~7}M-~UW%aKqD2_-%7AW{(E zDx7E^&@mw5? zI0Tp{JUT^EwWNDq1JF9^$hl(YLPp5Q@yG(>s=QSi5?;t$3|(-TB5y~S zKy;KKRZHnVN~;>33K%GsXnjgV)46$;LCF`vJe0!;CQ2duFg>)uIVDsCu5OP~RI0F{ zC+wJuUrW}_2d{IJI{}{wV0?tk(Q(OBj!cT4%9YcK4zjK$#)^*{+d6 zobJ%s^ad^!Y#@L-BzevfBfBTfphIdACL6|*d;=OM(S4|sE_o;_PZIbJR}ufOuKvdg z{tKU!rU&X0S&#gcQaI z+J`diG-zMb!|)3#gO)=%`#PH}-fFTtq*{43FU~5|wpDmrCcG^(n;l=4{U%wwaEYR| zSek$axA5@1*nY=?ftPh`iZ@s&@W}z^{Jor*Gw#Tevcl~&8gKPrA^$bx0!tQTikh&;=xZtlo>ku~*d5VlfH3T0CM8IXp z2sb%~*K1sO>s?t2t>KsFN@5$qDh+i%hiXeW;ANpqzDc#87y+M>0VR=SWdxN^3Qf4~dW)$>98$Q{)2O zr(F$zj4y(CMXLA6SOi|%#EVoE8sA3Quh!Tt2+ zEFy@!c+D7je~A}Sk#=^T*s|9tF)RudC|JRhD+{l1UQk|gg(RAQJ`L6aWgPkQX?PZLn$`%fHx6?^Z9|wmmI(E!=i-UZ5a{!eI4R0cIHD0._completion_with_retry in 4.0 seconds as it raised ServiceUnavailableError: The server is overloaded or not ready yet..\n", - "Retrying langchain_community.chat_models.openai.ChatOpenAI.completion_with_retry.._completion_with_retry in 4.0 seconds as it raised ServiceUnavailableError: The server is overloaded or not ready yet..\n" - ] - }, { "data": { "text/plain": [ "{'input': 'what is the weather in sf',\n", - " 'intermediate_steps': [(AgentActionMessageLog(tool='tavily_search_results_json', tool_input={'query': 'weather in San Francisco'}, log=\"\\nInvoking: `tavily_search_results_json` with `{'query': 'weather in San Francisco'}`\\n\\n\\n\", message_log=[AIMessage(content='', additional_kwargs={'function_call': {'name': 'tavily_search_results_json', 'arguments': '{\"query\":\"weather in San Francisco\"}'}})]),\n", - " [{'url': 'https://www.cbsnews.com/sanfrancisco/news/california-begins-2024-with-below-normal-snowpack-a-year-after-one-of-the-best-starts-in-decades/',\n", - " 'content': 'January 2, 2024 / 3:27 PM PST / AP More from CBS News First published on January 2, 2024 / 2:28 PM PST Watch CBS News California begins 2024 with below-normal snowpack a year after one of the best starts in decades between January and April.New storm packing significant rain, strong winds approaches Bay Area 02:16. California is beginning 2024 with a below-normal mountain snowpack a year after it had one of its best starts in decades ...'}]),\n", - " (AgentActionMessageLog(tool='tavily_search_results_json', tool_input={'query': 'current weather in San Francisco'}, log=\"\\nInvoking: `tavily_search_results_json` with `{'query': 'current weather in San Francisco'}`\\nresponded: It seems that the search results did not return the current weather in San Francisco. Let me try another method to fetch the weather information for you.\\n\\n\", message_log=[AIMessage(content='It seems that the search results did not return the current weather in San Francisco. Let me try another method to fetch the weather information for you.', additional_kwargs={'function_call': {'name': 'tavily_search_results_json', 'arguments': '{\"query\":\"current weather in San Francisco\"}'}})]),\n", - " [])],\n", - " 'agent_outcome': AgentFinish(return_values={'output': \"I'm sorry, but it seems that I'm unable to fetch the current weather information for San Francisco at the moment. I recommend using a weather website or app to get the most up-to-date weather forecast for San Francisco.\"}, log=\"I'm sorry, but it seems that I'm unable to fetch the current weather information for San Francisco at the moment. I recommend using a weather website or app to get the most up-to-date weather forecast for San Francisco.\")}" + " 'intermediate_steps': [(AgentActionMessageLog(tool='tavily_search_results_json', tool_input={'query': 'current weather in San Francisco'}, log=\"\\nInvoking: `tavily_search_results_json` with `{'query': 'current weather in San Francisco'}`\\n\\n\\n\", message_log=[AIMessage(content='', additional_kwargs={'function_call': {'name': 'tavily_search_results_json', 'arguments': '{\"query\":\"current weather in San Francisco\"}'}})]),\n", + " [{'url': 'https://www.weather25.com/north-america/usa/california/san-francisco',\n", + " 'content': 'will give you an idea of weather trends in San Francisco. For example, the weather in San Francisco in January 2024. San Francisco 14 day weather The weather today in San Francisco San Francisco weather report the weather in San Francisco including humidity, wind, chance of rain and more on the San Francisco current weather Weather25.com provides all the information that you need to know about the weather in San Francisco, United States.The current temperature in San Francisco is ° F. You can find more detailed information about the weather in San Francisco including humidity, wind, chance of rain and more on the San Francisco current weather page. The weather in San Francisco'}])],\n", + " 'agent_outcome': AgentFinish(return_values={'output': 'The current temperature in San Francisco is not available, but you can find detailed information about the weather in San Francisco, including humidity, wind, and chance of rain on the San Francisco current weather page. You can visit [Weather25.com](https://www.weather25.com/north-america/usa/california/san-francisco) for more information.'}, log='The current temperature in San Francisco is not available, but you can find detailed information about the weather in San Francisco, including humidity, wind, and chance of rain on the San Francisco current weather page. You can visit [Weather25.com](https://www.weather25.com/north-america/usa/california/san-francisco) for more information.')}" ] }, "execution_count": 2, @@ -129,7 +128,16 @@ "execution_count": 3, "id": "f6f96e81-4a20-4599-a625-8d18df6fa76d", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/Users/nuno/dev/permchain/.venv/lib/python3.11/site-packages/langchain_core/_api/deprecation.py:189: LangChainDeprecationWarning: The class `ChatOpenAI` was deprecated in LangChain 0.1.0 and will be removed in 0.2.0. Use langchain_openai.ChatOpenAI instead.\n", + " warn_deprecated(\n" + ] + } + ], "source": [ "from langchain.agents import AgentExecutor, BaseMultiActionAgent, Tool\n", "from langchain.schema import AgentAction, AgentFinish\n", @@ -333,7 +341,7 @@ { "data": { "text/plain": [ - "AgentFinish(return_values={'output': 'The current weather in San Francisco (SF) is characterized by a mild climate with January daytime maximum temperatures averaging around 13°C (55°F). The city experiences microclimates due to its topography and coastal location, leading to significant weather variations across different neighborhoods[1]. Historically, SF has wet winters and dry summers, with average temperatures ranging from the mid-40s to the low 70s Fahrenheit (7-22 degrees Celsius). The warmest months are typically September and October. Fog is frequent, especially in summer, which can lead to cooler temperatures. The rainy season spans from November to March, with an annual average rainfall of about 23 inches (584 mm). Wind is also a notable factor, particularly in coastal areas.\\n\\nReferences:\\n[1] https://www.weather2travel.com/california/san-francisco/january/', 'initial_answer': \"The weather in San Francisco (SF) is characterized by a mild, Mediterranean-like climate with wet winters and dry summers. The city's unique topography and coastal location result in microclimates, where weather conditions can vary significantly from one neighborhood to another. Average temperatures typically range from the mid-40s to the low 70s Fahrenheit (7-22 degrees Celsius), with the warmest months being September and October. Fog is a common occurrence, particularly in the summer, leading to cooler temperatures compared to the surrounding areas. Rainfall is concentrated from November to March, with the city receiving an average of about 23 inches (584 mm) annually. Wind is another factor to consider, as it can be quite strong, especially near the Golden Gate Bridge. It's always advisable to dress in layers when visiting SF due to the potential for rapid weather changes.\"}, log='Reached max steps.')" + "AgentFinish(return_values={'output': 'The current weather in San Francisco can be accessed through various weather reporting services, which provide up-to-date temperature, humidity, wind, and chance of rain information [1]. Historically, San Francisco experiences a Mediterranean climate with average temperatures ranging from the low 50s to mid-60s Fahrenheit. The city is known for its microclimates, leading to significant weather variations across different neighborhoods. Summer temperatures are often cooler compared to other California areas due to the cold California Current and frequent fog, particularly in June and July. Winters are mild and moist, with most rainfall occurring between November and March, averaging around 23 inches annually. Wind is a prominent feature, especially in spring. For historical weather extremes and average wind speeds, additional specific data would be required.\\n\\nReferences:\\n[1] https://www.weather25.com/north-america/usa/california/san-francisco', 'initial_answer': \"The weather in San Francisco (SF) is characterized by a mild, Mediterranean-like climate with wet winters and dry summers. The city's unique topography and coastal location result in microclimates, where weather conditions can vary significantly from one neighborhood to another. Average temperatures typically range from the low 50s to the mid-60s Fahrenheit throughout the year. Summers in San Francisco are often cooler than in other parts of California due to the cold California Current offshore and the presence of fog, particularly in June and July. The fog usually burns off by the afternoon, leading to clearer skies and slightly warmer temperatures. Winters are mild and moist, with the majority of the city's rainfall occurring between November and March. Rainfall averages around 23 inches annually. Wind is also a notable feature of San Francisco's weather, with spring being the windiest season. Despite the general patterns, it's always advisable to dress in layers due to the potential for rapid weather changes.\"}, log='Reached max steps.')" ] }, "execution_count": 5, @@ -343,31 +351,27 @@ ], "source": [ "workflow = Graph()\n", - "initial_answer_actor = Actor(\"initial\", initial_chain)\n", - "next_step_actor = Actor(\"next\", next_chain)\n", - "finish_actor = Actor(\"finish\", RunnableLambda(finish))\n", - "tool_actor = Actor(\"tools\", RunnableLambda(execute_tools))\n", "\n", "# add actors\n", - "workflow.add_node(initial_answer_actor)\n", - "workflow.add_node(next_step_actor)\n", - "workflow.add_node(finish_actor)\n", - "workflow.add_node(tool_actor)\n", + "workflow.add_node(\"initial\", initial_chain)\n", + "workflow.add_node(\"next\", next_chain)\n", + "workflow.add_node(\"finish\", finish)\n", + "workflow.add_node(\"tools\", execute_tools)\n", "\n", "# Enter with initial actor, then loop through tools -> next steps until finished\n", - "workflow.set_entry_point(initial_answer_actor.key)\n", + "workflow.set_entry_point('initial')\n", "\n", - "workflow.add_edge(initial_answer_actor.key, tool_actor.key)\n", + "workflow.add_edge('initial', 'tools')\n", "workflow.add_conditional_edges(\n", - " tool_actor.key,\n", + " 'tools',\n", " lambda x: \"exit\" if len(x['intermediate_steps']) >= 2 else \"continue\",\n", " {\n", - " \"continue\": next_step_actor.key,\n", - " \"exit\": finish_actor.key\n", + " \"continue\": 'next',\n", + " \"exit\": 'finish'\n", " }\n", ")\n", - "workflow.add_edge(next_step_actor.key, tool_actor.key)\n", - "workflow.set_finish_point(finish_actor.key)\n", + "workflow.add_edge('next', 'tools')\n", + "workflow.set_finish_point('finish')\n", "\n", "chain = workflow.compile()\n", "\n", diff --git a/permchain/__init__.py b/permchain/__init__.py index f72ff7219..24c2199d6 100644 --- a/permchain/__init__.py +++ b/permchain/__init__.py @@ -1,4 +1,5 @@ from permchain.checkpoint.base import BaseCheckpointAdapter, CheckpointAt +from permchain.langgraph import Graph from permchain.pregel import Channel, Pregel, ReservedChannels __all__ = [ @@ -7,4 +8,5 @@ __all__ = [ "ReservedChannels", "BaseCheckpointAdapter", "CheckpointAt", + "Graph", ] diff --git a/permchain/langgraph/__init__.py b/permchain/langgraph/__init__.py index 4876e282c..cca29a9d1 100644 --- a/permchain/langgraph/__init__.py +++ b/permchain/langgraph/__init__.py @@ -1,235 +1,127 @@ -from langchain_core.runnables import Runnable, RunnableMap, RunnableLambda, RunnablePassthrough -from typing import Callable, Union, Optional, List, Any, Dict -from permchain import Channel, Pregel +from collections import defaultdict +from typing import Any, Callable, Dict, NamedTuple -######################################################### -# NODE CLASSES # -######################################################### +from langchain_core.runnables import Runnable +from langchain_core.runnables.base import RunnableLike, coerce_to_runnable -class LangGraphNode: - def __init__(self, key: str): - self.key = key - - def get_runnable(self) -> Runnable: - pass +from permchain.pregel import Channel, Pregel -class Actor(LangGraphNode): - - def __init__(self, key: str, runnable: Runnable): - self.runnable = runnable - super().__init__(key) - - def get_runnable(self) -> Union[Runnable, Callable]: - return self.runnable +class Edge(NamedTuple): + start: str + end: str -class End(LangGraphNode): - def __init__(self): - super().__init__(key="end") +class Branch(NamedTuple): + condition: Callable[..., str] + ends: dict[str, str] - def get_runnable(self) -> Union[Runnable, Callable]: - raise NotImplementedError + def runnable(self, input: Any) -> Runnable: + result = self.condition(input) + return Channel.write_to(self.ends[result]) -class Branch(LangGraphNode): - - def __init__(self, parent_key: str, condition: str): - self.parent_key = parent_key - self.condition = condition - super().__init__(f"{self.parent_key}.{self.condition}") - - def get_runnable(self) -> Union[Runnable, Callable]: - # Only used for structure, so the runnable should never be called - raise NotImplementedError - - -class Conditional(LangGraphNode): - - def __init__(self, key: str, conditional_edge_mapping: Dict[str, str], callable: Callable): - self.callable = callable - self.branches = [] - - for condition, output in conditional_edge_mapping.items(): - self.branches.append(Branch(key, condition)) - - self.conditional_edge_mapping = conditional_edge_mapping - - super().__init__(key) - - def get_runnable(self) -> Union[Runnable, Callable]: - return self.callable - - - -######################################################### -# EDGE CLASSES # -######################################################### - -class LangGraphEdge: - def __init__(self, start_key: str, end_key: str): - self.start_key = start_key - self.end_key = end_key - - def flow(self, node_map: Dict[str, LangGraphNode]): - return ( - Channel.subscribe_to(self.start_key) | - node_map[self.start_key].get_runnable() | - Channel.write_to(self.end_key) - ) - - -class BranchEdge(LangGraphEdge): - - def flow(self, node_map: Dict[str, LangGraphNode]): - # flow should skip over the branch edge - raise NotImplementedError - - -class ConditionalEdge(LangGraphEdge): - - def __init__(self, base_key: str, branch_key: str): - self.base_key = base_key - self.branch_key = branch_key - if not branch_key.startswith(base_key) or not branch_key[len(base_key)] == ".": - raise ValueError(f"Invalid branch edge from {base_key} to {branch_key}") - - super().__init__(base_key, branch_key) - - def _branch(self, data, condition, mapping): - result = condition(data) - return Channel.write_to(mapping[result]) - - def flow(self, node_map: Dict[str, LangGraphNode]): - conditional_node = node_map[self.base_key] - - return ( - Channel.subscribe_to(self.start_key) | - ( - lambda x: self._branch( - x, - conditional_node.get_runnable(), - conditional_node.conditional_edge_mapping - ) - ) - ) +START = "__start__" +END = "__end__" class Graph: - def __init__(self): - end_node = End() - self.nodes = {end_node.key: end_node} - self.edges = [] - - # self.connections = {} - # self.branches = {} - self.entry_point: Optional[str] = None + self.nodes: dict[str, Runnable] = {} + self.edges = set[Edge]() + self.branches: defaultdict[str, list[Branch]] = defaultdict(list) - def add_node(self, node: Actor): - if node.key in self.nodes: - raise ValueError(f"Actor `{node.key}` already present.") - self.nodes[node.key] = node + def add_node(self, key: str, action: RunnableLike) -> None: + if key in self.nodes: + raise ValueError(f"Node `{key}` already present.") + self.nodes[key] = coerce_to_runnable(action) - def add_edge(self, start_key: str, end_key: str): + def add_edge(self, start_key: str, end_key: str) -> None: if start_key not in self.nodes: raise ValueError(f"Need to add_node `{start_key}` first") if end_key not in self.nodes: raise ValueError(f"Need to add_node `{end_key}` first") # TODO: support multiple message passing - if start_key in set(edge.start_key for edge in self.edges): + if start_key in set(start for start, _ in self.edges): raise ValueError(f"Already found path for {start_key}") - - self.edges.append(LangGraphEdge(start_key, end_key)) + + self.edges.add((start_key, end_key)) def add_conditional_edges( self, start_key: str, - condition: Callable[Any, str], - conditional_edge_mapping: Dict[str, str]): + condition: Callable[..., str], + conditional_edge_mapping: Dict[str, str], + ): + if start_key not in self.nodes: + raise ValueError(f"Need to add_node `{start_key}` first") - conditional_node = Conditional( - f"_conditional_from_{start_key}", - conditional_edge_mapping, - condition - ) + self.branches[start_key].append(Branch(condition, conditional_edge_mapping)) - self.add_node(conditional_node) - self.add_edge(start_key, conditional_node.key) - - for branch in conditional_node.branches: - self.add_node(branch) - self.edges.append(ConditionalEdge(conditional_node.key, branch.key)) - self.edges.append( - BranchEdge(branch.key, conditional_node.conditional_edge_mapping[branch.condition]) - ) - - def set_entry_point(self, key: str): if key not in self.nodes: - raise ValueError(f"Need to add_node `{node.key}` first") + raise ValueError(f"Need to add_node `{key}` first") self.entry_point = key def set_finish_point(self, key: str): if key not in self.nodes: - raise ValueError(f"Need to add_node `{node.key}` first") - self.add_edge(key, "end") + raise ValueError(f"Need to add_node `{key}` first") + self.finish_point = key def compile(self): - ################################################ # STEP 1: VALIDATE GRAPH STRUCTURE # ################################################ - seen_node_keys = set() - all_node_keys = set(self.nodes.keys()) - - edge_map = {} - for edge in self.edges: - edge_map[edge.start_key] = edge_map.get(edge.start_key, []) + [edge.end_key] - to_see = [self.entry_point] - while len(to_see) > 0: - current = to_see.pop(0) - if current in seen_node_keys: - continue + all_starts = ( + {start for start, _ in self.edges} + | {start for start in self.branches} + | ({self.finish_point} if hasattr(self, "finish_point") else set()) + ) + all_ends = ( + {end for _, end in self.edges} + | { + end + for branch_list in self.branches.values() + for branch in branch_list + for end in branch.ends.values() + } + | {self.entry_point} + ) - seen_node_keys.add(current) - next_nodes = edge_map.get(current, []) - to_see += next_nodes + for node in self.nodes: + if node not in all_ends: + raise ValueError(f"Node `{node}` is not reachable") + if node not in all_starts: + raise ValueError(f"Node `{node}` is a dead-end") - if len(next_nodes) == 0 and current != "end": - raise ValueError(f"Node {current} is a dead end") - - if seen_node_keys != all_node_keys: - raise ValueError(f"Found unreachable nodes: {list(all_node_keys - seen_node_keys)}") - - ################################################ # STEP 2: CREATE GRAPH # ################################################ + outgoing_edges = defaultdict(list) + for start, end in self.edges: + outgoing_edges[start].append(end) + if hasattr(self, "finish_point"): + outgoing_edges[self.finish_point].append(END) + chains = { - edge.start_key: edge.flow(self.nodes) - for edge in self.edges - # specifically skip over branch edges since they are defined purely for structure - if not isinstance(edge, BranchEdge) + key: ( + Channel.subscribe_to(key) + | node + | Channel.write_to(*outgoing_edges[key]) + ) + for key, node in self.nodes.items() } - - app = Pregel( + + for key, branches in self.branches.items(): + for branch in branches: + chains[key] |= branch.runnable + + return Pregel( chains=chains, input=self.entry_point, - output="end" + output=END, ) - return app - - - - - - - - - - diff --git a/permchain/pregel/__init__.py b/permchain/pregel/__init__.py index 1eee4933b..e97926b4c 100644 --- a/permchain/pregel/__init__.py +++ b/permchain/pregel/__init__.py @@ -633,7 +633,7 @@ def _updateable_channel_values(channels: Mapping[str, BaseChannel]) -> dict[str, """Return a dictionary of updateable channel values.""" values: dict[str, Any] = {} for k, v in channels.items(): - if isinstance(v, LastValue): + if isinstance(v, LastValue) and k not in [c.value for c in ReservedChannels]: try: values[k] = v.get() except EmptyChannelError: diff --git a/poetry.lock b/poetry.lock index f8f608c67..5a769b810 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1520,13 +1520,13 @@ files = [ [[package]] name = "langchain" -version = "0.0.353" +version = "0.1.0" description = "Building applications with LLMs through composability" optional = false python-versions = ">=3.8.1,<4.0" files = [ - {file = "langchain-0.0.353-py3-none-any.whl", hash = "sha256:54cac8b74fbefacddcdf0c443619a7331d6b59fe94fa2a48a4d7da2b59cf1f63"}, - {file = "langchain-0.0.353.tar.gz", hash = "sha256:a095ea819f13a3606ced699182a8369eb2d77034ec8c913983675d6dd9a98196"}, + {file = "langchain-0.1.0-py3-none-any.whl", hash = "sha256:8652e74b039333a55c79faff4400b077ba1bd0ddce5255574e42d301c05c1733"}, + {file = "langchain-0.1.0.tar.gz", hash = "sha256:d43119f8d3fda2c8ddf8c3a19bd5b94b347e27d1867ff14a921b90bdbed0668a"}, ] [package.dependencies] @@ -1534,9 +1534,9 @@ aiohttp = ">=3.8.3,<4.0.0" async-timeout = {version = ">=4.0.0,<5.0.0", markers = "python_version < \"3.11\""} dataclasses-json = ">=0.5.7,<0.7" jsonpatch = ">=1.33,<2.0" -langchain-community = ">=0.0.2,<0.1" -langchain-core = ">=0.1.4,<0.2" -langsmith = ">=0.0.70,<0.1.0" +langchain-community = ">=0.0.9,<0.1" +langchain-core = ">=0.1.7,<0.2" +langsmith = ">=0.0.77,<0.1.0" numpy = ">=1,<2" pydantic = ">=1,<3" PyYAML = ">=5.3" @@ -1551,7 +1551,7 @@ cli = ["typer (>=0.9.0,<0.10.0)"] cohere = ["cohere (>=4,<5)"] docarray = ["docarray[hnswlib] (>=0.32.0,<0.33.0)"] embeddings = ["sentence-transformers (>=2,<3)"] -extended-testing = ["aiosqlite (>=0.19.0,<0.20.0)", "aleph-alpha-client (>=2.15.0,<3.0.0)", "anthropic (>=0.3.11,<0.4.0)", "arxiv (>=1.4,<2.0)", "assemblyai (>=0.17.0,<0.18.0)", "atlassian-python-api (>=3.36.0,<4.0.0)", "beautifulsoup4 (>=4,<5)", "bibtexparser (>=1.4.0,<2.0.0)", "cassio (>=0.1.0,<0.2.0)", "chardet (>=5.1.0,<6.0.0)", "cohere (>=4,<5)", "couchbase (>=4.1.9,<5.0.0)", "dashvector (>=1.0.1,<2.0.0)", "databricks-vectorsearch (>=0.21,<0.22)", "datasets (>=2.15.0,<3.0.0)", "dgml-utils (>=0.3.0,<0.4.0)", "esprima (>=4.0.1,<5.0.0)", "faiss-cpu (>=1,<2)", "feedparser (>=6.0.10,<7.0.0)", "fireworks-ai (>=0.9.0,<0.10.0)", "geopandas (>=0.13.1,<0.14.0)", "gitpython (>=3.1.32,<4.0.0)", "google-cloud-documentai (>=2.20.1,<3.0.0)", "gql (>=3.4.1,<4.0.0)", "hologres-vector (>=0.0.6,<0.0.7)", "html2text (>=2020.1.16,<2021.0.0)", "javelin-sdk (>=0.1.8,<0.2.0)", "jinja2 (>=3,<4)", "jq (>=1.4.1,<2.0.0)", "jsonschema (>1)", "lxml (>=4.9.2,<5.0.0)", "markdownify (>=0.11.6,<0.12.0)", "motor (>=3.3.1,<4.0.0)", "msal (>=1.25.0,<2.0.0)", "mwparserfromhell (>=0.6.4,<0.7.0)", "mwxml (>=0.3.3,<0.4.0)", "newspaper3k (>=0.2.8,<0.3.0)", "numexpr (>=2.8.6,<3.0.0)", "openai (<2)", "openapi-pydantic (>=0.3.2,<0.4.0)", "pandas (>=2.0.1,<3.0.0)", "pdfminer-six (>=20221105,<20221106)", "pgvector (>=0.1.6,<0.2.0)", "praw (>=7.7.1,<8.0.0)", "psychicapi (>=0.8.0,<0.9.0)", "py-trello (>=0.19.0,<0.20.0)", "pymupdf (>=1.22.3,<2.0.0)", "pypdf (>=3.4.0,<4.0.0)", "pypdfium2 (>=4.10.0,<5.0.0)", "pyspark (>=3.4.0,<4.0.0)", "rank-bm25 (>=0.2.2,<0.3.0)", "rapidfuzz (>=3.1.1,<4.0.0)", "rapidocr-onnxruntime (>=1.3.2,<2.0.0)", "requests-toolbelt (>=1.0.0,<2.0.0)", "rspace_client (>=2.5.0,<3.0.0)", "scikit-learn (>=1.2.2,<2.0.0)", "sqlite-vss (>=0.1.2,<0.2.0)", "streamlit (>=1.18.0,<2.0.0)", "sympy (>=1.12,<2.0)", "telethon (>=1.28.5,<2.0.0)", "timescale-vector (>=0.0.1,<0.0.2)", "tqdm (>=4.48.0)", "upstash-redis (>=0.15.0,<0.16.0)", "xata (>=1.0.0a7,<2.0.0)", "xmltodict (>=0.13.0,<0.14.0)"] +extended-testing = ["aiosqlite (>=0.19.0,<0.20.0)", "aleph-alpha-client (>=2.15.0,<3.0.0)", "anthropic (>=0.3.11,<0.4.0)", "arxiv (>=1.4,<2.0)", "assemblyai (>=0.17.0,<0.18.0)", "atlassian-python-api (>=3.36.0,<4.0.0)", "beautifulsoup4 (>=4,<5)", "bibtexparser (>=1.4.0,<2.0.0)", "cassio (>=0.1.0,<0.2.0)", "chardet (>=5.1.0,<6.0.0)", "cohere (>=4,<5)", "couchbase (>=4.1.9,<5.0.0)", "dashvector (>=1.0.1,<2.0.0)", "databricks-vectorsearch (>=0.21,<0.22)", "datasets (>=2.15.0,<3.0.0)", "dgml-utils (>=0.3.0,<0.4.0)", "esprima (>=4.0.1,<5.0.0)", "faiss-cpu (>=1,<2)", "feedparser (>=6.0.10,<7.0.0)", "fireworks-ai (>=0.9.0,<0.10.0)", "geopandas (>=0.13.1,<0.14.0)", "gitpython (>=3.1.32,<4.0.0)", "google-cloud-documentai (>=2.20.1,<3.0.0)", "gql (>=3.4.1,<4.0.0)", "hologres-vector (>=0.0.6,<0.0.7)", "html2text (>=2020.1.16,<2021.0.0)", "javelin-sdk (>=0.1.8,<0.2.0)", "jinja2 (>=3,<4)", "jq (>=1.4.1,<2.0.0)", "jsonschema (>1)", "langchain-openai (>=0.0.2,<0.1)", "lxml (>=4.9.2,<5.0.0)", "markdownify (>=0.11.6,<0.12.0)", "motor (>=3.3.1,<4.0.0)", "msal (>=1.25.0,<2.0.0)", "mwparserfromhell (>=0.6.4,<0.7.0)", "mwxml (>=0.3.3,<0.4.0)", "newspaper3k (>=0.2.8,<0.3.0)", "numexpr (>=2.8.6,<3.0.0)", "openai (<2)", "openapi-pydantic (>=0.3.2,<0.4.0)", "pandas (>=2.0.1,<3.0.0)", "pdfminer-six (>=20221105,<20221106)", "pgvector (>=0.1.6,<0.2.0)", "praw (>=7.7.1,<8.0.0)", "psychicapi (>=0.8.0,<0.9.0)", "py-trello (>=0.19.0,<0.20.0)", "pymupdf (>=1.22.3,<2.0.0)", "pypdf (>=3.4.0,<4.0.0)", "pypdfium2 (>=4.10.0,<5.0.0)", "pyspark (>=3.4.0,<4.0.0)", "rank-bm25 (>=0.2.2,<0.3.0)", "rapidfuzz (>=3.1.1,<4.0.0)", "rapidocr-onnxruntime (>=1.3.2,<2.0.0)", "requests-toolbelt (>=1.0.0,<2.0.0)", "rspace_client (>=2.5.0,<3.0.0)", "scikit-learn (>=1.2.2,<2.0.0)", "sqlite-vss (>=0.1.2,<0.2.0)", "streamlit (>=1.18.0,<2.0.0)", "sympy (>=1.12,<2.0)", "telethon (>=1.28.5,<2.0.0)", "timescale-vector (>=0.0.1,<0.0.2)", "tqdm (>=4.48.0)", "upstash-redis (>=0.15.0,<0.16.0)", "xata (>=1.0.0a7,<2.0.0)", "xmltodict (>=0.13.0,<0.14.0)"] javascript = ["esprima (>=4.0.1,<5.0.0)"] llms = ["clarifai (>=9.1.0)", "cohere (>=4,<5)", "huggingface_hub (>=0,<1)", "manifest-ml (>=0.0.1,<0.0.2)", "nlpcloud (>=1,<2)", "openai (<2)", "openlm (>=0.0.5,<0.0.6)", "torch (>=1,<3)", "transformers (>=4,<5)"] openai = ["openai (<2)", "tiktoken (>=0.3.2,<0.6.0)"] @@ -1560,19 +1560,19 @@ text-helpers = ["chardet (>=5.1.0,<6.0.0)"] [[package]] name = "langchain-community" -version = "0.0.7" +version = "0.0.9" description = "Community contributed LangChain integrations." optional = false python-versions = ">=3.8.1,<4.0" files = [ - {file = "langchain_community-0.0.7-py3-none-any.whl", hash = "sha256:468af187bfffe753426cc4548132824be7df9404d38ceef2f873087290d8ff0e"}, - {file = "langchain_community-0.0.7.tar.gz", hash = "sha256:cfbeb25cac7dff3c021f3c82aa243fc80f80082d6f6fdcc79daf36b1408828cc"}, + {file = "langchain_community-0.0.9-py3-none-any.whl", hash = "sha256:21e1f96c776541255b7067f32aafbf065f78a33be8f0e2660080ddc3e9ed48b7"}, + {file = "langchain_community-0.0.9.tar.gz", hash = "sha256:b14f10b249fd61b0b8e3d2896f85c2d577eb4a5e2ae01291e2a4ebbe1bb3c370"}, ] [package.dependencies] aiohttp = ">=3.8.3,<4.0.0" dataclasses-json = ">=0.5.7,<0.7" -langchain-core = ">=0.1,<0.2" +langchain-core = ">=0.1.7,<0.2" langsmith = ">=0.0.63,<0.1.0" numpy = ">=1,<2" PyYAML = ">=5.3" @@ -1582,17 +1582,17 @@ tenacity = ">=8.1.0,<9.0.0" [package.extras] cli = ["typer (>=0.9.0,<0.10.0)"] -extended-testing = ["aiosqlite (>=0.19.0,<0.20.0)", "aleph-alpha-client (>=2.15.0,<3.0.0)", "anthropic (>=0.3.11,<0.4.0)", "arxiv (>=1.4,<2.0)", "assemblyai (>=0.17.0,<0.18.0)", "atlassian-python-api (>=3.36.0,<4.0.0)", "azure-ai-documentintelligence (>=1.0.0b1,<2.0.0)", "beautifulsoup4 (>=4,<5)", "bibtexparser (>=1.4.0,<2.0.0)", "cassio (>=0.1.0,<0.2.0)", "chardet (>=5.1.0,<6.0.0)", "cohere (>=4,<5)", "dashvector (>=1.0.1,<2.0.0)", "databricks-vectorsearch (>=0.21,<0.22)", "datasets (>=2.15.0,<3.0.0)", "dgml-utils (>=0.3.0,<0.4.0)", "esprima (>=4.0.1,<5.0.0)", "faiss-cpu (>=1,<2)", "feedparser (>=6.0.10,<7.0.0)", "fireworks-ai (>=0.9.0,<0.10.0)", "geopandas (>=0.13.1,<0.14.0)", "gitpython (>=3.1.32,<4.0.0)", "google-cloud-documentai (>=2.20.1,<3.0.0)", "gql (>=3.4.1,<4.0.0)", "gradientai (>=1.4.0,<2.0.0)", "hologres-vector (>=0.0.6,<0.0.7)", "html2text (>=2020.1.16,<2021.0.0)", "javelin-sdk (>=0.1.8,<0.2.0)", "jinja2 (>=3,<4)", "jq (>=1.4.1,<2.0.0)", "jsonschema (>1)", "lxml (>=4.9.2,<5.0.0)", "markdownify (>=0.11.6,<0.12.0)", "motor (>=3.3.1,<4.0.0)", "msal (>=1.25.0,<2.0.0)", "mwparserfromhell (>=0.6.4,<0.7.0)", "mwxml (>=0.3.3,<0.4.0)", "newspaper3k (>=0.2.8,<0.3.0)", "numexpr (>=2.8.6,<3.0.0)", "openai (<2)", "openapi-pydantic (>=0.3.2,<0.4.0)", "oracle-ads (>=2.9.1,<3.0.0)", "pandas (>=2.0.1,<3.0.0)", "pdfminer-six (>=20221105,<20221106)", "pgvector (>=0.1.6,<0.2.0)", "praw (>=7.7.1,<8.0.0)", "psychicapi (>=0.8.0,<0.9.0)", "py-trello (>=0.19.0,<0.20.0)", "pymupdf (>=1.22.3,<2.0.0)", "pypdf (>=3.4.0,<4.0.0)", "pypdfium2 (>=4.10.0,<5.0.0)", "pyspark (>=3.4.0,<4.0.0)", "rank-bm25 (>=0.2.2,<0.3.0)", "rapidfuzz (>=3.1.1,<4.0.0)", "rapidocr-onnxruntime (>=1.3.2,<2.0.0)", "requests-toolbelt (>=1.0.0,<2.0.0)", "rspace_client (>=2.5.0,<3.0.0)", "scikit-learn (>=1.2.2,<2.0.0)", "sqlite-vss (>=0.1.2,<0.2.0)", "streamlit (>=1.18.0,<2.0.0)", "sympy (>=1.12,<2.0)", "telethon (>=1.28.5,<2.0.0)", "timescale-vector (>=0.0.1,<0.0.2)", "tqdm (>=4.48.0)", "upstash-redis (>=0.15.0,<0.16.0)", "xata (>=1.0.0a7,<2.0.0)", "xmltodict (>=0.13.0,<0.14.0)"] +extended-testing = ["aiosqlite (>=0.19.0,<0.20.0)", "aleph-alpha-client (>=2.15.0,<3.0.0)", "anthropic (>=0.3.11,<0.4.0)", "arxiv (>=1.4,<2.0)", "assemblyai (>=0.17.0,<0.18.0)", "atlassian-python-api (>=3.36.0,<4.0.0)", "azure-ai-documentintelligence (>=1.0.0b1,<2.0.0)", "beautifulsoup4 (>=4,<5)", "bibtexparser (>=1.4.0,<2.0.0)", "cassio (>=0.1.0,<0.2.0)", "chardet (>=5.1.0,<6.0.0)", "cohere (>=4,<5)", "dashvector (>=1.0.1,<2.0.0)", "databricks-vectorsearch (>=0.21,<0.22)", "datasets (>=2.15.0,<3.0.0)", "dgml-utils (>=0.3.0,<0.4.0)", "esprima (>=4.0.1,<5.0.0)", "faiss-cpu (>=1,<2)", "feedparser (>=6.0.10,<7.0.0)", "fireworks-ai (>=0.9.0,<0.10.0)", "geopandas (>=0.13.1,<0.14.0)", "gitpython (>=3.1.32,<4.0.0)", "google-cloud-documentai (>=2.20.1,<3.0.0)", "gql (>=3.4.1,<4.0.0)", "gradientai (>=1.4.0,<2.0.0)", "hologres-vector (>=0.0.6,<0.0.7)", "html2text (>=2020.1.16,<2021.0.0)", "javelin-sdk (>=0.1.8,<0.2.0)", "jinja2 (>=3,<4)", "jq (>=1.4.1,<2.0.0)", "jsonschema (>1)", "lxml (>=4.9.2,<5.0.0)", "markdownify (>=0.11.6,<0.12.0)", "motor (>=3.3.1,<4.0.0)", "msal (>=1.25.0,<2.0.0)", "mwparserfromhell (>=0.6.4,<0.7.0)", "mwxml (>=0.3.3,<0.4.0)", "newspaper3k (>=0.2.8,<0.3.0)", "numexpr (>=2.8.6,<3.0.0)", "openai (<2)", "openapi-pydantic (>=0.3.2,<0.4.0)", "oracle-ads (>=2.9.1,<3.0.0)", "pandas (>=2.0.1,<3.0.0)", "pdfminer-six (>=20221105,<20221106)", "pgvector (>=0.1.6,<0.2.0)", "praw (>=7.7.1,<8.0.0)", "psychicapi (>=0.8.0,<0.9.0)", "py-trello (>=0.19.0,<0.20.0)", "pymupdf (>=1.22.3,<2.0.0)", "pypdf (>=3.4.0,<4.0.0)", "pypdfium2 (>=4.10.0,<5.0.0)", "pyspark (>=3.4.0,<4.0.0)", "rank-bm25 (>=0.2.2,<0.3.0)", "rapidfuzz (>=3.1.1,<4.0.0)", "rapidocr-onnxruntime (>=1.3.2,<2.0.0)", "requests-toolbelt (>=1.0.0,<2.0.0)", "rspace_client (>=2.5.0,<3.0.0)", "scikit-learn (>=1.2.2,<2.0.0)", "sqlite-vss (>=0.1.2,<0.2.0)", "streamlit (>=1.18.0,<2.0.0)", "sympy (>=1.12,<2.0)", "telethon (>=1.28.5,<2.0.0)", "timescale-vector (>=0.0.1,<0.0.2)", "tqdm (>=4.48.0)", "upstash-redis (>=0.15.0,<0.16.0)", "xata (>=1.0.0a7,<2.0.0)", "xmltodict (>=0.13.0,<0.14.0)", "zhipuai (>=1.0.7,<2.0.0)"] [[package]] name = "langchain-core" -version = "0.1.4" +version = "0.1.7" description = "Building applications with LLMs through composability" optional = false python-versions = ">=3.8.1,<4.0" files = [ - {file = "langchain_core-0.1.4-py3-none-any.whl", hash = "sha256:c62bd362d5abf5359436a99b29629e12a4d1ede9f1704dc958cdb8530a791efd"}, - {file = "langchain_core-0.1.4.tar.gz", hash = "sha256:f700138689c9014e23d3c29796a892dccf7f2a42901cb8817671823e1a24724c"}, + {file = "langchain_core-0.1.7-py3-none-any.whl", hash = "sha256:c66327dbb4b7d4ab911556aa0511ebf4f40801ad66d98778fb5566dba45b0091"}, + {file = "langchain_core-0.1.7.tar.gz", hash = "sha256:c05211a309721d67aa5a681c946a2f010e14632a2bea3728da0a30a2534efa9e"}, ] [package.dependencies] @@ -1625,13 +1625,13 @@ types-requests = ">=2.31.0.2,<3.0.0.0" [[package]] name = "langsmith" -version = "0.0.75" +version = "0.0.77" description = "Client library to connect to the LangSmith LLM Tracing and Evaluation Platform." optional = false python-versions = ">=3.8.1,<4.0" files = [ - {file = "langsmith-0.0.75-py3-none-any.whl", hash = "sha256:3e008854204c5eaae007f34c7e249059218605689c385c037f6a40cac044833b"}, - {file = "langsmith-0.0.75.tar.gz", hash = "sha256:3fd44c58bd53cb9366af3de129c7f11b6947914f1bb598a585240df0e2c566eb"}, + {file = "langsmith-0.0.77-py3-none-any.whl", hash = "sha256:750c0aa9177240c64e131d831e009ed08dd59038f7cabbd0bbcf62ccb7c8dcac"}, + {file = "langsmith-0.0.77.tar.gz", hash = "sha256:c4c8d3a96ad8671a41064f3ccc673e2e22a4153e823b19f915c9c9b8a4f33a2c"}, ] [package.dependencies] @@ -3629,4 +3629,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p [metadata] lock-version = "2.0" python-versions = ">=3.8.1,<4.0" -content-hash = "4e4d02201942d821f9a687e6c0eb787ed841d537498a0fd118226cd48f8d022c" +content-hash = "4f1c52f5b61024577a687d37a2d42023f6519f31f36f47449779db8f4f3ca355" diff --git a/pyproject.toml b/pyproject.toml index 88bf3781c..ce2741652 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -37,7 +37,7 @@ optional = true [tool.poetry.group.dev.dependencies] jupyter = "^1.0.0" openai = "^0.27.8" -langchain = "^0.0.353" +langchain = "^0.1.0" langchainhub = "^0.1.14" [tool.ruff] diff --git a/tests/test_graph.py b/tests/test_graph.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/test_pregel.py b/tests/test_pregel.py index aad297018..163c9ea11 100644 --- a/tests/test_pregel.py +++ b/tests/test_pregel.py @@ -8,7 +8,7 @@ import pytest from langchain_core.runnables import RunnablePassthrough from pytest_mock import MockerFixture -from permchain import Channel, Pregel +from permchain import Channel, Graph, Pregel from permchain.channels.base import InvalidUpdateError from permchain.channels.binop import BinaryOperatorAggregate from permchain.channels.context import Context @@ -33,12 +33,19 @@ def test_invoke_single_process_in_out(mocker: MockerFixture) -> None: input="input", output="output", ) + graph = Graph() + graph.add_node("add_one", add_one) + graph.set_entry_point("add_one") + graph.set_finish_point("add_one") + gapp = graph.compile() assert app.input_schema.schema() == {"title": "PregelInput", "type": "integer"} assert app.output_schema.schema() == {"title": "PregelOutput", "type": "integer"} assert app.invoke(2) == 3 assert repr(app), "does not raise recursion error" + assert gapp.invoke(2) == 3 + def test_invoke_single_process_in_out_implicit_channels(mocker: MockerFixture) -> None: add_one = mocker.Mock(side_effect=lambda x: x + 1) @@ -152,7 +159,6 @@ def test_invoke_two_processes_in_out(mocker: MockerFixture) -> None: assert view.values == { "inbox": 3, "input": 2, - "is_last_step": False, } assert output is None elif view.step == 2: @@ -160,7 +166,6 @@ def test_invoke_two_processes_in_out(mocker: MockerFixture) -> None: "output": 4, "inbox": 3, "input": 2, - "is_last_step": False, } assert output == 4 @@ -169,7 +174,6 @@ def test_invoke_two_processes_in_out(mocker: MockerFixture) -> None: assert view.values == { "inbox": 3, "input": 2, - "is_last_step": False, } assert output is None # modify inbox value @@ -179,7 +183,49 @@ def test_invoke_two_processes_in_out(mocker: MockerFixture) -> None: "output": 6, "inbox": 5, "input": 2, - "is_last_step": False, + } + # output is different now + assert output == 6 + + graph = Graph() + graph.add_node("add_one", add_one) + graph.add_node("add_one_more", add_one) + graph.set_entry_point("add_one") + graph.set_finish_point("add_one_more") + graph.add_edge("add_one", "add_one_more") + gapp = graph.compile() + + assert gapp.invoke(2) == 4 + + for output, view in gapp.step(2): + if view.step == 1: + assert view.values == { + "add_one": 2, + "add_one_more": 3, + } + assert output is None + elif view.step == 2: + assert view.values == { + "add_one": 2, + "add_one_more": 3, + "__end__": 4, + } + assert output == 4 + + for output, view in gapp.step(2): + if view.step == 1: + assert view.values == { + "add_one": 2, + "add_one_more": 3, + } + assert output is None + # modify inbox value + view.values["add_one_more"] = 5 + elif view.step == 2: + assert view.values == { + "add_one": 2, + "add_one_more": 5, + "__end__": 6, } # output is different now assert output == 6 @@ -217,6 +263,16 @@ def test_batch_two_processes_in_out() -> None: assert app.batch([3, 2, 1, 3, 5]) == [5, 4, 3, 5, 7] + graph = Graph() + graph.add_node("add_one", add_one_with_delay) + graph.add_node("add_one_more", add_one_with_delay) + graph.set_entry_point("add_one") + graph.set_finish_point("add_one_more") + graph.add_edge("add_one", "add_one_more") + gapp = graph.compile() + + assert gapp.batch([3, 2, 1, 3, 5]) == [5, 4, 3, 5, 7] + def test_invoke_many_processes_in_out(mocker: MockerFixture) -> None: test_size = 100 diff --git a/tests/test_pregel_async.py b/tests/test_pregel_async.py index b32dc17d2..90e82d94c 100644 --- a/tests/test_pregel_async.py +++ b/tests/test_pregel_async.py @@ -157,7 +157,6 @@ async def test_invoke_two_processes_in_out(mocker: MockerFixture) -> None: assert view.values == { "inbox": 3, "input": 2, - "is_last_step": False, } assert output is None elif view.step == 2: @@ -165,7 +164,6 @@ async def test_invoke_two_processes_in_out(mocker: MockerFixture) -> None: "output": 4, "inbox": 3, "input": 2, - "is_last_step": False, } assert output == 4 @@ -174,7 +172,6 @@ async def test_invoke_two_processes_in_out(mocker: MockerFixture) -> None: assert view.values == { "inbox": 3, "input": 2, - "is_last_step": False, } assert output is None # modify inbox value @@ -184,7 +181,6 @@ async def test_invoke_two_processes_in_out(mocker: MockerFixture) -> None: "output": 6, "inbox": 5, "input": 2, - "is_last_step": False, } # output is different now assert output == 6 From de599be8a136c52a2453a6ca9da98ff831629c3e Mon Sep 17 00:00:00 2001 From: Nuno Campos Date: Sat, 6 Jan 2024 12:43:15 -0800 Subject: [PATCH 06/19] Rename chains to nodes --- examples/Untitled.ipynb | 139 ++++++++++++++++++++++++++++++++ examples/langgraph.ipynb | 62 ++++---------- permchain/langgraph/__init__.py | 6 +- permchain/pregel/__init__.py | 32 +++++--- permchain/pregel/model.py | 50 ++++++++++++ permchain/pregel/validate.py | 20 ++--- tests/test_pregel.py | 118 ++++++++++++--------------- tests/test_pregel_async.py | 114 ++++++++++++-------------- 8 files changed, 342 insertions(+), 199 deletions(-) create mode 100644 examples/Untitled.ipynb create mode 100644 permchain/pregel/model.py diff --git a/examples/Untitled.ipynb b/examples/Untitled.ipynb new file mode 100644 index 000000000..36f1f3a76 --- /dev/null +++ b/examples/Untitled.ipynb @@ -0,0 +1,139 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "2589ed8b-a781-45cc-aeb6-0eebb6469100", + "metadata": {}, + "outputs": [], + "source": [ + "from langchain.hub import pull" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "de600f76-dd51-415f-afae-f8574cb6f99e", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " \n" + ] + } + ], + "source": [ + "pull('homanp/superagent')" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "b4831d38-7bb1-49a2-9efa-802adc24110f", + "metadata": {}, + "outputs": [], + "source": [ + "from langchain.load import loads" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "2ef796f9-7b34-462e-acb6-25cd116b9045", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/Users/nuno/dev/langchain/libs/core/langchain_core/_api/beta_decorator.py:162: LangChainBetaWarning: The function `loads` is in beta. It is actively being worked on, so the API may change.\n", + " warn_beta(\n" + ] + }, + { + "data": { + "text/plain": [ + "{}" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "loads('{}')" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "4b6d8788-0b6f-4bd6-b6cf-e2e4e80f4707", + "metadata": {}, + "outputs": [], + "source": [ + "from langchain_core.beta.runnables.context import ContextGet" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "6975707d-58eb-4642-9618-76e37cdeb5e1", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/Users/nuno/dev/langchain/libs/core/langchain_core/_api/beta_decorator.py:162: LangChainBetaWarning: The class `ContextGet` is in beta. It is actively being worked on, so the API may change.\n", + " warn_beta(\n" + ] + }, + { + "data": { + "text/plain": [ + "ContextGet(key='hello')" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "ContextGet(key='hello')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1977eda2-4c4a-4bb0-886a-fe274599dc50", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.5" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/examples/langgraph.ipynb b/examples/langgraph.ipynb index 505ee9162..b502b1e33 100644 --- a/examples/langgraph.ipynb +++ b/examples/langgraph.ipynb @@ -14,13 +14,18 @@ "id": "d642e6af-217a-4414-a78c-509b44155eca", "metadata": {}, "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "input_variables=['agent_scratchpad', 'input'] input_types={'chat_history': typing.List[typing.Union[langchain_core.messages.ai.AIMessage, langchain_core.messages.human.HumanMessage, langchain_core.messages.chat.ChatMessage, langchain_core.messages.system.SystemMessage, langchain_core.messages.function.FunctionMessage, langchain_core.messages.tool.ToolMessage]], 'agent_scratchpad': typing.List[typing.Union[langchain_core.messages.ai.AIMessage, langchain_core.messages.human.HumanMessage, langchain_core.messages.chat.ChatMessage, langchain_core.messages.system.SystemMessage, langchain_core.messages.function.FunctionMessage, langchain_core.messages.tool.ToolMessage]]} messages=[SystemMessagePromptTemplate(prompt=PromptTemplate(input_variables=[], template='You are a helpful assistant')), MessagesPlaceholder(variable_name='chat_history', optional=True), HumanMessagePromptTemplate(prompt=PromptTemplate(input_variables=['input'], template='{input}')), MessagesPlaceholder(variable_name='agent_scratchpad')]\n" + ] + }, { "name": "stderr", "output_type": "stream", "text": [ - "/Users/nuno/dev/permchain/.venv/lib/python3.11/site-packages/langchain_core/_api/beta_decorator.py:160: LangChainBetaWarning: The function `loads` is in beta. It is actively being worked on, so the API may change.\n", - " warn_beta(\n", - "/Users/nuno/dev/permchain/.venv/lib/python3.11/site-packages/langchain_core/_api/deprecation.py:189: LangChainDeprecationWarning: The class `ChatOpenAI` was deprecated in LangChain 0.1.0 and will be removed in 0.2.0. Use langchain_openai.ChatOpenAI instead.\n", + "/Users/nuno/dev/langchain/libs/core/langchain_core/_api/deprecation.py:191: LangChainDeprecationWarning: The class `ChatOpenAI` was deprecated in LangChain 0.1.0 and will be removed in 0.2.0. Use langchain_openai.ChatOpenAI instead.\n", " warn_deprecated(\n" ] } @@ -92,25 +97,10 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "id": "c46bd262-9605-4449-9391-f6b6e0fe440e", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'input': 'what is the weather in sf',\n", - " 'intermediate_steps': [(AgentActionMessageLog(tool='tavily_search_results_json', tool_input={'query': 'current weather in San Francisco'}, log=\"\\nInvoking: `tavily_search_results_json` with `{'query': 'current weather in San Francisco'}`\\n\\n\\n\", message_log=[AIMessage(content='', additional_kwargs={'function_call': {'name': 'tavily_search_results_json', 'arguments': '{\"query\":\"current weather in San Francisco\"}'}})]),\n", - " [{'url': 'https://www.weather25.com/north-america/usa/california/san-francisco',\n", - " 'content': 'will give you an idea of weather trends in San Francisco. For example, the weather in San Francisco in January 2024. San Francisco 14 day weather The weather today in San Francisco San Francisco weather report the weather in San Francisco including humidity, wind, chance of rain and more on the San Francisco current weather Weather25.com provides all the information that you need to know about the weather in San Francisco, United States.The current temperature in San Francisco is ° F. You can find more detailed information about the weather in San Francisco including humidity, wind, chance of rain and more on the San Francisco current weather page. The weather in San Francisco'}])],\n", - " 'agent_outcome': AgentFinish(return_values={'output': 'The current temperature in San Francisco is not available, but you can find detailed information about the weather in San Francisco, including humidity, wind, and chance of rain on the San Francisco current weather page. You can visit [Weather25.com](https://www.weather25.com/north-america/usa/california/san-francisco) for more information.'}, log='The current temperature in San Francisco is not available, but you can find detailed information about the weather in San Francisco, including humidity, wind, and chance of rain on the San Francisco current weather page. You can visit [Weather25.com](https://www.weather25.com/north-america/usa/california/san-francisco) for more information.')}" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "chain.invoke({\"input\": \"what is the weather in sf\", \"intermediate_steps\": []})" ] @@ -125,19 +115,10 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "id": "f6f96e81-4a20-4599-a625-8d18df6fa76d", "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/Users/nuno/dev/permchain/.venv/lib/python3.11/site-packages/langchain_core/_api/deprecation.py:189: LangChainDeprecationWarning: The class `ChatOpenAI` was deprecated in LangChain 0.1.0 and will be removed in 0.2.0. Use langchain_openai.ChatOpenAI instead.\n", - " warn_deprecated(\n" - ] - } - ], + "outputs": [], "source": [ "from langchain.agents import AgentExecutor, BaseMultiActionAgent, Tool\n", "from langchain.schema import AgentAction, AgentFinish\n", @@ -268,7 +249,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": null, "id": "7708fa95-547b-4bea-b126-3656de7d5873", "metadata": {}, "outputs": [], @@ -334,21 +315,10 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": null, "id": "d6cdd1cd-e480-4dd7-99b4-9018eb243b4d", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "AgentFinish(return_values={'output': 'The current weather in San Francisco can be accessed through various weather reporting services, which provide up-to-date temperature, humidity, wind, and chance of rain information [1]. Historically, San Francisco experiences a Mediterranean climate with average temperatures ranging from the low 50s to mid-60s Fahrenheit. The city is known for its microclimates, leading to significant weather variations across different neighborhoods. Summer temperatures are often cooler compared to other California areas due to the cold California Current and frequent fog, particularly in June and July. Winters are mild and moist, with most rainfall occurring between November and March, averaging around 23 inches annually. Wind is a prominent feature, especially in spring. For historical weather extremes and average wind speeds, additional specific data would be required.\\n\\nReferences:\\n[1] https://www.weather25.com/north-america/usa/california/san-francisco', 'initial_answer': \"The weather in San Francisco (SF) is characterized by a mild, Mediterranean-like climate with wet winters and dry summers. The city's unique topography and coastal location result in microclimates, where weather conditions can vary significantly from one neighborhood to another. Average temperatures typically range from the low 50s to the mid-60s Fahrenheit throughout the year. Summers in San Francisco are often cooler than in other parts of California due to the cold California Current offshore and the presence of fog, particularly in June and July. The fog usually burns off by the afternoon, leading to clearer skies and slightly warmer temperatures. Winters are mild and moist, with the majority of the city's rainfall occurring between November and March. Rainfall averages around 23 inches annually. Wind is also a notable feature of San Francisco's weather, with spring being the windiest season. Despite the general patterns, it's always advisable to dress in layers due to the potential for rapid weather changes.\"}, log='Reached max steps.')" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "workflow = Graph()\n", "\n", @@ -411,7 +381,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.6" + "version": "3.11.5" } }, "nbformat": 4, diff --git a/permchain/langgraph/__init__.py b/permchain/langgraph/__init__.py index cca29a9d1..f968b98b9 100644 --- a/permchain/langgraph/__init__.py +++ b/permchain/langgraph/__init__.py @@ -107,7 +107,7 @@ class Graph: if hasattr(self, "finish_point"): outgoing_edges[self.finish_point].append(END) - chains = { + nodes = { key: ( Channel.subscribe_to(key) | node @@ -118,10 +118,10 @@ class Graph: for key, branches in self.branches.items(): for branch in branches: - chains[key] |= branch.runnable + nodes[key] |= branch.runnable return Pregel( - chains=chains, + nodes=nodes, input=self.entry_point, output=END, ) diff --git a/permchain/pregel/__init__.py b/permchain/pregel/__init__.py index e97926b4c..d7444b5d8 100644 --- a/permchain/pregel/__init__.py +++ b/permchain/pregel/__init__.py @@ -61,7 +61,7 @@ from permchain.pregel.io import map_input, map_output from permchain.pregel.log import logger from permchain.pregel.read import ChannelBatch, ChannelInvoke from permchain.pregel.reserved import ReservedChannels -from permchain.pregel.validate import validate_chains_channels +from permchain.pregel.validate import validate_graph from permchain.pregel.write import ChannelWrite WriteValue = Union[ @@ -81,12 +81,22 @@ def _coerce_write_value(value: WriteValue) -> Runnable[Input, Output]: class Channel: @overload @classmethod - def subscribe_to(cls, channels: str, key: Optional[str] = None) -> ChannelInvoke: + def subscribe_to( + cls, + channels: str, + key: Optional[str] = None, + when: Callable[[Any], bool] | None = None, + ) -> ChannelInvoke: ... @overload @classmethod - def subscribe_to(cls, channels: Sequence[str], key: None = None) -> ChannelInvoke: + def subscribe_to( + cls, + channels: Sequence[str], + key: None = None, + when: Callable[[Any], bool] | None = None, + ) -> ChannelInvoke: ... @classmethod @@ -134,7 +144,7 @@ class Channel: class Pregel(RunnableSerializable[dict[str, Any] | Any, dict[str, Any] | Any]): - chains: Mapping[str, ChannelInvoke | ChannelBatch] + nodes: Mapping[str, ChannelInvoke | ChannelBatch] channels: Mapping[str, BaseChannel] = Field(default_factory=dict) @@ -153,15 +163,15 @@ class Pregel(RunnableSerializable[dict[str, Any] | Any, dict[str, Any] | Any]): @root_validator(skip_on_failure=True) def validate_pregel(cls, values: dict[str, Any]) -> dict[str, Any]: - validate_chains_channels( - values["chains"], values["channels"], values["input"], values["output"] + validate_graph( + values["nodes"], values["channels"], values["input"], values["output"] ) return values @property def config_specs(self) -> list[ConfigurableFieldSpec]: return get_unique_config_specs( - [spec for chain in self.chains.values() for spec in chain.config_specs] + [spec for node in self.nodes.values() for spec in node.config_specs] + (self.saver.config_specs if self.saver is not None else []) ) @@ -208,8 +218,8 @@ class Pregel(RunnableSerializable[dict[str, Any] | Any, dict[str, Any] | Any]): ) -> Iterator[tuple[dict[str, Any] | Any, CheckpointView]]: if config["recursion_limit"] < 1: raise ValueError("recursion_limit must be at least 1") - # copy chains to ignore mutations during execution - processes = {**self.chains} + # copy nodes to ignore mutations during execution + processes = {**self.nodes} # get checkpoint from saver, or create an empty one checkpoint = self.saver.get(config) if self.saver else None checkpoint = checkpoint or empty_checkpoint() @@ -305,8 +315,8 @@ class Pregel(RunnableSerializable[dict[str, Any] | Any, dict[str, Any] | Any]): ) -> AsyncIterator[tuple[dict[str, Any] | Any, CheckpointView]]: if config["recursion_limit"] < 1: raise ValueError("recursion_limit must be at least 1") - # copy chains to ignore mutations during execution - processes = {**self.chains} + # copy nodes to ignore mutations during execution + processes = {**self.nodes} # get checkpoint from saver, or create an empty one checkpoint = await self.saver.aget(config) if self.saver else None checkpoint = checkpoint or empty_checkpoint() diff --git a/permchain/pregel/model.py b/permchain/pregel/model.py new file mode 100644 index 000000000..8607ed374 --- /dev/null +++ b/permchain/pregel/model.py @@ -0,0 +1,50 @@ +from __future__ import annotations + +from dataclasses import dataclass, field +from typing import Any, ClassVar, Dict +from langchain_core.pydantic_v1 import dataclasses + +from permchain.checkpoint.base import BaseCheckpointAdapter +from permchain.pregel import Pregel + +dataclasses.DataclassClassOrWrapper + +from langchain_core.messages import BaseMessage +from langchain_core.runnables import RunnableLambda + +from permchain.pregel.read import ChannelInvoke + + +def on_change(field_name: str): + def decorator(func): + return ChannelInvoke(bound=RunnableLambda(func), triggers=[field_name]) + + return decorator + + +class DataclassProtocol: + __dataclass_fields__: ClassVar[Dict[str, Any]] + + +def thread(data: type[DataclassProtocol], thread_id: str, saver: BaseCheckpointAdapter): + return Pregel( + chains={ + v.__name__: v + for v in data.__dict__.values() + if isinstance(v, ChannelInvoke) + } + ) + + +@dataclass +class Agent: + messages: list[BaseMessage] = field(default_factory=list) + actions: list[BaseMessage] = field(default_factory=list) + + @on_change("messages") + def plan(self): + ... + + @on_change("actions") + def execute(self): + ... diff --git a/permchain/pregel/validate.py b/permchain/pregel/validate.py index 5c0dd6718..66a5c06b4 100644 --- a/permchain/pregel/validate.py +++ b/permchain/pregel/validate.py @@ -6,21 +6,21 @@ from permchain.pregel.read import ChannelBatch, ChannelInvoke from permchain.pregel.reserved import ReservedChannels -def validate_chains_channels( - chains: Mapping[str, ChannelInvoke | ChannelBatch], +def validate_graph( + nodes: Mapping[str, ChannelInvoke | ChannelBatch], channels: dict[str, BaseChannel], input: str | Sequence[str], output: str | Sequence[str], ) -> None: subscribed_channels = set[str]() - for chain in chains.values(): - if isinstance(chain, ChannelInvoke): - subscribed_channels.update(chain.channels.values()) - elif isinstance(chain, ChannelBatch): - subscribed_channels.add(chain.channel) + for node in nodes.values(): + if isinstance(node, ChannelInvoke): + subscribed_channels.update(node.channels.values()) + elif isinstance(node, ChannelBatch): + subscribed_channels.add(node.channel) else: raise TypeError( - f"Invalid chain type {type(chain)}, expected Channel.subscribe_to() or Channel.subscribe_to_each()" + f"Invalid node type {type(node)}, expected Channel.subscribe_to() or Channel.subscribe_to_each()" ) for chan in subscribed_channels: @@ -31,14 +31,14 @@ def validate_chains_channels( if input not in channels: channels[input] = LastValue(Any) # type: ignore[arg-type] if input not in subscribed_channels: - raise ValueError(f"Input channel {input} is not subscribed to by any chain") + raise ValueError(f"Input channel {input} is not subscribed to by any node") else: for chan in input: if chan not in channels: channels[chan] = LastValue(Any) # type: ignore[arg-type] if all(chan not in subscribed_channels for chan in input): raise ValueError( - f"None of the input channels {input} are subscribed to by any chain" + f"None of the input channels {input} are subscribed to by any node" ) if isinstance(output, str): diff --git a/tests/test_pregel.py b/tests/test_pregel.py index 163c9ea11..1a1187367 100644 --- a/tests/test_pregel.py +++ b/tests/test_pregel.py @@ -23,7 +23,7 @@ def test_invoke_single_process_in_out(mocker: MockerFixture) -> None: chain = Channel.subscribe_to("input") | add_one | Channel.write_to("output") app = Pregel( - chains={ + nodes={ "one": chain, }, channels={ @@ -51,7 +51,7 @@ def test_invoke_single_process_in_out_implicit_channels(mocker: MockerFixture) - add_one = mocker.Mock(side_effect=lambda x: x + 1) chain = Channel.subscribe_to("input") | add_one | Channel.write_to("output") - app = Pregel(chains={"one": chain}) + app = Pregel(nodes={"one": chain}) assert app.input_schema.schema() == {"title": "PregelInput"} assert app.output_schema.schema() == {"title": "PregelOutput"} @@ -66,7 +66,7 @@ def test_invoke_single_process_in_write_kwargs(mocker: MockerFixture) -> None: | Channel.write_to("output", fixed=5, output_plus_one=lambda x: x + 1) ) - app = Pregel(chains={"one": chain}, output=["output", "fixed", "output_plus_one"]) + app = Pregel(nodes={"one": chain}, output=["output", "fixed", "output_plus_one"]) assert app.input_schema.schema() == {"title": "PregelInput"} assert app.output_schema.schema() == { @@ -90,7 +90,7 @@ def test_invoke_single_process_in_out_reserved_is_last(mocker: MockerFixture) -> | Channel.write_to("output") ) - app = Pregel(chains={"one": chain}) + app = Pregel(nodes={"one": chain}) assert app.input_schema.schema() == {"title": "PregelInput"} assert app.output_schema.schema() == {"title": "PregelOutput"} @@ -103,7 +103,7 @@ def test_invoke_single_process_in_out_dict(mocker: MockerFixture) -> None: chain = Channel.subscribe_to("input") | add_one | Channel.write_to("output") app = Pregel( - chains={ + nodes={ "one": chain, }, output=["output"], @@ -123,7 +123,7 @@ def test_invoke_single_process_in_dict_out_dict(mocker: MockerFixture) -> None: chain = Channel.subscribe_to("input") | add_one | Channel.write_to("output") app = Pregel( - chains={ + nodes={ "one": chain, }, input=["input"], @@ -145,11 +145,11 @@ def test_invoke_single_process_in_dict_out_dict(mocker: MockerFixture) -> None: def test_invoke_two_processes_in_out(mocker: MockerFixture) -> None: add_one = mocker.Mock(side_effect=lambda x: x + 1) - chain_one = Channel.subscribe_to("input") | add_one | Channel.write_to("inbox") - chain_two = Channel.subscribe_to("inbox") | add_one | Channel.write_to("output") + one = Channel.subscribe_to("input") | add_one | Channel.write_to("inbox") + two = Channel.subscribe_to("inbox") | add_one | Channel.write_to("output") app = Pregel( - chains={"chain_one": chain_one, "chain_two": chain_two}, + nodes={"one": one, "two": two}, ) assert app.invoke(2) == 4 @@ -233,13 +233,11 @@ def test_invoke_two_processes_in_out(mocker: MockerFixture) -> None: def test_invoke_two_processes_in_dict_out(mocker: MockerFixture) -> None: add_one = mocker.Mock(side_effect=lambda x: x + 1) - chain_one = Channel.subscribe_to("input") | add_one | Channel.write_to("inbox") - chain_two = ( - Channel.subscribe_to_each("inbox") | add_one | Channel.write_to("output") - ) + one = Channel.subscribe_to("input") | add_one | Channel.write_to("inbox") + two = Channel.subscribe_to_each("inbox") | add_one | Channel.write_to("output") app = Pregel( - chains={"chain_one": chain_one, "chain_two": chain_two}, + nodes={"one": one, "two": two}, channels={"inbox": Topic(int)}, input=["input", "inbox"], ) @@ -252,14 +250,10 @@ def test_batch_two_processes_in_out() -> None: time.sleep(inp / 10) return inp + 1 - chain_one = ( - Channel.subscribe_to("input") | add_one_with_delay | Channel.write_to("one") - ) - chain_two = ( - Channel.subscribe_to("one") | add_one_with_delay | Channel.write_to("output") - ) + one = Channel.subscribe_to("input") | add_one_with_delay | Channel.write_to("one") + two = Channel.subscribe_to("one") | add_one_with_delay | Channel.write_to("output") - app = Pregel(chains={"chain_one": chain_one, "chain_two": chain_two}) + app = Pregel(nodes={"one": one, "two": two}) assert app.batch([3, 2, 1, 3, 5]) == [5, 4, 3, 5, 7] @@ -278,14 +272,14 @@ def test_invoke_many_processes_in_out(mocker: MockerFixture) -> None: test_size = 100 add_one = mocker.Mock(side_effect=lambda x: x + 1) - chains = {"-1": Channel.subscribe_to("input") | add_one | Channel.write_to("-1")} + nodes = {"-1": Channel.subscribe_to("input") | add_one | Channel.write_to("-1")} for i in range(test_size - 2): - chains[str(i)] = ( + nodes[str(i)] = ( Channel.subscribe_to(str(i - 1)) | add_one | Channel.write_to(str(i)) ) - chains["last"] = Channel.subscribe_to(str(i)) | add_one | Channel.write_to("output") + nodes["last"] = Channel.subscribe_to(str(i)) | add_one | Channel.write_to("output") - app = Pregel(chains=chains) + app = Pregel(nodes=nodes) for _ in range(10): assert app.invoke(2, {"recursion_limit": test_size}) == 2 + test_size @@ -300,14 +294,14 @@ def test_batch_many_processes_in_out(mocker: MockerFixture) -> None: test_size = 100 add_one = mocker.Mock(side_effect=lambda x: x + 1) - chains = {"-1": Channel.subscribe_to("input") | add_one | Channel.write_to("-1")} + nodes = {"-1": Channel.subscribe_to("input") | add_one | Channel.write_to("-1")} for i in range(test_size - 2): - chains[str(i)] = ( + nodes[str(i)] = ( Channel.subscribe_to(str(i - 1)) | add_one | Channel.write_to(str(i)) ) - chains["last"] = Channel.subscribe_to(str(i)) | add_one | Channel.write_to("output") + nodes["last"] = Channel.subscribe_to(str(i)) | add_one | Channel.write_to("output") - app = Pregel(chains=chains) + app = Pregel(nodes=nodes) for _ in range(3): assert app.batch([2, 1, 3, 4, 5], {"recursion_limit": test_size}) == [ @@ -331,10 +325,10 @@ def test_batch_many_processes_in_out(mocker: MockerFixture) -> None: def test_invoke_two_processes_two_in_two_out_invalid(mocker: MockerFixture) -> None: add_one = mocker.Mock(side_effect=lambda x: x + 1) - chain_one = Channel.subscribe_to("input") | add_one | Channel.write_to("output") - chain_two = Channel.subscribe_to("input") | add_one | Channel.write_to("output") + one = Channel.subscribe_to("input") | add_one | Channel.write_to("output") + two = Channel.subscribe_to("input") | add_one | Channel.write_to("output") - app = Pregel(chains={"chain_one": chain_one, "chain_two": chain_two}) + app = Pregel(nodes={"one": one, "two": two}) with pytest.raises(InvalidUpdateError): # LastValue channels can only be updated once per iteration @@ -344,11 +338,11 @@ def test_invoke_two_processes_two_in_two_out_invalid(mocker: MockerFixture) -> N def test_invoke_two_processes_two_in_two_out_valid(mocker: MockerFixture) -> None: add_one = mocker.Mock(side_effect=lambda x: x + 1) - chain_one = Channel.subscribe_to("input") | add_one | Channel.write_to("output") - chain_two = Channel.subscribe_to("input") | add_one | Channel.write_to("output") + one = Channel.subscribe_to("input") | add_one | Channel.write_to("output") + two = Channel.subscribe_to("input") | add_one | Channel.write_to("output") app = Pregel( - chains={"chain_one": chain_one, "chain_two": chain_two}, + nodes={"one": one, "two": two}, channels={"output": Topic(int)}, ) @@ -364,7 +358,7 @@ def test_invoke_checkpoint(mocker: MockerFixture) -> None: raise ValueError("Input is too large") return input - chain_one = ( + one = ( Channel.subscribe_to(["input"]).join(["total"]) | add_one | Channel.write_to("output", "total") @@ -374,7 +368,7 @@ def test_invoke_checkpoint(mocker: MockerFixture) -> None: memory = MemoryCheckpoint() app = Pregel( - chains={"chain_one": chain_one}, + nodes={"one": one}, channels={"total": BinaryOperatorAggregate(int, operator.add)}, saver=memory, ) @@ -410,15 +404,15 @@ def test_invoke_two_processes_two_in_join_two_out(mocker: MockerFixture) -> None add_one = mocker.Mock(side_effect=lambda x: x + 1) add_10_each = mocker.Mock(side_effect=lambda x: sorted(y + 10 for y in x)) - chain_one = Channel.subscribe_to("input") | add_one | Channel.write_to("inbox") + one = Channel.subscribe_to("input") | add_one | Channel.write_to("inbox") chain_three = Channel.subscribe_to("input") | add_one | Channel.write_to("inbox") chain_four = ( Channel.subscribe_to("inbox") | add_10_each | Channel.write_to("output") ) app = Pregel( - chains={ - "chain_one": chain_one, + nodes={ + "one": one, "chain_three": chain_three, "chain_four": chain_four, }, @@ -440,17 +434,17 @@ def test_invoke_join_then_call_other_app(mocker: MockerFixture) -> None: add_10_each = mocker.Mock(side_effect=lambda x: [y + 10 for y in x]) inner_app = Pregel( - chains={ + nodes={ "one": Channel.subscribe_to("input") | add_one | Channel.write_to("output") } ) - chain_one = ( + one = ( Channel.subscribe_to("input") | add_10_each | Channel.write_to("inbox_one").map() ) - chain_two = ( + two = ( Channel.subscribe_to("inbox_one") | inner_app.map() | sorted @@ -459,9 +453,9 @@ def test_invoke_join_then_call_other_app(mocker: MockerFixture) -> None: chain_three = Channel.subscribe_to("outbox_one") | sum | Channel.write_to("output") app = Pregel( - chains={ - "chain_one": chain_one, - "chain_two": chain_two, + nodes={ + "one": one, + "two": two, "chain_three": chain_three, }, channels={"inbox_one": Topic(int)}, @@ -477,28 +471,24 @@ def test_invoke_join_then_call_other_app(mocker: MockerFixture) -> None: def test_invoke_two_processes_one_in_two_out(mocker: MockerFixture) -> None: add_one = mocker.Mock(side_effect=lambda x: x + 1) - chain_one = ( + one = ( Channel.subscribe_to("input") | add_one | Channel.write_to(output=RunnablePassthrough(), between=RunnablePassthrough()) ) - chain_two = Channel.subscribe_to("between") | add_one | Channel.write_to("output") + two = Channel.subscribe_to("between") | add_one | Channel.write_to("output") - app = Pregel( - chains={"chain_one": chain_one, "chain_two": chain_two}, - ) + app = Pregel(nodes={"one": one, "two": two}) assert [c for c in app.stream(2)] == [3, 4] def test_invoke_two_processes_no_out(mocker: MockerFixture) -> None: add_one = mocker.Mock(side_effect=lambda x: x + 1) - chain_one = Channel.subscribe_to("input") | add_one | Channel.write_to("between") - chain_two = Channel.subscribe_to("between") | add_one + one = Channel.subscribe_to("input") | add_one | Channel.write_to("between") + two = Channel.subscribe_to("between") | add_one - app = Pregel( - chains={"chain_one": chain_one, "chain_two": chain_two}, - ) + app = Pregel(nodes={"one": one, "two": two}) # It finishes executing (once no more messages being published) # but returns nothing, as nothing was published to OUT topic @@ -508,13 +498,11 @@ def test_invoke_two_processes_no_out(mocker: MockerFixture) -> None: def test_invoke_two_processes_no_in(mocker: MockerFixture) -> None: add_one = mocker.Mock(side_effect=lambda x: x + 1) - chain_one = Channel.subscribe_to("between") | add_one | Channel.write_to("output") - chain_two = Channel.subscribe_to("between") | add_one + one = Channel.subscribe_to("between") | add_one | Channel.write_to("output") + two = Channel.subscribe_to("between") | add_one with pytest.raises(ValueError): - Pregel( - chains={"chain_one": chain_one, "chain_two": chain_two}, - ) + Pregel(nodes={"one": one, "two": two}) def test_channel_enter_exit_timing(mocker: MockerFixture) -> None: @@ -530,13 +518,11 @@ def test_channel_enter_exit_timing(mocker: MockerFixture) -> None: cleanup() add_one = mocker.Mock(side_effect=lambda x: x + 1) - chain_one = Channel.subscribe_to("input") | add_one | Channel.write_to("inbox") - chain_two = ( - Channel.subscribe_to_each("inbox") | add_one | Channel.write_to("output") - ) + one = Channel.subscribe_to("input") | add_one | Channel.write_to("inbox") + two = Channel.subscribe_to_each("inbox") | add_one | Channel.write_to("output") app = Pregel( - chains={"chain_one": chain_one, "chain_two": chain_two}, + nodes={"one": one, "two": two}, channels={ "inbox": Topic(int), "ctx": Context(an_int, typ=int), diff --git a/tests/test_pregel_async.py b/tests/test_pregel_async.py index 90e82d94c..879df9dfe 100644 --- a/tests/test_pregel_async.py +++ b/tests/test_pregel_async.py @@ -22,7 +22,7 @@ async def test_invoke_single_process_in_out(mocker: MockerFixture) -> None: chain = Channel.subscribe_to("input") | add_one | Channel.write_to("output") app = Pregel( - chains={ + nodes={ "one": chain, }, channels={ @@ -39,12 +39,12 @@ async def test_invoke_single_process_in_out(mocker: MockerFixture) -> None: async def test_invoke_single_process_in_out_implicit_channels( - mocker: MockerFixture + mocker: MockerFixture, ) -> None: add_one = mocker.Mock(side_effect=lambda x: x + 1) chain = Channel.subscribe_to("input") | add_one | Channel.write_to("output") - app = Pregel(chains={"one": chain}) + app = Pregel(nodes={"one": chain}) assert app.input_schema.schema() == {"title": "PregelInput"} assert app.output_schema.schema() == {"title": "PregelOutput"} @@ -59,7 +59,7 @@ async def test_invoke_single_process_in_write_kwargs(mocker: MockerFixture) -> N | Channel.write_to("output", fixed=5, output_plus_one=lambda x: x + 1) ) - app = Pregel(chains={"one": chain}, output=["output", "fixed", "output_plus_one"]) + app = Pregel(nodes={"one": chain}, output=["output", "fixed", "output_plus_one"]) assert app.input_schema.schema() == {"title": "PregelInput"} assert app.output_schema.schema() == { @@ -75,7 +75,7 @@ async def test_invoke_single_process_in_write_kwargs(mocker: MockerFixture) -> N async def test_invoke_single_process_in_out_reserved_is_last( - mocker: MockerFixture + mocker: MockerFixture, ) -> None: add_one = mocker.Mock(side_effect=lambda x: {**x, "input": x["input"] + 1}) @@ -85,7 +85,7 @@ async def test_invoke_single_process_in_out_reserved_is_last( | Channel.write_to("output") ) - app = Pregel(chains={"one": chain}) + app = Pregel(nodes={"one": chain}) assert app.input_schema.schema() == {"title": "PregelInput"} assert app.output_schema.schema() == {"title": "PregelOutput"} @@ -101,9 +101,7 @@ async def test_invoke_single_process_in_out_dict(mocker: MockerFixture) -> None: chain = Channel.subscribe_to("input") | add_one | Channel.write_to("output") app = Pregel( - chains={ - "one": chain, - }, + nodes={"one": chain}, output=["output"], ) @@ -121,7 +119,7 @@ async def test_invoke_single_process_in_dict_out_dict(mocker: MockerFixture) -> chain = Channel.subscribe_to("input") | add_one | Channel.write_to("output") app = Pregel( - chains={ + nodes={ "one": chain, }, input=["input"], @@ -143,12 +141,10 @@ async def test_invoke_single_process_in_dict_out_dict(mocker: MockerFixture) -> async def test_invoke_two_processes_in_out(mocker: MockerFixture) -> None: add_one = mocker.Mock(side_effect=lambda x: x + 1) - chain_one = Channel.subscribe_to("input") | add_one | Channel.write_to("inbox") - chain_two = Channel.subscribe_to("inbox") | add_one | Channel.write_to("output") + one = Channel.subscribe_to("input") | add_one | Channel.write_to("inbox") + two = Channel.subscribe_to("inbox") | add_one | Channel.write_to("output") - app = Pregel( - chains={"chain_one": chain_one, "chain_two": chain_two}, - ) + app = Pregel(nodes={"one": one, "two": two}) assert await app.ainvoke(2) == 4 @@ -188,13 +184,11 @@ async def test_invoke_two_processes_in_out(mocker: MockerFixture) -> None: async def test_invoke_two_processes_in_dict_out(mocker: MockerFixture) -> None: add_one = mocker.Mock(side_effect=lambda x: x + 1) - chain_one = Channel.subscribe_to("input") | add_one | Channel.write_to("inbox") - chain_two = ( - Channel.subscribe_to_each("inbox") | add_one | Channel.write_to("output") - ) + one = Channel.subscribe_to("input") | add_one | Channel.write_to("inbox") + two = Channel.subscribe_to_each("inbox") | add_one | Channel.write_to("output") pubsub = Pregel( - chains={"chain_one": chain_one, "chain_two": chain_two}, + nodes={"one": one, "two": two}, channels={"inbox": Topic(int)}, input=["input", "inbox"], ) @@ -208,15 +202,11 @@ async def test_batch_two_processes_in_out() -> None: await asyncio.sleep(inp / 10) return inp + 1 - chain_one = ( - Channel.subscribe_to("input") | add_one_with_delay | Channel.write_to("one") - ) - chain_two = ( - Channel.subscribe_to("one") | add_one_with_delay | Channel.write_to("output") - ) + one = Channel.subscribe_to("input") | add_one_with_delay | Channel.write_to("one") + two = Channel.subscribe_to("one") | add_one_with_delay | Channel.write_to("output") app = Pregel( - chains={"chain_one": chain_one, "chain_two": chain_two}, + nodes={"one": one, "two": two}, channels={"one": LastValue(int)}, ) @@ -227,14 +217,14 @@ async def test_invoke_many_processes_in_out(mocker: MockerFixture) -> None: test_size = 100 add_one = mocker.Mock(side_effect=lambda x: x + 1) - chains = {"-1": Channel.subscribe_to("input") | add_one | Channel.write_to("-1")} + nodes = {"-1": Channel.subscribe_to("input") | add_one | Channel.write_to("-1")} for i in range(test_size - 2): - chains[str(i)] = ( + nodes[str(i)] = ( Channel.subscribe_to(str(i - 1)) | add_one | Channel.write_to(str(i)) ) - chains["last"] = Channel.subscribe_to(str(i)) | add_one | Channel.write_to("output") + nodes["last"] = Channel.subscribe_to(str(i)) | add_one | Channel.write_to("output") - app = Pregel(chains=chains) + app = Pregel(nodes=nodes) # No state is left over from previous invocations for _ in range(10): @@ -250,14 +240,14 @@ async def test_batch_many_processes_in_out(mocker: MockerFixture) -> None: test_size = 100 add_one = mocker.Mock(side_effect=lambda x: x + 1) - chains = {"-1": Channel.subscribe_to("input") | add_one | Channel.write_to("-1")} + nodes = {"-1": Channel.subscribe_to("input") | add_one | Channel.write_to("-1")} for i in range(test_size - 2): - chains[str(i)] = ( + nodes[str(i)] = ( Channel.subscribe_to(str(i - 1)) | add_one | Channel.write_to(str(i)) ) - chains["last"] = Channel.subscribe_to(str(i)) | add_one | Channel.write_to("output") + nodes["last"] = Channel.subscribe_to(str(i)) | add_one | Channel.write_to("output") - app = Pregel(chains=chains) + app = Pregel(nodes=nodes) # No state is left over from previous invocations for _ in range(3): @@ -284,10 +274,10 @@ async def test_invoke_two_processes_two_in_two_out_invalid( ) -> None: add_one = mocker.Mock(side_effect=lambda x: x + 1) - chain_one = Channel.subscribe_to("input") | add_one | Channel.write_to("output") - chain_two = Channel.subscribe_to("input") | add_one | Channel.write_to("output") + one = Channel.subscribe_to("input") | add_one | Channel.write_to("output") + two = Channel.subscribe_to("input") | add_one | Channel.write_to("output") - app = Pregel(chains={"chain_one": chain_one, "chain_two": chain_two}) + app = Pregel(nodes={"one": one, "two": two}) with pytest.raises(InvalidUpdateError): # LastValue channels can only be updated once per iteration @@ -297,11 +287,11 @@ async def test_invoke_two_processes_two_in_two_out_invalid( async def test_invoke_two_processes_two_in_two_out_valid(mocker: MockerFixture) -> None: add_one = mocker.Mock(side_effect=lambda x: x + 1) - chain_one = Channel.subscribe_to("input") | add_one | Channel.write_to("output") - chain_two = Channel.subscribe_to("input") | add_one | Channel.write_to("output") + one = Channel.subscribe_to("input") | add_one | Channel.write_to("output") + two = Channel.subscribe_to("input") | add_one | Channel.write_to("output") app = Pregel( - chains={"chain_one": chain_one, "chain_two": chain_two}, + nodes={"one": one, "two": two}, channels={"output": Topic(int)}, ) @@ -317,7 +307,7 @@ async def test_invoke_checkpoint(mocker: MockerFixture) -> None: raise ValueError("Input is too large") return input - chain_one = ( + one = ( Channel.subscribe_to(["input"]).join(["total"]) | add_one | Channel.write_to("output", "total") @@ -327,7 +317,7 @@ async def test_invoke_checkpoint(mocker: MockerFixture) -> None: memory = MemoryCheckpoint() app = Pregel( - chains={"chain_one": chain_one}, + nodes={"one": one}, channels={"total": BinaryOperatorAggregate(int, operator.add)}, saver=memory, ) @@ -363,15 +353,15 @@ async def test_invoke_two_processes_two_in_join_two_out(mocker: MockerFixture) - add_one = mocker.Mock(side_effect=lambda x: x + 1) add_10_each = mocker.Mock(side_effect=lambda x: sorted(y + 10 for y in x)) - chain_one = Channel.subscribe_to("input") | add_one | Channel.write_to("inbox") + one = Channel.subscribe_to("input") | add_one | Channel.write_to("inbox") chain_three = Channel.subscribe_to("input") | add_one | Channel.write_to("inbox") chain_four = ( Channel.subscribe_to("inbox") | add_10_each | Channel.write_to("output") ) app = Pregel( - chains={ - "chain_one": chain_one, + nodes={ + "one": one, "chain_three": chain_three, "chain_four": chain_four, }, @@ -394,17 +384,17 @@ async def test_invoke_join_then_call_other_pubsub(mocker: MockerFixture) -> None add_10_each = mocker.Mock(side_effect=lambda x: [y + 10 for y in x]) inner_app = Pregel( - chains={ + nodes={ "one": Channel.subscribe_to("input") | add_one | Channel.write_to("output") } ) - chain_one = ( + one = ( Channel.subscribe_to("input") | add_10_each | Channel.write_to("inbox_one").map() ) - chain_two = ( + two = ( Channel.subscribe_to("inbox_one") | inner_app.map() | sorted @@ -413,9 +403,9 @@ async def test_invoke_join_then_call_other_pubsub(mocker: MockerFixture) -> None chain_three = Channel.subscribe_to("outbox_one") | sum | Channel.write_to("output") app = Pregel( - chains={ - "chain_one": chain_one, - "chain_two": chain_two, + nodes={ + "one": one, + "two": two, "chain_three": chain_three, }, channels={ @@ -436,14 +426,14 @@ async def test_invoke_join_then_call_other_pubsub(mocker: MockerFixture) -> None async def test_invoke_two_processes_one_in_two_out(mocker: MockerFixture) -> None: add_one = mocker.Mock(side_effect=lambda x: x + 1) - chain_one = ( + one = ( Channel.subscribe_to("input") | add_one | Channel.write_to(output=RunnablePassthrough(), between=RunnablePassthrough()) ) - chain_two = Channel.subscribe_to("between") | add_one | Channel.write_to("output") + two = Channel.subscribe_to("between") | add_one | Channel.write_to("output") - app = Pregel(chains={"chain_one": chain_one, "chain_two": chain_two}) + app = Pregel(nodes={"one": one, "two": two}) # Then invoke pubsub assert [c async for c in app.astream(2)] == [3, 4] @@ -451,10 +441,10 @@ async def test_invoke_two_processes_one_in_two_out(mocker: MockerFixture) -> Non async def test_invoke_two_processes_no_out(mocker: MockerFixture) -> None: add_one = mocker.Mock(side_effect=lambda x: x + 1) - chain_one = Channel.subscribe_to("input") | add_one | Channel.write_to("between") - chain_two = Channel.subscribe_to("between") | add_one + one = Channel.subscribe_to("input") | add_one | Channel.write_to("between") + two = Channel.subscribe_to("between") | add_one - app = Pregel(chains={"chain_one": chain_one, "chain_two": chain_two}) + app = Pregel(nodes={"one": one, "two": two}) # It finishes executing (once no more messages being published) # but returns nothing, as nothing was published to "output" topic @@ -484,13 +474,11 @@ async def test_channel_enter_exit_timing(mocker: MockerFixture) -> None: cleanup_async() add_one = mocker.Mock(side_effect=lambda x: x + 1) - chain_one = Channel.subscribe_to("input") | add_one | Channel.write_to("inbox") - chain_two = ( - Channel.subscribe_to_each("inbox") | add_one | Channel.write_to("output") - ) + one = Channel.subscribe_to("input") | add_one | Channel.write_to("inbox") + two = Channel.subscribe_to_each("inbox") | add_one | Channel.write_to("output") app = Pregel( - chains={"chain_one": chain_one, "chain_two": chain_two}, + nodes={"one": one, "two": two}, channels={ "inbox": Topic(int), "ctx": Context(an_int, an_int_async, typ=int), From d293f5156df574d8ad67f94e52e36873c46f9ba1 Mon Sep 17 00:00:00 2001 From: Nuno Campos Date: Sat, 6 Jan 2024 13:13:32 -0800 Subject: [PATCH 07/19] Add output kwarg --- permchain/pregel/__init__.py | 131 ++++++++++++++++++++++------------- tests/test_pregel.py | 12 ++++ tests/test_pregel_async.py | 11 +++ 3 files changed, 107 insertions(+), 47 deletions(-) diff --git a/permchain/pregel/__init__.py b/permchain/pregel/__init__.py index d7444b5d8..29deb0606 100644 --- a/permchain/pregel/__init__.py +++ b/permchain/pregel/__init__.py @@ -215,9 +215,13 @@ class Pregel(RunnableSerializable[dict[str, Any] | Any, dict[str, Any] | Any]): input: Iterator[dict[str, Any] | Any], run_manager: CallbackManagerForChainRun, config: RunnableConfig, + *, + output: str | Sequence[str] | None = None, ) -> Iterator[tuple[dict[str, Any] | Any, CheckpointView]]: if config["recursion_limit"] < 1: raise ValueError("recursion_limit must be at least 1") + # assign defaults + output = output if output is not None else self.output # copy nodes to ignore mutations during execution processes = {**self.nodes} # get checkpoint from saver, or create an empty one @@ -256,24 +260,31 @@ class Pregel(RunnableSerializable[dict[str, Any] | Any, dict[str, Any] | Any]): # collect all writes to channels, without applying them yet pending_writes = deque[tuple[str, Any]]() + # prepare tasks with config + tasks_w_config = [ + ( + proc, + input, + patch_config( + config, + run_name=name, + callbacks=run_manager.get_child(f"graph:step:{step}"), + configurable={ + # deque.extend is thread-safe + CONFIG_KEY_SEND: pending_writes.extend, + CONFIG_KEY_READ: read, + }, + ), + ) + for proc, input, name in next_tasks + ] + # execute tasks, and wait for one to fail or all to finish. # each task is independent from all other concurrent tasks done, inflight = concurrent.futures.wait( [ - executor.submit( - proc.invoke, - input, - patch_config( - config, - callbacks=run_manager.get_child(f"pregel:step:{step}"), - configurable={ - # deque.extend is thread-safe - CONFIG_KEY_SEND: pending_writes.extend, - CONFIG_KEY_READ: read, - }, - ), - ) - for proc, input, _ in next_tasks + executor.submit(proc.invoke, input, config) + for proc, input, config in tasks_w_config ], return_when=concurrent.futures.FIRST_EXCEPTION, timeout=self.step_timeout, @@ -293,7 +304,7 @@ class Pregel(RunnableSerializable[dict[str, Any] | Any, dict[str, Any] | Any]): values=_updateable_channel_values(channels), step=step + 1, ) - yield map_output(self.output, pending_writes, channels), view + yield map_output(output, pending_writes, channels), view # if view was updated, apply writes to channels _apply_writes_from_view(checkpoint, channels, view) @@ -312,9 +323,13 @@ class Pregel(RunnableSerializable[dict[str, Any] | Any, dict[str, Any] | Any]): input: AsyncIterator[dict[str, Any] | Any], run_manager: AsyncCallbackManagerForChainRun, config: RunnableConfig, + *, + output: str | Sequence[str] | None = None, ) -> AsyncIterator[tuple[dict[str, Any] | Any, CheckpointView]]: if config["recursion_limit"] < 1: raise ValueError("recursion_limit must be at least 1") + # assign defaults + output = output if output is not None else self.output # copy nodes to ignore mutations during execution processes = {**self.nodes} # get checkpoint from saver, or create an empty one @@ -351,27 +366,31 @@ class Pregel(RunnableSerializable[dict[str, Any] | Any, dict[str, Any] | Any]): # collect all writes to channels, without applying them yet pending_writes = deque[tuple[str, Any]]() + # prepare tasks with config + tasks_w_config = [ + ( + proc, + input, + patch_config( + config, + run_name=name, + callbacks=run_manager.get_child(f"graph:step:{step}"), + configurable={ + # deque.extend is thread-safe + CONFIG_KEY_SEND: pending_writes.extend, + CONFIG_KEY_READ: read, + }, + ), + ) + for proc, input, name in next_tasks + ] + # execute tasks, and wait for one to fail or all to finish. # each task is independent from all other concurrent tasks done, inflight = await asyncio.wait( [ - asyncio.create_task( - proc.ainvoke( - input, - patch_config( - config, - callbacks=run_manager.get_child( - f"pregel:step:{step}" - ), - configurable={ - # deque.extend is thread-safe - CONFIG_KEY_SEND: pending_writes.extend, - CONFIG_KEY_READ: read, - }, - ), - ) - ) - for proc, input, _ in next_tasks + asyncio.create_task(proc.ainvoke(input, config)) + for proc, input, config in tasks_w_config ], return_when=asyncio.FIRST_EXCEPTION, timeout=self.step_timeout, @@ -391,7 +410,7 @@ class Pregel(RunnableSerializable[dict[str, Any] | Any, dict[str, Any] | Any]): values=_updateable_channel_values(channels), step=step + 1, ) - yield map_output(self.output, pending_writes, channels), view + yield map_output(output, pending_writes, channels), view # if view was updated, apply writes to channels _apply_writes_from_view(checkpoint, channels, view) @@ -409,10 +428,12 @@ class Pregel(RunnableSerializable[dict[str, Any] | Any, dict[str, Any] | Any]): self, input: dict[str, Any] | Any, config: RunnableConfig | None = None, + *, + output: str | Sequence[str] | None = None, **kwargs: Any, ) -> dict[str, Any] | Any: latest: dict[str, Any] | Any = None - for chunk in self.stream(input, config, **kwargs): + for chunk in self.stream(input, config, output=output, **kwargs): latest = chunk return latest @@ -420,30 +441,36 @@ class Pregel(RunnableSerializable[dict[str, Any] | Any, dict[str, Any] | Any]): self, input: dict[str, Any] | Any, config: RunnableConfig | None = None, + *, + output: str | Sequence[str] | None = None, **kwargs: Any, ) -> Iterator[dict[str, Any] | Any]: - return self.transform(iter([input]), config, **kwargs) + return self.transform(iter([input]), config, output=output, **kwargs) def transform( self, input: Iterator[dict[str, Any] | Any], config: RunnableConfig | None = None, + *, + output: str | Sequence[str] | None = None, **kwargs: Any | None, ) -> Iterator[dict[str, Any] | Any]: - for output, _ in self._transform_stream_with_config( - input, self._transform, config, **kwargs + for out, _ in self._transform_stream_with_config( + input, self._transform, config, output=output, **kwargs ): - if output is not None: - yield output + if out is not None: + yield cast(dict[str, Any] | Any, out) def step( self, input: dict[str, Any] | Any, config: RunnableConfig | None = None, + *, + output: str | Sequence[str] | None = None, **kwargs: Any, ) -> Iterator[tuple[dict[str, Any] | Any, CheckpointView]]: for tup in self._transform_stream_with_config( - iter([input]), self._transform, config, **kwargs + iter([input]), self._transform, config, output=output, **kwargs ): yield cast(tuple[dict[str, Any] | Any, CheckpointView], tup) @@ -451,10 +478,12 @@ class Pregel(RunnableSerializable[dict[str, Any] | Any, dict[str, Any] | Any]): self, input: dict[str, Any] | Any, config: RunnableConfig | None = None, + *, + output: str | Sequence[str] | None = None, **kwargs: Any, ) -> dict[str, Any] | Any: latest: dict[str, Any] | Any = None - async for chunk in self.astream(input, config, **kwargs): + async for chunk in self.astream(input, config, output=output, **kwargs): latest = chunk return latest @@ -462,37 +491,45 @@ class Pregel(RunnableSerializable[dict[str, Any] | Any, dict[str, Any] | Any]): self, input: dict[str, Any] | Any, config: RunnableConfig | None = None, + *, + output: str | Sequence[str] | None = None, **kwargs: Any, ) -> AsyncIterator[dict[str, Any] | Any]: async def input_stream() -> AsyncIterator[dict[str, Any] | Any]: yield input - async for chunk in self.atransform(input_stream(), config, **kwargs): + async for chunk in self.atransform( + input_stream(), config, output=output, **kwargs + ): yield chunk async def atransform( self, input: AsyncIterator[dict[str, Any] | Any], config: RunnableConfig | None = None, + *, + output: str | Sequence[str] | None = None, **kwargs: Any | None, ) -> AsyncIterator[dict[str, Any] | Any]: - async for output, _ in self._atransform_stream_with_config( - input, self._atransform, config, **kwargs + async for out, _ in self._atransform_stream_with_config( + input, self._atransform, config, output=output, **kwargs ): - if output is not None: - yield output + if out is not None: + yield out async def astep( self, input: dict[str, Any] | Any, config: RunnableConfig | None = None, + *, + output: str | Sequence[str] | None = None, **kwargs: Any, ) -> AsyncIterator[tuple[dict[str, Any] | Any, CheckpointView]]: async def input_stream() -> AsyncIterator[dict[str, Any] | Any]: yield input async for tup in self._atransform_stream_with_config( - input_stream(), self._atransform, config, **kwargs + input_stream(), self._atransform, config, output=output, **kwargs ): yield cast(tuple[dict[str, Any] | Any, CheckpointView], tup) diff --git a/tests/test_pregel.py b/tests/test_pregel.py index 1a1187367..8e5979746 100644 --- a/tests/test_pregel.py +++ b/tests/test_pregel.py @@ -42,6 +42,7 @@ def test_invoke_single_process_in_out(mocker: MockerFixture) -> None: assert app.input_schema.schema() == {"title": "PregelInput", "type": "integer"} assert app.output_schema.schema() == {"title": "PregelOutput", "type": "integer"} assert app.invoke(2) == 3 + assert app.invoke(2, output=["output"]) == {"output": 3} assert repr(app), "does not raise recursion error" assert gapp.invoke(2) == 3 @@ -243,6 +244,10 @@ def test_invoke_two_processes_in_dict_out(mocker: MockerFixture) -> None: ) assert [*app.stream({"input": 2, "inbox": 12})] == [13, 4] # [12 + 1, 2 + 1 + 1] + assert [*app.stream({"input": 2, "inbox": 12}, output=["output"])] == [ + {"output": 13}, + {"output": 4}, + ] def test_batch_two_processes_in_out() -> None: @@ -256,6 +261,13 @@ def test_batch_two_processes_in_out() -> None: app = Pregel(nodes={"one": one, "two": two}) assert app.batch([3, 2, 1, 3, 5]) == [5, 4, 3, 5, 7] + assert app.batch([3, 2, 1, 3, 5], output=["output"]) == [ + {"output": 5}, + {"output": 4}, + {"output": 3}, + {"output": 5}, + {"output": 7}, + ] graph = Graph() graph.add_node("add_one", add_one_with_delay) diff --git a/tests/test_pregel_async.py b/tests/test_pregel_async.py index 879df9dfe..1e97c0f13 100644 --- a/tests/test_pregel_async.py +++ b/tests/test_pregel_async.py @@ -36,6 +36,7 @@ async def test_invoke_single_process_in_out(mocker: MockerFixture) -> None: assert app.input_schema.schema() == {"title": "PregelInput", "type": "integer"} assert app.output_schema.schema() == {"title": "PregelOutput", "type": "integer"} assert await app.ainvoke(2) == 3 + assert await app.ainvoke(2, output=["output"]) == {"output": 3} async def test_invoke_single_process_in_out_implicit_channels( @@ -195,6 +196,9 @@ async def test_invoke_two_processes_in_dict_out(mocker: MockerFixture) -> None: # [12 + 1, 2 + 1 + 1] assert [c async for c in pubsub.astream({"input": 2, "inbox": 12})] == [13, 4] + assert [ + c async for c in pubsub.astream({"input": 2, "inbox": 12}, output=["output"]) + ] == [{"output": 13}, {"output": 4}] async def test_batch_two_processes_in_out() -> None: @@ -211,6 +215,13 @@ async def test_batch_two_processes_in_out() -> None: ) assert await app.abatch([3, 2, 1, 3, 5]) == [5, 4, 3, 5, 7] + assert await app.abatch([3, 2, 1, 3, 5], output=["output"]) == [ + {"output": 5}, + {"output": 4}, + {"output": 3}, + {"output": 5}, + {"output": 7}, + ] async def test_invoke_many_processes_in_out(mocker: MockerFixture) -> None: From 4ab9ff05ad3ed576b2af845677ed51fcc7ddc6e3 Mon Sep 17 00:00:00 2001 From: Nuno Campos Date: Sat, 6 Jan 2024 13:15:49 -0800 Subject: [PATCH 08/19] Add graph async tests --- tests/test_pregel_async.py | 62 +++++++++++++++++++++++++++++++++++++- 1 file changed, 61 insertions(+), 1 deletion(-) diff --git a/tests/test_pregel_async.py b/tests/test_pregel_async.py index 1e97c0f13..abcc0e8b6 100644 --- a/tests/test_pregel_async.py +++ b/tests/test_pregel_async.py @@ -7,7 +7,7 @@ import pytest from langchain_core.runnables import RunnablePassthrough from pytest_mock import MockerFixture -from permchain import Channel, Pregel +from permchain import Channel, Graph, Pregel from permchain.channels.base import InvalidUpdateError from permchain.channels.binop import BinaryOperatorAggregate from permchain.channels.context import Context @@ -32,12 +32,19 @@ async def test_invoke_single_process_in_out(mocker: MockerFixture) -> None: input="input", output="output", ) + graph = Graph() + graph.add_node("add_one", add_one) + graph.set_entry_point("add_one") + graph.set_finish_point("add_one") + gapp = graph.compile() assert app.input_schema.schema() == {"title": "PregelInput", "type": "integer"} assert app.output_schema.schema() == {"title": "PregelOutput", "type": "integer"} assert await app.ainvoke(2) == 3 assert await app.ainvoke(2, output=["output"]) == {"output": 3} + assert await gapp.ainvoke(2) == 3 + async def test_invoke_single_process_in_out_implicit_channels( mocker: MockerFixture, @@ -182,6 +189,49 @@ async def test_invoke_two_processes_in_out(mocker: MockerFixture) -> None: # output is different now assert output == 6 + graph = Graph() + graph.add_node("add_one", add_one) + graph.add_node("add_one_more", add_one) + graph.set_entry_point("add_one") + graph.set_finish_point("add_one_more") + graph.add_edge("add_one", "add_one_more") + gapp = graph.compile() + + assert await gapp.ainvoke(2) == 4 + + async for output, view in gapp.astep(2): + if view.step == 1: + assert view.values == { + "add_one": 2, + "add_one_more": 3, + } + assert output is None + elif view.step == 2: + assert view.values == { + "add_one": 2, + "add_one_more": 3, + "__end__": 4, + } + assert output == 4 + + async for output, view in gapp.astep(2): + if view.step == 1: + assert view.values == { + "add_one": 2, + "add_one_more": 3, + } + assert output is None + # modify inbox value + view.values["add_one_more"] = 5 + elif view.step == 2: + assert view.values == { + "add_one": 2, + "add_one_more": 5, + "__end__": 6, + } + # output is different now + assert output == 6 + async def test_invoke_two_processes_in_dict_out(mocker: MockerFixture) -> None: add_one = mocker.Mock(side_effect=lambda x: x + 1) @@ -223,6 +273,16 @@ async def test_batch_two_processes_in_out() -> None: {"output": 7}, ] + graph = Graph() + graph.add_node("add_one", add_one_with_delay) + graph.add_node("add_one_more", add_one_with_delay) + graph.set_entry_point("add_one") + graph.set_finish_point("add_one_more") + graph.add_edge("add_one", "add_one_more") + gapp = graph.compile() + + assert await gapp.abatch([3, 2, 1, 3, 5]) == [5, 4, 3, 5, 7] + async def test_invoke_many_processes_in_out(mocker: MockerFixture) -> None: test_size = 100 From 73e4f8953b3d465ff999d20cdb2886d156530f17 Mon Sep 17 00:00:00 2001 From: Nuno Campos Date: Sat, 6 Jan 2024 13:51:00 -0800 Subject: [PATCH 09/19] Add tests for conditional edges --- permchain/langgraph/__init__.py | 3 + pyproject.toml | 2 +- tests/test_pregel.py | 177 +++++++++++++++++++++++++++++++- tests/test_pregel_async.py | 175 +++++++++++++++++++++++++++++++ 4 files changed, 355 insertions(+), 2 deletions(-) diff --git a/permchain/langgraph/__init__.py b/permchain/langgraph/__init__.py index f968b98b9..6f97bf491 100644 --- a/permchain/langgraph/__init__.py +++ b/permchain/langgraph/__init__.py @@ -1,3 +1,4 @@ +from asyncio import iscoroutinefunction from collections import defaultdict from typing import Any, Callable, Dict, NamedTuple @@ -57,6 +58,8 @@ class Graph: ): if start_key not in self.nodes: raise ValueError(f"Need to add_node `{start_key}` first") + if iscoroutinefunction(condition): + raise ValueError("Condition cannot be a coroutine function") self.branches[start_key].append(Branch(condition, conditional_edge_mapping)) diff --git a/pyproject.toml b/pyproject.toml index ce2741652..c94b6d9d9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -67,6 +67,6 @@ asyncio_mode = "auto" # # https://github.com/tophat/syrupy # --snapshot-warn-unused Prints a warning on unused snapshots rather than fail the test suite. -addopts = "-x --full-trace --strict-markers --strict-config --durations=5 --snapshot-warn-unused" +addopts = "-x -vv --full-trace --strict-markers --strict-config --durations=5 --snapshot-warn-unused" # Registering custom markers. # https://docs.pytest.org/en/7.1.x/example/markers.html#registering-markers diff --git a/tests/test_pregel.py b/tests/test_pregel.py index 8e5979746..b8253945f 100644 --- a/tests/test_pregel.py +++ b/tests/test_pregel.py @@ -2,7 +2,7 @@ import operator import time from concurrent.futures import ThreadPoolExecutor from contextlib import contextmanager -from typing import Generator +from typing import Any, Generator import pytest from langchain_core.runnables import RunnablePassthrough @@ -554,3 +554,178 @@ def test_channel_enter_exit_timing(mocker: MockerFixture) -> None: else: assert False, "Expected only two chunks" assert cleanup.call_count == 1, "Expected cleanup to be called once" + + +def test_conditional_graph() -> None: + from copy import deepcopy + + from langchain.llms.fake import FakeStreamingListLLM + from langchain_community.tools import tool + from langchain_core.agents import AgentAction, AgentFinish + from langchain_core.prompts import PromptTemplate + from langchain_core.runnables import RunnablePassthrough + + from permchain.langgraph import END + + # Assemble the tools + @tool() + def search_api(query: str) -> str: + """Searches the API for the query.""" + return f"result for {query}" + + tools = [search_api] + + # Construct the agent + prompt = PromptTemplate.from_template("Hello!") + + llm = FakeStreamingListLLM( + responses=[ + "tool:search_api:query", + "tool:search_api:another", + "finish:answer", + ] + ) + + def agent_parser(input: str) -> AgentFinish | AgentAction: + if input.startswith("finish"): + _, answer = input.split(":") + return AgentFinish(return_values={"answer": answer}, log=input) + else: + _, tool_name, tool_input = input.split(":") + return AgentAction(tool=tool_name, tool_input=tool_input, log=input) + + agent = RunnablePassthrough.assign(agent_outcome=prompt | llm | agent_parser) + + # Define tool execution logic + def execute_tools(data): + agent_action: AgentAction | AgentFinish = data.pop("agent_outcome") + observation = {t.name: t for t in tools}[agent_action.tool].invoke( + agent_action.tool_input + ) + if data.get("intermediate_steps") is None: + data["intermediate_steps"] = [] + data["intermediate_steps"].append((agent_action, observation)) + return data + + # Define decision-making logic + def should_continue(data): + # Logic to decide whether to continue in the loop or exit + if isinstance(data["agent_outcome"], AgentFinish): + return "exit" + else: + return "continue" + + # Define a new graph + workflow = Graph() + + workflow.add_node("agent", agent) + workflow.add_node("tools", execute_tools) + + workflow.set_entry_point("agent") + + workflow.add_conditional_edges( + "agent", should_continue, {"continue": "tools", "exit": END} + ) + + workflow.add_edge("tools", "agent") + + app = workflow.compile() + + assert app.invoke({"input": "what is weather in sf"}) == { + "input": "what is weather in sf", + "intermediate_steps": [ + ( + AgentAction( + tool="search_api", + tool_input="query", + log="tool:search_api:query", + ), + "result for query", + ), + ( + AgentAction( + tool="search_api", + tool_input="another", + log="tool:search_api:another", + ), + "result for another", + ), + ], + "agent_outcome": AgentFinish( + return_values={"answer": "answer"}, log="finish:answer" + ), + } + + assert [ + deepcopy(c) + for c in app.stream( + {"input": "what is weather in sf"}, output=["agent", "tools"] + ) + ] == [ + { + "tools": { + "input": "what is weather in sf", + "agent_outcome": AgentAction( + tool="search_api", tool_input="query", log="tool:search_api:query" + ), + } + }, + { + "agent": { + "input": "what is weather in sf", + "intermediate_steps": [ + ( + AgentAction( + tool="search_api", + tool_input="query", + log="tool:search_api:query", + ), + "result for query", + ) + ], + } + }, + { + "tools": { + "input": "what is weather in sf", + "intermediate_steps": [ + ( + AgentAction( + tool="search_api", + tool_input="query", + log="tool:search_api:query", + ), + "result for query", + ) + ], + "agent_outcome": AgentAction( + tool="search_api", + tool_input="another", + log="tool:search_api:another", + ), + } + }, + { + "agent": { + "input": "what is weather in sf", + "intermediate_steps": [ + ( + AgentAction( + tool="search_api", + tool_input="query", + log="tool:search_api:query", + ), + "result for query", + ), + ( + AgentAction( + tool="search_api", + tool_input="another", + log="tool:search_api:another", + ), + "result for another", + ), + ], + } + }, + ] diff --git a/tests/test_pregel_async.py b/tests/test_pregel_async.py index abcc0e8b6..760124d5f 100644 --- a/tests/test_pregel_async.py +++ b/tests/test_pregel_async.py @@ -582,3 +582,178 @@ async def test_channel_enter_exit_timing(mocker: MockerFixture) -> None: assert cleanup_sync.call_count == 0 assert setup_async.call_count == 1, "Expected setup to be called once" assert cleanup_async.call_count == 1, "Expected cleanup to be called once" + + +async def test_conditional_graph() -> None: + from copy import deepcopy + + from langchain.llms.fake import FakeStreamingListLLM + from langchain_community.tools import tool + from langchain_core.agents import AgentAction, AgentFinish + from langchain_core.prompts import PromptTemplate + from langchain_core.runnables import RunnablePassthrough + + from permchain.langgraph import END + + # Assemble the tools + @tool() + def search_api(query: str) -> str: + """Searches the API for the query.""" + return f"result for {query}" + + tools = [search_api] + + # Construct the agent + prompt = PromptTemplate.from_template("Hello!") + + llm = FakeStreamingListLLM( + responses=[ + "tool:search_api:query", + "tool:search_api:another", + "finish:answer", + ] + ) + + async def agent_parser(input: str) -> AgentFinish | AgentAction: + if input.startswith("finish"): + _, answer = input.split(":") + return AgentFinish(return_values={"answer": answer}, log=input) + else: + _, tool_name, tool_input = input.split(":") + return AgentAction(tool=tool_name, tool_input=tool_input, log=input) + + agent = RunnablePassthrough.assign(agent_outcome=prompt | llm | agent_parser) + + # Define tool execution logic + async def execute_tools(data): + agent_action: AgentAction | AgentFinish = data.pop("agent_outcome") + observation = await {t.name: t for t in tools}[agent_action.tool].ainvoke( + agent_action.tool_input + ) + if data.get("intermediate_steps") is None: + data["intermediate_steps"] = [] + data["intermediate_steps"].append((agent_action, observation)) + return data + + # Define decision-making logic + def should_continue(data): + # Logic to decide whether to continue in the loop or exit + if isinstance(data["agent_outcome"], AgentFinish): + return "exit" + else: + return "continue" + + # Define a new graph + workflow = Graph() + + workflow.add_node("agent", agent) + workflow.add_node("tools", execute_tools) + + workflow.set_entry_point("agent") + + workflow.add_conditional_edges( + "agent", should_continue, {"continue": "tools", "exit": END} + ) + + workflow.add_edge("tools", "agent") + + app = workflow.compile() + + assert await app.ainvoke({"input": "what is weather in sf"}) == { + "input": "what is weather in sf", + "intermediate_steps": [ + ( + AgentAction( + tool="search_api", + tool_input="query", + log="tool:search_api:query", + ), + "result for query", + ), + ( + AgentAction( + tool="search_api", + tool_input="another", + log="tool:search_api:another", + ), + "result for another", + ), + ], + "agent_outcome": AgentFinish( + return_values={"answer": "answer"}, log="finish:answer" + ), + } + + assert [ + deepcopy(c) + async for c in app.astream( + {"input": "what is weather in sf"}, output=["agent", "tools"] + ) + ] == [ + { + "tools": { + "input": "what is weather in sf", + "agent_outcome": AgentAction( + tool="search_api", tool_input="query", log="tool:search_api:query" + ), + } + }, + { + "agent": { + "input": "what is weather in sf", + "intermediate_steps": [ + ( + AgentAction( + tool="search_api", + tool_input="query", + log="tool:search_api:query", + ), + "result for query", + ) + ], + } + }, + { + "tools": { + "input": "what is weather in sf", + "intermediate_steps": [ + ( + AgentAction( + tool="search_api", + tool_input="query", + log="tool:search_api:query", + ), + "result for query", + ) + ], + "agent_outcome": AgentAction( + tool="search_api", + tool_input="another", + log="tool:search_api:another", + ), + } + }, + { + "agent": { + "input": "what is weather in sf", + "intermediate_steps": [ + ( + AgentAction( + tool="search_api", + tool_input="query", + log="tool:search_api:query", + ), + "result for query", + ), + ( + AgentAction( + tool="search_api", + tool_input="another", + log="tool:search_api:another", + ), + "result for another", + ), + ], + } + }, + ] From 49aad8f3200913f40132e38620d20760639aa1d4 Mon Sep 17 00:00:00 2001 From: Nuno Campos Date: Sat, 6 Jan 2024 14:21:48 -0800 Subject: [PATCH 10/19] Stream output of each process when running with astream_log() --- permchain/pregel/__init__.py | 21 +++++++++++++++++++++ tests/test_pregel.py | 2 +- tests/test_pregel_async.py | 6 ++++++ 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/permchain/pregel/__init__.py b/permchain/pregel/__init__.py index 29deb0606..bfd61bb56 100644 --- a/permchain/pregel/__init__.py +++ b/permchain/pregel/__init__.py @@ -39,6 +39,7 @@ from langchain_core.runnables.utils import ( ConfigurableFieldSpec, get_unique_config_specs, ) +from langchain_core.tracers.log_stream import LogStreamCallbackHandler from permchain.channels.base import ( AsyncChannelsManager, @@ -328,6 +329,15 @@ class Pregel(RunnableSerializable[dict[str, Any] | Any, dict[str, Any] | Any]): ) -> AsyncIterator[tuple[dict[str, Any] | Any, CheckpointView]]: if config["recursion_limit"] < 1: raise ValueError("recursion_limit must be at least 1") + # if running from astream_log() run each proc with streaming + do_stream = next( + ( + h + for h in run_manager.handlers + if isinstance(h, LogStreamCallbackHandler) + ), + None, + ) # assign defaults output = output if output is not None else self.output # copy nodes to ignore mutations during execution @@ -389,6 +399,11 @@ class Pregel(RunnableSerializable[dict[str, Any] | Any, dict[str, Any] | Any]): # each task is independent from all other concurrent tasks done, inflight = await asyncio.wait( [ + asyncio.create_task(_aconsume(proc.astream(input, config))) + for proc, input, config in tasks_w_config + ] + if do_stream + else [ asyncio.create_task(proc.ainvoke(input, config)) for proc, input, config in tasks_w_config ], @@ -686,3 +701,9 @@ def _updateable_channel_values(channels: Mapping[str, BaseChannel]) -> dict[str, except EmptyChannelError: pass return values + + +async def _aconsume(iterator: AsyncIterator[Any]) -> None: + """Consume an async iterator.""" + async for _ in iterator: + pass diff --git a/tests/test_pregel.py b/tests/test_pregel.py index b8253945f..642098321 100644 --- a/tests/test_pregel.py +++ b/tests/test_pregel.py @@ -2,7 +2,7 @@ import operator import time from concurrent.futures import ThreadPoolExecutor from contextlib import contextmanager -from typing import Any, Generator +from typing import Generator import pytest from langchain_core.runnables import RunnablePassthrough diff --git a/tests/test_pregel_async.py b/tests/test_pregel_async.py index 760124d5f..c205e0dac 100644 --- a/tests/test_pregel_async.py +++ b/tests/test_pregel_async.py @@ -757,3 +757,9 @@ async def test_conditional_graph() -> None: } }, ] + + patches = [c async for c in app.astream_log({"input": "what is weather in sf"})] + patch_paths = {op["path"] for log in patches for op in log.ops} + + # Check that agent (one of the nodes) has its output streamed to the logs + assert "/logs/agent/streamed_output/-" in patch_paths From e0a6a6b9c00d3a6ab2274f6f4b49fd8794b8f7e2 Mon Sep 17 00:00:00 2001 From: Nuno Campos Date: Sat, 6 Jan 2024 14:22:00 -0800 Subject: [PATCH 11/19] Use better pytest watcher --- Makefile | 2 +- poetry.lock | 31 ++++++++++--------------------- pyproject.toml | 4 ++-- 3 files changed, 13 insertions(+), 24 deletions(-) diff --git a/Makefile b/Makefile index 7ace36f8a..f228a3fed 100644 --- a/Makefile +++ b/Makefile @@ -18,7 +18,7 @@ test: poetry run pytest test_watch: - poetry run ptw + poetry run ptw --snapshot-update --now . -- -vv -x tests ###################### # LINTING AND FORMATTING diff --git a/poetry.lock b/poetry.lock index 5a769b810..2aa9f8a63 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand. [[package]] name = "aiohttp" @@ -692,16 +692,6 @@ files = [ {file = "defusedxml-0.7.1.tar.gz", hash = "sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69"}, ] -[[package]] -name = "docopt" -version = "0.6.2" -description = "Pythonic argument parser, that will make you smile" -optional = false -python-versions = "*" -files = [ - {file = "docopt-0.6.2.tar.gz", hash = "sha256:49b3a825280bd66b3aa83585ef59c4a8c82f2c8a522dbe754a8bc8d08c85c491"}, -] - [[package]] name = "exceptiongroup" version = "1.2.0" @@ -2532,20 +2522,19 @@ pytest = ">=5.0" dev = ["pre-commit", "pytest-asyncio", "tox"] [[package]] -name = "pytest-watch" -version = "4.2.0" -description = "Local continuous test runner with pytest and watchdog." +name = "pytest-watcher" +version = "0.3.4" +description = "Automatically rerun your tests on file modifications" optional = false -python-versions = "*" +python-versions = ">=3.7.0,<4.0.0" files = [ - {file = "pytest-watch-4.2.0.tar.gz", hash = "sha256:06136f03d5b361718b8d0d234042f7b2f203910d8568f63df2f866b547b3d4b9"}, + {file = "pytest_watcher-0.3.4-py3-none-any.whl", hash = "sha256:edd2bd9c8a1fb14d48c9f4947234065eb9b4c1acedc0bf213b1f12501dfcffd3"}, + {file = "pytest_watcher-0.3.4.tar.gz", hash = "sha256:d39491ba15b589221bb9a78ef4bed3d5d1503aed08209b1a138aeb95b9117a18"}, ] [package.dependencies] -colorama = ">=0.3.3" -docopt = ">=0.4.0" -pytest = ">=2.6.4" -watchdog = ">=0.6.0" +tomli = {version = ">=2.0.1,<3.0.0", markers = "python_version < \"3.11\""} +watchdog = ">=2.0.0" [[package]] name = "python-dateutil" @@ -3629,4 +3618,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p [metadata] lock-version = "2.0" python-versions = ">=3.8.1,<4.0" -content-hash = "4f1c52f5b61024577a687d37a2d42023f6519f31f36f47449779db8f4f3ca355" +content-hash = "d830534e382bb3d1d6d51a55ab7ac6762fbabd0be9c4030578ec920aedd6698b" diff --git a/pyproject.toml b/pyproject.toml index c94b6d9d9..3357125af 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -22,8 +22,8 @@ pytest-dotenv = "^0.5.2" pytest-asyncio = "^0.20.3" pytest-mock = "^3.10.0" syrupy = "^4.0.2" -pytest-watch = "^4.2.0" httpx = "^0.26.0" +pytest-watcher = "^0.3.4" [tool.poetry.group.lint.dependencies] ruff = "^0.1.4" @@ -67,6 +67,6 @@ asyncio_mode = "auto" # # https://github.com/tophat/syrupy # --snapshot-warn-unused Prints a warning on unused snapshots rather than fail the test suite. -addopts = "-x -vv --full-trace --strict-markers --strict-config --durations=5 --snapshot-warn-unused" +addopts = "--full-trace --strict-markers --strict-config --durations=5 --snapshot-warn-unused" # Registering custom markers. # https://docs.pytest.org/en/7.1.x/example/markers.html#registering-markers From 5f8f17cac36b3634e325198f5ba4990c8b375642 Mon Sep 17 00:00:00 2001 From: Nuno Campos Date: Sat, 6 Jan 2024 14:42:28 -0800 Subject: [PATCH 12/19] Improve run names --- examples/langgraph.ipynb | 20 ++------------------ permchain/langgraph/__init__.py | 19 +++++++++++-------- permchain/pregel/read.py | 1 + permchain/pregel/write.py | 1 + 4 files changed, 15 insertions(+), 26 deletions(-) diff --git a/examples/langgraph.ipynb b/examples/langgraph.ipynb index b502b1e33..b179a5fda 100644 --- a/examples/langgraph.ipynb +++ b/examples/langgraph.ipynb @@ -13,30 +13,14 @@ "execution_count": 1, "id": "d642e6af-217a-4414-a78c-509b44155eca", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "input_variables=['agent_scratchpad', 'input'] input_types={'chat_history': typing.List[typing.Union[langchain_core.messages.ai.AIMessage, langchain_core.messages.human.HumanMessage, langchain_core.messages.chat.ChatMessage, langchain_core.messages.system.SystemMessage, langchain_core.messages.function.FunctionMessage, langchain_core.messages.tool.ToolMessage]], 'agent_scratchpad': typing.List[typing.Union[langchain_core.messages.ai.AIMessage, langchain_core.messages.human.HumanMessage, langchain_core.messages.chat.ChatMessage, langchain_core.messages.system.SystemMessage, langchain_core.messages.function.FunctionMessage, langchain_core.messages.tool.ToolMessage]]} messages=[SystemMessagePromptTemplate(prompt=PromptTemplate(input_variables=[], template='You are a helpful assistant')), MessagesPlaceholder(variable_name='chat_history', optional=True), HumanMessagePromptTemplate(prompt=PromptTemplate(input_variables=['input'], template='{input}')), MessagesPlaceholder(variable_name='agent_scratchpad')]\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/Users/nuno/dev/langchain/libs/core/langchain_core/_api/deprecation.py:191: LangChainDeprecationWarning: The class `ChatOpenAI` was deprecated in LangChain 0.1.0 and will be removed in 0.2.0. Use langchain_openai.ChatOpenAI instead.\n", - " warn_deprecated(\n" - ] - } - ], + "outputs": [], "source": [ "from langchain.chat_models import ChatOpenAI\n", "from langchain import hub\n", "from langchain.agents import create_openai_functions_agent\n", "from langchain_community.chat_models import ChatOpenAI\n", "from langchain_community.tools.tavily_search import TavilySearchResults\n", - "from langchain_core.runnables import RunnablePassthrough, RunnableLambda\n", + "from langchain_core.runnables import RunnablePassthrough\n", "from permchain.langgraph import Graph, END\n", "\n", "tools = [TavilySearchResults(max_results=1)]\n", diff --git a/permchain/langgraph/__init__.py b/permchain/langgraph/__init__.py index 6f97bf491..e082ee8ca 100644 --- a/permchain/langgraph/__init__.py +++ b/permchain/langgraph/__init__.py @@ -3,7 +3,11 @@ from collections import defaultdict from typing import Any, Callable, Dict, NamedTuple from langchain_core.runnables import Runnable -from langchain_core.runnables.base import RunnableLike, coerce_to_runnable +from langchain_core.runnables.base import ( + RunnableLambda, + RunnableLike, + coerce_to_runnable, +) from permchain.pregel import Channel, Pregel @@ -111,17 +115,16 @@ class Graph: outgoing_edges[self.finish_point].append(END) nodes = { - key: ( - Channel.subscribe_to(key) - | node - | Channel.write_to(*outgoing_edges[key]) - ) - for key, node in self.nodes.items() + key: Channel.subscribe_to(key) | node for key, node in self.nodes.items() } + for key, edges in outgoing_edges.items(): + if edges: + nodes[key] |= Channel.write_to(*edges) + for key, branches in self.branches.items(): for branch in branches: - nodes[key] |= branch.runnable + nodes[key] |= RunnableLambda(branch.runnable, name=f"{key}_condition") return Pregel( nodes=nodes, diff --git a/permchain/pregel/read.py b/permchain/pregel/read.py index 1c9b1dc13..f5184f821 100644 --- a/permchain/pregel/read.py +++ b/permchain/pregel/read.py @@ -40,6 +40,7 @@ class ChannelRead(RunnableLambda): def __init__(self, channel: str) -> None: super().__init__(func=self._read, afunc=self._aread) self.channel = channel + self.name = f"ChannelRead<{channel}>" def _read(self, _: Any, config: RunnableConfig) -> Any: try: diff --git a/permchain/pregel/write.py b/permchain/pregel/write.py index 3c21d39c8..7135e5a76 100644 --- a/permchain/pregel/write.py +++ b/permchain/pregel/write.py @@ -30,6 +30,7 @@ class ChannelWrite(RunnablePassthrough): channels: Sequence[tuple[str, Runnable | None]], ): super().__init__(func=self._write, afunc=self._awrite, channels=channels) + self.name = f"ChannelWrite<{','.join(chan for chan, _ in self.channels)}>" @property def config_specs(self) -> list[ConfigurableFieldSpec]: From 19493799263e9e45e79283ed982a242c934325ae Mon Sep 17 00:00:00 2001 From: Nuno Campos Date: Sat, 6 Jan 2024 14:44:25 -0800 Subject: [PATCH 13/19] Add outputs to notebook --- examples/langgraph.ipynb | 38 ++++++++++++++++++++++++++++++++------ 1 file changed, 32 insertions(+), 6 deletions(-) diff --git a/examples/langgraph.ipynb b/examples/langgraph.ipynb index b179a5fda..8b3dca25a 100644 --- a/examples/langgraph.ipynb +++ b/examples/langgraph.ipynb @@ -81,10 +81,25 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 2, "id": "c46bd262-9605-4449-9391-f6b6e0fe440e", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "{'input': 'what is the weather in sf',\n", + " 'intermediate_steps': [(AgentActionMessageLog(tool='tavily_search_results_json', tool_input={'query': 'weather in San Francisco'}, log=\"\\nInvoking: `tavily_search_results_json` with `{'query': 'weather in San Francisco'}`\\n\\n\\n\", message_log=[AIMessage(content='', additional_kwargs={'function_call': {'name': 'tavily_search_results_json', 'arguments': '{\"query\":\"weather in San Francisco\"}'}})]),\n", + " [{'url': 'https://www.weather25.com/north-america/usa/california/san-francisco',\n", + " 'content': 'will give you an idea of weather trends in San Francisco. For example, the weather in San Francisco in January 2024. San Francisco 14 day weather The weather today in San Francisco San Francisco weather report The weather in San Francisco, United States San Francisco weather by months San Francisco weather the weather in San Francisco including humidity, wind, chance of rain and more on the San Francisco current weather01 January 02 February 03 March 04 April 05 May 06 June 07 July 08 August 09 September 10 October 11 November 12 December. ... For example, the weather in San Francisco in January 2024. These trends can be helpful when planning trips to San Francisco or preparing for the weather in advance. There are many factors to consider when looking at the ...'}])],\n", + " 'agent_outcome': AgentFinish(return_values={'output': 'For the current weather in San Francisco, you can visit the following website: [San Francisco Weather](https://www.weather25.com/north-america/usa/california/san-francisco). This will provide you with the latest weather updates including humidity, wind, chance of rain, and more.'}, log='For the current weather in San Francisco, you can visit the following website: [San Francisco Weather](https://www.weather25.com/north-america/usa/california/san-francisco). This will provide you with the latest weather updates including humidity, wind, chance of rain, and more.')}" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "chain.invoke({\"input\": \"what is the weather in sf\", \"intermediate_steps\": []})" ] @@ -99,7 +114,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 3, "id": "f6f96e81-4a20-4599-a625-8d18df6fa76d", "metadata": {}, "outputs": [], @@ -233,7 +248,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 4, "id": "7708fa95-547b-4bea-b126-3656de7d5873", "metadata": {}, "outputs": [], @@ -299,10 +314,21 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 5, "id": "d6cdd1cd-e480-4dd7-99b4-9018eb243b4d", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "AgentFinish(return_values={'output': \"The current weather in San Francisco can be accessed through various weather reporting services, which provide real-time temperature, humidity, wind, and chances of precipitation [1]. Historically, San Francisco experiences a mild, Mediterranean climate with average temperatures ranging from the low 50s to the mid-60s Fahrenheit. The city's unique topography creates microclimates, leading to significant weather variations across different neighborhoods. San Francisco's summers are notably cooler compared to other Californian cities, largely due to the cold California Current and persistent fog, especially in June and July. Winters are mild and the wettest months span from November to March, with an annual rainfall average of approximately 23 inches. Wind is a prominent feature, with spring being particularly windy. For historical weather extremes and average wind speeds, additional specific data can be sought from climatological records.\\n\\nReferences:\\n[1] https://www.weather25.com/north-america/usa/california/san-francisco\", 'initial_answer': \"The weather in San Francisco (SF) is characterized by a mild, Mediterranean-like climate with wet winters and dry summers. The city's unique topography and coastal location result in microclimates, where weather conditions can vary significantly from one neighborhood to another. Average temperatures typically range from the low 50s to the mid-60s Fahrenheit throughout the year. Summers in San Francisco are often cooler than in other parts of California due to the cold California Current offshore and the presence of fog, particularly in June and July. The fog usually burns off by the afternoon, leading to clearer skies and slightly warmer temperatures. Winters are mild and moist, with the majority of the city's rainfall occurring between November and March. Rainfall averages around 23 inches annually. Wind is also a notable feature of San Francisco's weather, with spring being the windiest season. Despite the general patterns, it's always advisable to dress in layers due to the potential for rapid weather changes.\"}, log='Reached max steps.')" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "workflow = Graph()\n", "\n", From d399074d0576a3d95d40d5dddbf68be75513cac8 Mon Sep 17 00:00:00 2001 From: Nuno Campos Date: Sat, 6 Jan 2024 14:52:29 -0800 Subject: [PATCH 14/19] Remove bogus example --- examples/Untitled.ipynb | 139 ---------------------------------------- 1 file changed, 139 deletions(-) delete mode 100644 examples/Untitled.ipynb diff --git a/examples/Untitled.ipynb b/examples/Untitled.ipynb deleted file mode 100644 index 36f1f3a76..000000000 --- a/examples/Untitled.ipynb +++ /dev/null @@ -1,139 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "id": "2589ed8b-a781-45cc-aeb6-0eebb6469100", - "metadata": {}, - "outputs": [], - "source": [ - "from langchain.hub import pull" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "de600f76-dd51-415f-afae-f8574cb6f99e", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - " \n" - ] - } - ], - "source": [ - "pull('homanp/superagent')" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "b4831d38-7bb1-49a2-9efa-802adc24110f", - "metadata": {}, - "outputs": [], - "source": [ - "from langchain.load import loads" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "id": "2ef796f9-7b34-462e-acb6-25cd116b9045", - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/Users/nuno/dev/langchain/libs/core/langchain_core/_api/beta_decorator.py:162: LangChainBetaWarning: The function `loads` is in beta. It is actively being worked on, so the API may change.\n", - " warn_beta(\n" - ] - }, - { - "data": { - "text/plain": [ - "{}" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "loads('{}')" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "id": "4b6d8788-0b6f-4bd6-b6cf-e2e4e80f4707", - "metadata": {}, - "outputs": [], - "source": [ - "from langchain_core.beta.runnables.context import ContextGet" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "id": "6975707d-58eb-4642-9618-76e37cdeb5e1", - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/Users/nuno/dev/langchain/libs/core/langchain_core/_api/beta_decorator.py:162: LangChainBetaWarning: The class `ContextGet` is in beta. It is actively being worked on, so the API may change.\n", - " warn_beta(\n" - ] - }, - { - "data": { - "text/plain": [ - "ContextGet(key='hello')" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "ContextGet(key='hello')" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "1977eda2-4c4a-4bb0-886a-fe274599dc50", - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.11.5" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} From cc2af50ce9794d66aeff1473fe87b579c255fe0c Mon Sep 17 00:00:00 2001 From: Nuno Campos Date: Sat, 6 Jan 2024 14:53:22 -0800 Subject: [PATCH 15/19] Lint --- permchain/langgraph/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/permchain/langgraph/__init__.py b/permchain/langgraph/__init__.py index e082ee8ca..02573bfc7 100644 --- a/permchain/langgraph/__init__.py +++ b/permchain/langgraph/__init__.py @@ -26,7 +26,6 @@ class Branch(NamedTuple): return Channel.write_to(self.ends[result]) -START = "__start__" END = "__end__" @@ -39,6 +38,8 @@ class Graph: def add_node(self, key: str, action: RunnableLike) -> None: if key in self.nodes: raise ValueError(f"Node `{key}` already present.") + if key == END: + raise ValueError(f"Node `{key}` is reserved.") self.nodes[key] = coerce_to_runnable(action) From 0da6d74320157a1b020f79bfad3aaef116190831 Mon Sep 17 00:00:00 2001 From: Nuno Campos Date: Sat, 6 Jan 2024 14:55:29 -0800 Subject: [PATCH 16/19] Remove file --- permchain/pregel/model.py | 50 --------------------------------------- 1 file changed, 50 deletions(-) delete mode 100644 permchain/pregel/model.py diff --git a/permchain/pregel/model.py b/permchain/pregel/model.py deleted file mode 100644 index 8607ed374..000000000 --- a/permchain/pregel/model.py +++ /dev/null @@ -1,50 +0,0 @@ -from __future__ import annotations - -from dataclasses import dataclass, field -from typing import Any, ClassVar, Dict -from langchain_core.pydantic_v1 import dataclasses - -from permchain.checkpoint.base import BaseCheckpointAdapter -from permchain.pregel import Pregel - -dataclasses.DataclassClassOrWrapper - -from langchain_core.messages import BaseMessage -from langchain_core.runnables import RunnableLambda - -from permchain.pregel.read import ChannelInvoke - - -def on_change(field_name: str): - def decorator(func): - return ChannelInvoke(bound=RunnableLambda(func), triggers=[field_name]) - - return decorator - - -class DataclassProtocol: - __dataclass_fields__: ClassVar[Dict[str, Any]] - - -def thread(data: type[DataclassProtocol], thread_id: str, saver: BaseCheckpointAdapter): - return Pregel( - chains={ - v.__name__: v - for v in data.__dict__.values() - if isinstance(v, ChannelInvoke) - } - ) - - -@dataclass -class Agent: - messages: list[BaseMessage] = field(default_factory=list) - actions: list[BaseMessage] = field(default_factory=list) - - @on_change("messages") - def plan(self): - ... - - @on_change("actions") - def execute(self): - ... From 641190d84b0641e52054770563212dac818938be Mon Sep 17 00:00:00 2001 From: Nuno Campos Date: Sat, 6 Jan 2024 14:56:19 -0800 Subject: [PATCH 17/19] Remove file --- tests/test_graph.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 tests/test_graph.py diff --git a/tests/test_graph.py b/tests/test_graph.py deleted file mode 100644 index e69de29bb..000000000 From 54bfdd8e427e5c96a5068e22e0e4391792f4c394 Mon Sep 17 00:00:00 2001 From: Nuno Campos Date: Sun, 7 Jan 2024 09:50:39 -0800 Subject: [PATCH 18/19] Remove file --- examples/.gitignore | 1 + examples/.langchain.db | Bin 53248 -> 0 bytes 2 files changed, 1 insertion(+) create mode 100644 examples/.gitignore delete mode 100644 examples/.langchain.db diff --git a/examples/.gitignore b/examples/.gitignore new file mode 100644 index 000000000..98e6ef67f --- /dev/null +++ b/examples/.gitignore @@ -0,0 +1 @@ +*.db diff --git a/examples/.langchain.db b/examples/.langchain.db deleted file mode 100644 index 791e9b4ba8f8727604c9f43d1454fe65ade828f6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 53248 zcmeHQ&2t+^b|<}-DJzz}dr0Zpg$uta?qMsJTyoDL=N$H$WB!ZWQk6@7ucrqXd`O~YRcyEzgk%KI{AU$u^Q?zWED z;r$bK`0&dw>+H(=Q^3p1be2f;chgrwYya?M_s;Io^qJ}nnJ`1GjHsS_aI}BWI(p2$ z*nP~d%Xs6;#?HI%U3;{(y5bmWzD^Lhc6e^J`@T%xwicIq>DxQ2Yu7e5R)4=gg$Lvo z66)@se0ygRmdQ1CykI?e8Hw1Hjo-ZU-nIK1FNI@5 zZl{1^^8FW3GnYx#P*A`6(f`un)#3*ohR;t5fj|9v_3|G-`@Zn3R8 ztJ(2T;II~9YuPN1tj=mUEn}Q~QcJk%M*}Vuoik9+DW{`U7{mL*(DB_ob{C;l|HlZqeggO?F3~36L5K%Vh$BFm#35w%Ts8BhgDlWI<@mqD)$e z5oty&(XF(}j)x+WJsI&N8P^>#W}x#V#v}}%20Ix@b;@{G=XSE7R2oCn_FyJwhI`pV zCI{%fB-gniQma(F@UenF1Zh?vRS?H=XkaDIE#W0os2m_MKcIuBa*`$$=RC5>m~FEm z&n#FEC2{iXYpajF9MH)Hv?87gmJiuT+QEyVYOC9~Z<9>z6}i4 za#Dj$*(cd^H%bMu;)$o|X2b(qGPvt z3*jgydub9YXRod$_?nsNXRG2#}?B`UFsuXAmM z0d1hJ^_UFj-TlKmOeB!kVIsH@O;T47GJvKPPdZaY_5Atsr?00Ip&a3>>KN0|=z1s= zmvpp)3-|G@wLh;Etw^yOxy7QO7&n`nxI5+N9ji};BE7l2xmljegv})MEOd2oj%Fft z+8^4+CylMG%}*P{Oq@wEnoi&0L)keMW8Al7QP?*amG1UB{{DmA!`6PM^&m& zU^E(yC)d}F)x-5VI|L&(UK5_F$$$5L`793Hgl@ ziNXnN4(WoCfHIe`ix~_HL^ppnZWvMpFv;xZCT`Hq2&Xb`e2TAoe2@t> z5E6QIkmW|w!;&NN|ll@ z&#<_D`bfhfR4(o08OX4Bpa<)Np$S}~0=vlw713NU`u(~aSVnomGk}EY?&ZLU?!K2N zV{gTDA7(Lk7NeVI%FwVR6Eq+P&6(0#!7mp)_MS$B;|z;1r`Xq#F=+*z+GTu zAq2#RB?Pyhj+9)Uukk3i%Ix@w;5Uc-3QCS=?tC)Kk67hABD43Yubys8iYdTt^Ejth_uK#mw5vSUbISu8X7 z>6obCCp|*bOag$y|E5!(rA|0zJRnF*ZJzI#b_RqtOm4gOG6pVxVv(1$qPd~ToWIDk z!KDHn5~2=Nfp*5V2k+4gI&gHc&B&!7b5G+Wx(~0uOHPN%5#oNZdIkT!b0u5(@K^XJ zd;$Uifq+0jARrJB2nYlO0s?Owfq(hywZBNzDpo_O0%6DZDpedIJBSphOBlOUAr%39 z=$gAy0);k8j1X2J`a+@#VFE&&q6C3Fd6_1s#6R6S8Dx@DM!1dOgQ@{KLl8;XsL4na zi&wJReqb8B5506i9f0X1gsK}A|aM3MN7mko=y@Ilw#-)2*oe0AsTS_?wWRfVQ zg+LPd3gojyT$!Z7TA++0@g%B~kdd#n*$ zQ=o{@8Edl|37XhfmQb8RM2|>)1A)7u5S2#p1sqx=eH!e^)>AgHc4%(hxPdwd!dlTp z8oL0wxXInN{gT@n4z5ZO=7qc{svbxxR*ODUhRj!vAPjMlXFq;;v`cXMz<8R9pBCcU z3VZ#^KmBISl@i|%+w=Qw&mVgw5$t~7z2N`LH?HKvfB}JkKtLcM5D*9m1Ox&C0fB%( zKp-Fx5C{nTh!CLqKYr;yd;$Uifq+0jARrJB2nYlO0s;YnfIvVXAP^9EixCL%|69!5 zu(W_cKp-Fx5C{ka1Ofs9fq+0jARrJB2ncutLi`^@As`SC2nYlO0s;YnfIvVXAP^7; z2m}NI0&hP8A^v~+c^p<45C{ka1Ofs9fq+0jARrJB2nYlO0s;X6LSU{9+3X*etp3@| z$)65g=w7zaBdhYqEJH`J48VnsVy@j>=qUDc=qMKSYCs?$5D*9m1Ox&C0fB%(Kp-IS zV?`izG@og6PCXbyNAo4k-`nZ|b!wp|GsX&ZJYlXQHxAhr`l7UzZ?o(=sFpoa=Nnpv zF3V`O6S^#iF3WFym*q*1Wma|<4lS0c8}zhy)6ccV@=Swe^zZsX`zt#ehK}uMppAC* zLv*Z1KP?dTLz7i=CiTg)^*l?~Z?W~V$=GN#YI@_keUn;^-B4)FHfZpozuJx5@Ed3% zF0l$F`3=KWqnB|NNfYVyI$Mvlq8{lqDhZ6E#=Vwe0y{IlO~((Z_TzoL2Gj~P4_dNOnY&o z9UEO)7;&aQ_T<4#P=`A9Dq^S^9kl@;9yoaXon9=o3)70f& zxe;gQoR?SjsGz>!2fFC#GayOL>l63%OwT;(4v$uJXv>F=cW6>~s`SWL;Hd3e3B>%e z>+GSD7LOdGdmg&j6Hp}`6@Ow8E~uP#zPZ`mWP455XO24Rp+h(t!_fj`VYy5&Zk5P| zzUWJab$$KbIFv))7e(9m7Xh*U{3&hO+qZAi4+tXK8di&xj2rCWB+(<|c2LnI5sd;B zH5V-FPp%o@T;IVirzV7+pqOgsVQ3fK+r22e$KbDAc_} zISKT_Ou%j1G0{Mz+>z!YVLIA@D|AOF z0j~`H)jT?>Fa{p`a@sH8XiaDIBN>{rwSVBponwZNT?x`Tx4x}TAi!ln^rG0I>?Y15 z^a>|u-wraJ_Xq5ZXD+W@K3GJP2R|% zu%b$hfzhLYq(6;Q5EikUn`m*a5i`V%PjR@%2MF^ALfRtmLVtEd-Npr`uJ1YehEs$Q zW!g^&FyMN-I2z*^*;nYzj%>5pl@=psTZi*0E`_<2*&? zVwP+Q2y_o=3WNnZ!Bs>D2n>i}nrW!2jO|QP927nv=8JQzz3BNK=_Ib+u#;z4p>>+R zmkIc=_|nt;x(lOZlqWocr;BjoUXJLESavT@#!dDJA&A?d^GSykZD7uS7_;7yvV@!>$hj|n-C5fLI z@ej_Bz@>;OiDG0K@(kgVFhdbZx{+u$Lz=S4$qXivG+~7}M-~UW%aKqD2_-%7AW{(E zDx7E^&@mw5? zI0Tp{JUT^EwWNDq1JF9^$hl(YLPp5Q@yG(>s=QSi5?;t$3|(-TB5y~S zKy;KKRZHnVN~;>33K%GsXnjgV)46$;LCF`vJe0!;CQ2duFg>)uIVDsCu5OP~RI0F{ zC+wJuUrW}_2d{IJI{}{wV0?tk(Q(OBj!cT4%9YcK4zjK$#)^*{+d6 zobJ%s^ad^!Y#@L-BzevfBfBTfphIdACL6|*d;=OM(S4|sE_o;_PZIbJR}ufOuKvdg z{tKU!rU&X0S&#gcQaI z+J`diG-zMb!|)3#gO)=%`#PH}-fFTtq*{43FU~5|wpDmrCcG^(n;l=4{U%wwaEYR| zSek$axA5@1*nY=?ftPh`iZ@s&@W}z^{Jor*Gw#Tevcl~&8gKPrA^$bx0!tQTikh&;=xZtlo>ku~*d5VlfH3T0CM8IXp z2sb%~*K1sO>s?t2t>KsFN@5$qDh+i%hiXeW;ANpqzDc#87y+M>0VR=SWdxN^3Qf4~dW)$>98$Q{)2O zr(F$zj4y(CMXLA6SOi|%#EVoE8sA3Quh!Tt2+ zEFy@!c+D7je~A}Sk#=^T*s|9tF)RudC|JRhD+{l1UQk|gg(RAQJ`L6aWgPkQX?PZLn$`%fHx6?^Z9|wmmI(E!=i-UZ5a{!eI4R0cIHD0 Date: Sun, 7 Jan 2024 09:55:43 -0800 Subject: [PATCH 19/19] Lint --- permchain/langgraph/__init__.py | 17 ++++++----------- tests/test_pregel.py | 6 +++--- tests/test_pregel_async.py | 6 +++--- 3 files changed, 12 insertions(+), 17 deletions(-) diff --git a/permchain/langgraph/__init__.py b/permchain/langgraph/__init__.py index 02573bfc7..1b5fcde3a 100644 --- a/permchain/langgraph/__init__.py +++ b/permchain/langgraph/__init__.py @@ -12,11 +12,6 @@ from langchain_core.runnables.base import ( from permchain.pregel import Channel, Pregel -class Edge(NamedTuple): - start: str - end: str - - class Branch(NamedTuple): condition: Callable[..., str] ends: dict[str, str] @@ -30,9 +25,9 @@ END = "__end__" class Graph: - def __init__(self): + def __init__(self) -> None: self.nodes: dict[str, Runnable] = {} - self.edges = set[Edge]() + self.edges = set[tuple[str, str]]() self.branches: defaultdict[str, list[Branch]] = defaultdict(list) def add_node(self, key: str, action: RunnableLike) -> None: @@ -60,7 +55,7 @@ class Graph: start_key: str, condition: Callable[..., str], conditional_edge_mapping: Dict[str, str], - ): + ) -> None: if start_key not in self.nodes: raise ValueError(f"Need to add_node `{start_key}` first") if iscoroutinefunction(condition): @@ -68,17 +63,17 @@ class Graph: self.branches[start_key].append(Branch(condition, conditional_edge_mapping)) - def set_entry_point(self, key: str): + def set_entry_point(self, key: str) -> None: if key not in self.nodes: raise ValueError(f"Need to add_node `{key}` first") self.entry_point = key - def set_finish_point(self, key: str): + def set_finish_point(self, key: str) -> None: if key not in self.nodes: raise ValueError(f"Need to add_node `{key}` first") self.finish_point = key - def compile(self): + def compile(self) -> Pregel: ################################################ # STEP 1: VALIDATE GRAPH STRUCTURE # ################################################ diff --git a/tests/test_pregel.py b/tests/test_pregel.py index 642098321..30a8f891a 100644 --- a/tests/test_pregel.py +++ b/tests/test_pregel.py @@ -597,8 +597,8 @@ def test_conditional_graph() -> None: agent = RunnablePassthrough.assign(agent_outcome=prompt | llm | agent_parser) # Define tool execution logic - def execute_tools(data): - agent_action: AgentAction | AgentFinish = data.pop("agent_outcome") + def execute_tools(data: dict) -> dict: + agent_action: AgentAction = data.pop("agent_outcome") observation = {t.name: t for t in tools}[agent_action.tool].invoke( agent_action.tool_input ) @@ -608,7 +608,7 @@ def test_conditional_graph() -> None: return data # Define decision-making logic - def should_continue(data): + def should_continue(data: dict) -> str: # Logic to decide whether to continue in the loop or exit if isinstance(data["agent_outcome"], AgentFinish): return "exit" diff --git a/tests/test_pregel_async.py b/tests/test_pregel_async.py index c205e0dac..082b8569a 100644 --- a/tests/test_pregel_async.py +++ b/tests/test_pregel_async.py @@ -625,8 +625,8 @@ async def test_conditional_graph() -> None: agent = RunnablePassthrough.assign(agent_outcome=prompt | llm | agent_parser) # Define tool execution logic - async def execute_tools(data): - agent_action: AgentAction | AgentFinish = data.pop("agent_outcome") + async def execute_tools(data: dict) -> dict: + agent_action: AgentAction = data.pop("agent_outcome") observation = await {t.name: t for t in tools}[agent_action.tool].ainvoke( agent_action.tool_input ) @@ -636,7 +636,7 @@ async def test_conditional_graph() -> None: return data # Define decision-making logic - def should_continue(data): + def should_continue(data: dict) -> str: # Logic to decide whether to continue in the loop or exit if isinstance(data["agent_outcome"], AgentFinish): return "exit"