diff --git a/.github/DISCUSSION_TEMPLATE/q-a.yml b/.github/DISCUSSION_TEMPLATE/q-a.yml index d0229b2d7bd..af6688cde17 100644 --- a/.github/DISCUSSION_TEMPLATE/q-a.yml +++ b/.github/DISCUSSION_TEMPLATE/q-a.yml @@ -22,7 +22,7 @@ body: if there's another way to solve your problem: [LangChain documentation with the integrated search](https://python.langchain.com/docs/get_started/introduction), - [API Reference](https://api.python.langchain.com/en/stable/), + [API Reference](https://python.langchain.com/api_reference/), [GitHub search](https://github.com/langchain-ai/langchain), [LangChain Github Discussions](https://github.com/langchain-ai/langchain/discussions), [LangChain Github Issues](https://github.com/langchain-ai/langchain/issues?q=is%3Aissue), diff --git a/.github/ISSUE_TEMPLATE/bug-report.yml b/.github/ISSUE_TEMPLATE/bug-report.yml index 4fe94a53c8f..f1276df4de6 100644 --- a/.github/ISSUE_TEMPLATE/bug-report.yml +++ b/.github/ISSUE_TEMPLATE/bug-report.yml @@ -16,7 +16,7 @@ body: if there's another way to solve your problem: [LangChain documentation with the integrated search](https://python.langchain.com/docs/get_started/introduction), - [API Reference](https://api.python.langchain.com/en/stable/), + [API Reference](https://python.langchain.com/api_reference/), [GitHub search](https://github.com/langchain-ai/langchain), [LangChain Github Discussions](https://github.com/langchain-ai/langchain/discussions), [LangChain Github Issues](https://github.com/langchain-ai/langchain/issues?q=is%3Aissue), diff --git a/.github/ISSUE_TEMPLATE/documentation.yml b/.github/ISSUE_TEMPLATE/documentation.yml index 0b4bd4bd7d2..a931cef1d29 100644 --- a/.github/ISSUE_TEMPLATE/documentation.yml +++ b/.github/ISSUE_TEMPLATE/documentation.yml @@ -21,7 +21,7 @@ body: place to ask your question: [LangChain documentation with the integrated search](https://python.langchain.com/docs/get_started/introduction), - [API Reference](https://api.python.langchain.com/en/stable/), + [API Reference](https://python.langchain.com/api_reference/), [GitHub search](https://github.com/langchain-ai/langchain), [LangChain Github Discussions](https://github.com/langchain-ai/langchain/discussions), [LangChain Github Issues](https://github.com/langchain-ai/langchain/issues?q=is%3Aissue), diff --git a/.github/scripts/check_diff.py b/.github/scripts/check_diff.py index fbbe47aa4a9..873a98d158c 100644 --- a/.github/scripts/check_diff.py +++ b/.github/scripts/check_diff.py @@ -272,6 +272,7 @@ if __name__ == "__main__": # TODO: update to include all packages that rely on standard-tests (all partner packages) # note: won't run on external repo partners dirs_to_run["lint"].add("libs/standard-tests") + dirs_to_run["test"].add("libs/standard-tests") dirs_to_run["test"].add("libs/partners/mistralai") dirs_to_run["test"].add("libs/partners/openai") dirs_to_run["test"].add("libs/partners/anthropic") @@ -279,8 +280,9 @@ if __name__ == "__main__": dirs_to_run["test"].add("libs/partners/groq") elif file.startswith("libs/cli"): - # todo: add cli makefile - pass + dirs_to_run["lint"].add("libs/cli") + dirs_to_run["test"].add("libs/cli") + elif file.startswith("libs/partners"): partner_dir = file.split("/")[2] if os.path.isdir(f"libs/partners/{partner_dir}") and [ diff --git a/.github/workflows/_release.yml b/.github/workflows/_release.yml index 377b26a14a1..e54bcb360f4 100644 --- a/.github/workflows/_release.yml +++ b/.github/workflows/_release.yml @@ -192,7 +192,12 @@ jobs: poetry-version: ${{ env.POETRY_VERSION }} working-directory: ${{ inputs.working-directory }} - - name: Import published package + - uses: actions/download-artifact@v4 + with: + name: dist + path: ${{ inputs.working-directory }}/dist/ + + - name: Import dist package shell: bash working-directory: ${{ inputs.working-directory }} env: @@ -208,15 +213,7 @@ jobs: # - attempt install again after 5 seconds if it fails because there is # sometimes a delay in availability on test pypi run: | - poetry run pip install \ - --extra-index-url https://test.pypi.org/simple/ \ - "$PKG_NAME==$VERSION" || \ - ( \ - sleep 15 && \ - poetry run pip install \ - --extra-index-url https://test.pypi.org/simple/ \ - "$PKG_NAME==$VERSION" \ - ) + poetry run pip install dist/*.whl # Replace all dashes in the package name with underscores, # since that's how Python imports packages with dashes in the name. @@ -225,10 +222,10 @@ jobs: poetry run python -c "import $IMPORT_NAME; print(dir($IMPORT_NAME))" - name: Import test dependencies - run: poetry install --with test + run: poetry install --with test --no-root working-directory: ${{ inputs.working-directory }} - # Overwrite the local version of the package with the test PyPI version. + # Overwrite the local version of the package with the built version - name: Import published package (again) working-directory: ${{ inputs.working-directory }} shell: bash @@ -236,9 +233,7 @@ jobs: PKG_NAME: ${{ needs.build.outputs.pkg-name }} VERSION: ${{ needs.build.outputs.version }} run: | - poetry run pip install \ - --extra-index-url https://test.pypi.org/simple/ \ - "$PKG_NAME==$VERSION" + poetry run pip install dist/*.whl - name: Run unit tests run: make tests diff --git a/.github/workflows/scheduled_test.yml b/.github/workflows/scheduled_test.yml index 4134afd1d39..bcf489e52b1 100644 --- a/.github/workflows/scheduled_test.yml +++ b/.github/workflows/scheduled_test.yml @@ -14,17 +14,7 @@ on: env: POETRY_VERSION: "1.8.4" - DEFAULT_LIBS: > - [ - "libs/partners/openai", - "libs/partners/anthropic", - "libs/partners/fireworks", - "libs/partners/groq", - "libs/partners/mistralai", - "libs/partners/google-vertexai", - "libs/partners/google-genai", - "libs/partners/aws" - ] + DEFAULT_LIBS: '["libs/partners/openai", "libs/partners/anthropic", "libs/partners/fireworks", "libs/partners/groq", "libs/partners/mistralai", "libs/partners/google-vertexai", "libs/partners/google-genai", "libs/partners/aws"]' jobs: compute-matrix: diff --git a/Makefile b/Makefile index 5b684c94ac9..05fd5b5cfea 100644 --- a/Makefile +++ b/Makefile @@ -69,7 +69,11 @@ lint lint_package lint_tests: poetry run ruff check docs cookbook poetry run ruff format docs cookbook cookbook --diff poetry run ruff check --select I docs cookbook - git grep 'from langchain import' docs/docs cookbook | grep -vE 'from langchain import (hub)' && exit 1 || exit 0 + git --no-pager grep 'from langchain import' docs cookbook | grep -vE 'from langchain import (hub)' && echo "Error: no importing langchain from root in docs, except for hub" && exit 1 || exit 0 + + git --no-pager grep 'api.python.langchain.com' -- docs/docs ':!docs/docs/additional_resources/arxiv_references.mdx' ':!docs/docs/integrations/document_loaders/sitemap.ipynb' || exit 0 && \ + echo "Error: you should link python.langchain.com/api_reference, not api.python.langchain.com in the docs" && \ + exit 1 ## format: Format the project files. format format_diff: diff --git a/README.md b/README.md index f3e64b60cdb..04de99fad0f 100644 --- a/README.md +++ b/README.md @@ -123,7 +123,7 @@ Please see [here](https://python.langchain.com) for full documentation, which in - [Tutorials](https://python.langchain.com/docs/tutorials/): If you're looking to build something specific or are more of a hands-on learner, check out our tutorials. This is the best place to get started. - [How-to guides](https://python.langchain.com/docs/how_to/): Answers to “How do I….?” type questions. These guides are goal-oriented and concrete; they're meant to help you complete a specific task. - [Conceptual guide](https://python.langchain.com/docs/concepts/): Conceptual explanations of the key parts of the framework. -- [API Reference](https://api.python.langchain.com): Thorough documentation of every class and method. +- [API Reference](https://python.langchain.com/api_reference/): Thorough documentation of every class and method. ## 🌐 Ecosystem diff --git a/SECURITY.md b/SECURITY.md index 50e0632582c..15e44be0b43 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -1,5 +1,30 @@ # Security Policy +LangChain has a large ecosystem of integrations with various external resources like local and remote file systems, APIs and databases. These integrations allow developers to create versatile applications that combine the power of LLMs with the ability to access, interact with and manipulate external resources. + +## Best practices + +When building such applications developers should remember to follow good security practices: + +* [**Limit Permissions**](https://en.wikipedia.org/wiki/Principle_of_least_privilege): Scope permissions specifically to the application's need. Granting broad or excessive permissions can introduce significant security vulnerabilities. To avoid such vulnerabilities, consider using read-only credentials, disallowing access to sensitive resources, using sandboxing techniques (such as running inside a container), specifying proxy configurations to control external requests, etc. as appropriate for your application. +* **Anticipate Potential Misuse**: Just as humans can err, so can Large Language Models (LLMs). Always assume that any system access or credentials may be used in any way allowed by the permissions they are assigned. For example, if a pair of database credentials allows deleting data, it’s safest to assume that any LLM able to use those credentials may in fact delete data. +* [**Defense in Depth**](https://en.wikipedia.org/wiki/Defense_in_depth_(computing)): No security technique is perfect. Fine-tuning and good chain design can reduce, but not eliminate, the odds that a Large Language Model (LLM) may make a mistake. It’s best to combine multiple layered security approaches rather than relying on any single layer of defense to ensure security. For example: use both read-only permissions and sandboxing to ensure that LLMs are only able to access data that is explicitly meant for them to use. + +Risks of not doing so include, but are not limited to: +* Data corruption or loss. +* Unauthorized access to confidential information. +* Compromised performance or availability of critical resources. + +Example scenarios with mitigation strategies: + +* A user may ask an agent with access to the file system to delete files that should not be deleted or read the content of files that contain sensitive information. To mitigate, limit the agent to only use a specific directory and only allow it to read or write files that are safe to read or write. Consider further sandboxing the agent by running it in a container. +* A user may ask an agent with write access to an external API to write malicious data to the API, or delete data from that API. To mitigate, give the agent read-only API keys, or limit it to only use endpoints that are already resistant to such misuse. +* A user may ask an agent with access to a database to drop a table or mutate the schema. To mitigate, scope the credentials to only the tables that the agent needs to access and consider issuing READ-ONLY credentials. + +If you're building applications that access external resources like file systems, APIs +or databases, consider speaking with your company's security team to determine how to best +design and secure your applications. + ## Reporting OSS Vulnerabilities LangChain is partnered with [huntr by Protect AI](https://huntr.com/) to provide @@ -14,7 +39,7 @@ Before reporting a vulnerability, please review: 1) In-Scope Targets and Out-of-Scope Targets below. 2) The [langchain-ai/langchain](https://python.langchain.com/docs/contributing/repo_structure) monorepo structure. -3) LangChain [security guidelines](https://python.langchain.com/docs/security) to +3) The [Best practicies](#best-practices) above to understand what we consider to be a security vulnerability vs. developer responsibility. @@ -33,13 +58,13 @@ The following packages and repositories are eligible for bug bounties: All out of scope targets defined by huntr as well as: - **langchain-experimental**: This repository is for experimental code and is not - eligible for bug bounties, bug reports to it will be marked as interesting or waste of + eligible for bug bounties (see [package warning](https://pypi.org/project/langchain-experimental/)), bug reports to it will be marked as interesting or waste of time and published with no bounty attached. - **tools**: Tools in either langchain or langchain-community are not eligible for bug bounties. This includes the following directories - - langchain/tools - - langchain-community/tools - - Please review our [security guidelines](https://python.langchain.com/docs/security) + - libs/langchain/langchain/tools + - libs/community/langchain_community/tools + - Please review the [best practices](#best-practices) for more details, but generally tools interact with the real world. Developers are expected to understand the security implications of their code and are responsible for the security of their tools. @@ -47,7 +72,7 @@ All out of scope targets defined by huntr as well as: case basis, but likely will not be eligible for a bounty as the code is already documented with guidelines for developers that should be followed for making their application secure. -- Any LangSmith related repositories or APIs see below. +- Any LangSmith related repositories or APIs (see [Reporting LangSmith Vulnerabilities](#reporting-langsmith-vulnerabilities)). ## Reporting LangSmith Vulnerabilities diff --git a/docs/Makefile b/docs/Makefile index a3c41260e3d..f8d5d96714d 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -47,6 +47,7 @@ generate-files: $(PYTHON) scripts/partner_pkg_table.py $(INTERMEDIATE_DIR) curl https://raw.githubusercontent.com/langchain-ai/langserve/main/README.md | sed 's/<=/\<=/g' > $(INTERMEDIATE_DIR)/langserve.md + cp ../SECURITY.md $(INTERMEDIATE_DIR)/security.md $(PYTHON) scripts/resolve_local_links.py $(INTERMEDIATE_DIR)/langserve.md https://github.com/langchain-ai/langserve/tree/main/ copy-infra: diff --git a/docs/docs/additional_resources/arxiv_references.mdx b/docs/docs/additional_resources/arxiv_references.mdx index 461399688f6..fb843aa0c3c 100644 --- a/docs/docs/additional_resources/arxiv_references.mdx +++ b/docs/docs/additional_resources/arxiv_references.mdx @@ -28,19 +28,19 @@ From the opposite direction, scientists use `LangChain` in research and referenc | `2307.09288v2` [Llama 2: Open Foundation and Fine-Tuned Chat Models](http://arxiv.org/abs/2307.09288v2) | Hugo Touvron, Louis Martin, Kevin Stone, et al. | 2023‑07‑18 | `Cookbook:` [Semi Structured Rag](https://github.com/langchain-ai/langchain/blob/master/cookbook/Semi_Structured_RAG.ipynb) | `2307.03172v3` [Lost in the Middle: How Language Models Use Long Contexts](http://arxiv.org/abs/2307.03172v3) | Nelson F. Liu, Kevin Lin, John Hewitt, et al. | 2023‑07‑06 | `Docs:` [docs/how_to/long_context_reorder](https://python.langchain.com/docs/how_to/long_context_reorder) | `2305.14283v3` [Query Rewriting for Retrieval-Augmented Large Language Models](http://arxiv.org/abs/2305.14283v3) | Xinbei Ma, Yeyun Gong, Pengcheng He, et al. | 2023‑05‑23 | `Template:` [rewrite-retrieve-read](https://python.langchain.com/docs/templates/rewrite-retrieve-read), `Cookbook:` [Rewrite](https://github.com/langchain-ai/langchain/blob/master/cookbook/rewrite.ipynb) -| `2305.08291v1` [Large Language Model Guided Tree-of-Thought](http://arxiv.org/abs/2305.08291v1) | Jieyi Long | 2023‑05‑15 | `API:` [langchain_experimental.tot](https://api.python.langchain.com/en/latest/experimental_api_reference.html#module-langchain_experimental.tot), `Cookbook:` [Tree Of Thought](https://github.com/langchain-ai/langchain/blob/master/cookbook/tree_of_thought.ipynb) +| `2305.08291v1` [Large Language Model Guided Tree-of-Thought](http://arxiv.org/abs/2305.08291v1) | Jieyi Long | 2023‑05‑15 | `API:` [langchain_experimental.tot](https://python.langchain.com/api_reference/experimental/tot.html), `Cookbook:` [Tree Of Thought](https://github.com/langchain-ai/langchain/blob/master/cookbook/tree_of_thought.ipynb) | `2305.04091v3` [Plan-and-Solve Prompting: Improving Zero-Shot Chain-of-Thought Reasoning by Large Language Models](http://arxiv.org/abs/2305.04091v3) | Lei Wang, Wanyu Xu, Yihuai Lan, et al. | 2023‑05‑06 | `Cookbook:` [Plan And Execute Agent](https://github.com/langchain-ai/langchain/blob/master/cookbook/plan_and_execute_agent.ipynb) -| `2305.02156v1` [Zero-Shot Listwise Document Reranking with a Large Language Model](http://arxiv.org/abs/2305.02156v1) | Xueguang Ma, Xinyu Zhang, Ronak Pradeep, et al. | 2023‑05‑03 | `Docs:` [docs/how_to/contextual_compression](https://python.langchain.com/docs/how_to/contextual_compression), `API:` [langchain...LLMListwiseRerank](https://api.python.langchain.com/en/latest/retrievers/langchain.retrievers.document_compressors.listwise_rerank.LLMListwiseRerank.html#langchain.retrievers.document_compressors.listwise_rerank.LLMListwiseRerank) +| `2305.02156v1` [Zero-Shot Listwise Document Reranking with a Large Language Model](http://arxiv.org/abs/2305.02156v1) | Xueguang Ma, Xinyu Zhang, Ronak Pradeep, et al. | 2023‑05‑03 | `Docs:` [docs/how_to/contextual_compression](https://python.langchain.com/docs/how_to/contextual_compression), `API:` [langchain...LLMListwiseRerank](https://python.langchain.com/api_reference/langchain/retrievers/langchain.retrievers.document_compressors.listwise_rerank.LLMListwiseRerank.html#) | `2304.08485v2` [Visual Instruction Tuning](http://arxiv.org/abs/2304.08485v2) | Haotian Liu, Chunyuan Li, Qingyang Wu, et al. | 2023‑04‑17 | `Cookbook:` [Semi Structured Multi Modal Rag Llama2](https://github.com/langchain-ai/langchain/blob/master/cookbook/Semi_structured_multi_modal_RAG_LLaMA2.ipynb), [Semi Structured And Multi Modal Rag](https://github.com/langchain-ai/langchain/blob/master/cookbook/Semi_structured_and_multi_modal_RAG.ipynb) | `2304.03442v2` [Generative Agents: Interactive Simulacra of Human Behavior](http://arxiv.org/abs/2304.03442v2) | Joon Sung Park, Joseph C. O'Brien, Carrie J. Cai, et al. | 2023‑04‑07 | `Cookbook:` [Generative Agents Interactive Simulacra Of Human Behavior](https://github.com/langchain-ai/langchain/blob/master/cookbook/generative_agents_interactive_simulacra_of_human_behavior.ipynb), [Multiagent Bidding](https://github.com/langchain-ai/langchain/blob/master/cookbook/multiagent_bidding.ipynb) | `2303.17760v2` [CAMEL: Communicative Agents for "Mind" Exploration of Large Language Model Society](http://arxiv.org/abs/2303.17760v2) | Guohao Li, Hasan Abed Al Kader Hammoud, Hani Itani, et al. | 2023‑03‑31 | `Cookbook:` [Camel Role Playing](https://github.com/langchain-ai/langchain/blob/master/cookbook/camel_role_playing.ipynb) -| `2303.17580v4` [HuggingGPT: Solving AI Tasks with ChatGPT and its Friends in Hugging Face](http://arxiv.org/abs/2303.17580v4) | Yongliang Shen, Kaitao Song, Xu Tan, et al. | 2023‑03‑30 | `API:` [langchain_experimental.autonomous_agents](https://api.python.langchain.com/en/latest/experimental_api_reference.html#module-langchain_experimental.autonomous_agents), `Cookbook:` [Hugginggpt](https://github.com/langchain-ai/langchain/blob/master/cookbook/hugginggpt.ipynb) +| `2303.17580v4` [HuggingGPT: Solving AI Tasks with ChatGPT and its Friends in Hugging Face](http://arxiv.org/abs/2303.17580v4) | Yongliang Shen, Kaitao Song, Xu Tan, et al. | 2023‑03‑30 | `API:` [langchain_experimental.autonomous_agents](https://python.langchain.com/api_reference/experimental/autonomous_agents.html), `Cookbook:` [Hugginggpt](https://github.com/langchain-ai/langchain/blob/master/cookbook/hugginggpt.ipynb) | `2301.10226v4` [A Watermark for Large Language Models](http://arxiv.org/abs/2301.10226v4) | John Kirchenbauer, Jonas Geiping, Yuxin Wen, et al. | 2023‑01‑24 | `API:` [langchain_community...OCIModelDeploymentTGI](https://api.python.langchain.com/en/latest/llms/langchain_community.llms.oci_data_science_model_deployment_endpoint.OCIModelDeploymentTGI.html#langchain_community.llms.oci_data_science_model_deployment_endpoint.OCIModelDeploymentTGI), [langchain_huggingface...HuggingFaceEndpoint](https://api.python.langchain.com/en/latest/llms/langchain_huggingface.llms.huggingface_endpoint.HuggingFaceEndpoint.html#langchain_huggingface.llms.huggingface_endpoint.HuggingFaceEndpoint), [langchain_community...HuggingFaceTextGenInference](https://api.python.langchain.com/en/latest/llms/langchain_community.llms.huggingface_text_gen_inference.HuggingFaceTextGenInference.html#langchain_community.llms.huggingface_text_gen_inference.HuggingFaceTextGenInference), [langchain_community...HuggingFaceEndpoint](https://api.python.langchain.com/en/latest/llms/langchain_community.llms.huggingface_endpoint.HuggingFaceEndpoint.html#langchain_community.llms.huggingface_endpoint.HuggingFaceEndpoint) | `2212.10496v1` [Precise Zero-Shot Dense Retrieval without Relevance Labels](http://arxiv.org/abs/2212.10496v1) | Luyu Gao, Xueguang Ma, Jimmy Lin, et al. | 2022‑12‑20 | `Docs:` [docs/concepts](https://python.langchain.com/docs/concepts), `API:` [langchain...HypotheticalDocumentEmbedder](https://api.python.langchain.com/en/latest/chains/langchain.chains.hyde.base.HypotheticalDocumentEmbedder.html#langchain.chains.hyde.base.HypotheticalDocumentEmbedder), `Template:` [hyde](https://python.langchain.com/docs/templates/hyde), `Cookbook:` [Hypothetical Document Embeddings](https://github.com/langchain-ai/langchain/blob/master/cookbook/hypothetical_document_embeddings.ipynb) | `2212.08073v1` [Constitutional AI: Harmlessness from AI Feedback](http://arxiv.org/abs/2212.08073v1) | Yuntao Bai, Saurav Kadavath, Sandipan Kundu, et al. | 2022‑12‑15 | `Docs:` [docs/versions/migrating_chains/constitutional_chain](https://python.langchain.com/docs/versions/migrating_chains/constitutional_chain) -| `2212.07425v3` [Robust and Explainable Identification of Logical Fallacies in Natural Language Arguments](http://arxiv.org/abs/2212.07425v3) | Zhivar Sourati, Vishnu Priya Prasanna Venkatesh, Darshan Deshpande, et al. | 2022‑12‑12 | `API:` [langchain_experimental.fallacy_removal](https://api.python.langchain.com/en/latest/experimental_api_reference.html#module-langchain_experimental.fallacy_removal) +| `2212.07425v3` [Robust and Explainable Identification of Logical Fallacies in Natural Language Arguments](http://arxiv.org/abs/2212.07425v3) | Zhivar Sourati, Vishnu Priya Prasanna Venkatesh, Darshan Deshpande, et al. | 2022‑12‑12 | `API:` [langchain_experimental.fallacy_removal](https://python.langchain.com/api_reference/experimental/fallacy_removal.html) | `2211.13892v2` [Complementary Explanations for Effective In-Context Learning](http://arxiv.org/abs/2211.13892v2) | Xi Ye, Srinivasan Iyer, Asli Celikyilmaz, et al. | 2022‑11‑25 | `API:` [langchain_core...MaxMarginalRelevanceExampleSelector](https://api.python.langchain.com/en/latest/example_selectors/langchain_core.example_selectors.semantic_similarity.MaxMarginalRelevanceExampleSelector.html#langchain_core.example_selectors.semantic_similarity.MaxMarginalRelevanceExampleSelector) -| `2211.10435v2` [PAL: Program-aided Language Models](http://arxiv.org/abs/2211.10435v2) | Luyu Gao, Aman Madaan, Shuyan Zhou, et al. | 2022‑11‑18 | `API:` [langchain_experimental.pal_chain](https://api.python.langchain.com/en/latest/experimental_api_reference.html#module-langchain_experimental.pal_chain), [langchain_experimental...PALChain](https://api.python.langchain.com/en/latest/pal_chain/langchain_experimental.pal_chain.base.PALChain.html#langchain_experimental.pal_chain.base.PALChain), `Cookbook:` [Program Aided Language Model](https://github.com/langchain-ai/langchain/blob/master/cookbook/program_aided_language_model.ipynb) +| `2211.10435v2` [PAL: Program-aided Language Models](http://arxiv.org/abs/2211.10435v2) | Luyu Gao, Aman Madaan, Shuyan Zhou, et al. | 2022‑11‑18 | `API:` [langchain_experimental.pal_chain](https://python.langchain.com/api_reference/experimental/pal_chain.html), [langchain_experimental...PALChain](https://api.python.langchain.com/en/latest/pal_chain/langchain_experimental.pal_chain.base.PALChain.html#langchain_experimental.pal_chain.base.PALChain), `Cookbook:` [Program Aided Language Model](https://github.com/langchain-ai/langchain/blob/master/cookbook/program_aided_language_model.ipynb) | `2210.11934v2` [An Analysis of Fusion Functions for Hybrid Retrieval](http://arxiv.org/abs/2210.11934v2) | Sebastian Bruch, Siyu Gai, Amir Ingber | 2022‑10‑21 | `Docs:` [docs/concepts](https://python.langchain.com/docs/concepts) | `2210.03629v3` [ReAct: Synergizing Reasoning and Acting in Language Models](http://arxiv.org/abs/2210.03629v3) | Shunyu Yao, Jeffrey Zhao, Dian Yu, et al. | 2022‑10‑06 | `Docs:` [docs/integrations/tools/ionic_shopping](https://python.langchain.com/docs/integrations/tools/ionic_shopping), [docs/integrations/providers/cohere](https://python.langchain.com/docs/integrations/providers/cohere), [docs/concepts](https://python.langchain.com/docs/concepts), `API:` [langchain...create_react_agent](https://api.python.langchain.com/en/latest/agents/langchain.agents.react.agent.create_react_agent.html#langchain.agents.react.agent.create_react_agent), [langchain...TrajectoryEvalChain](https://api.python.langchain.com/en/latest/evaluation/langchain.evaluation.agents.trajectory_eval_chain.TrajectoryEvalChain.html#langchain.evaluation.agents.trajectory_eval_chain.TrajectoryEvalChain) | `2209.10785v2` [Deep Lake: a Lakehouse for Deep Learning](http://arxiv.org/abs/2209.10785v2) | Sasun Hambardzumyan, Abhinav Tuli, Levon Ghukasyan, et al. | 2022‑09‑22 | `Docs:` [docs/integrations/providers/activeloop_deeplake](https://python.langchain.com/docs/integrations/providers/activeloop_deeplake) @@ -49,7 +49,7 @@ From the opposite direction, scientists use `LangChain` in research and referenc | `2204.00498v1` [Evaluating the Text-to-SQL Capabilities of Large Language Models](http://arxiv.org/abs/2204.00498v1) | Nitarshan Rajkumar, Raymond Li, Dzmitry Bahdanau | 2022‑03‑15 | `Docs:` [docs/tutorials/sql_qa](https://python.langchain.com/docs/tutorials/sql_qa), `API:` [langchain_community...SQLDatabase](https://api.python.langchain.com/en/latest/utilities/langchain_community.utilities.sql_database.SQLDatabase.html#langchain_community.utilities.sql_database.SQLDatabase), [langchain_community...SparkSQL](https://api.python.langchain.com/en/latest/utilities/langchain_community.utilities.spark_sql.SparkSQL.html#langchain_community.utilities.spark_sql.SparkSQL) | `2202.00666v5` [Locally Typical Sampling](http://arxiv.org/abs/2202.00666v5) | Clara Meister, Tiago Pimentel, Gian Wiher, et al. | 2022‑02‑01 | `API:` [langchain_huggingface...HuggingFaceEndpoint](https://api.python.langchain.com/en/latest/llms/langchain_huggingface.llms.huggingface_endpoint.HuggingFaceEndpoint.html#langchain_huggingface.llms.huggingface_endpoint.HuggingFaceEndpoint), [langchain_community...HuggingFaceTextGenInference](https://api.python.langchain.com/en/latest/llms/langchain_community.llms.huggingface_text_gen_inference.HuggingFaceTextGenInference.html#langchain_community.llms.huggingface_text_gen_inference.HuggingFaceTextGenInference), [langchain_community...HuggingFaceEndpoint](https://api.python.langchain.com/en/latest/llms/langchain_community.llms.huggingface_endpoint.HuggingFaceEndpoint.html#langchain_community.llms.huggingface_endpoint.HuggingFaceEndpoint) | `2112.01488v3` [ColBERTv2: Effective and Efficient Retrieval via Lightweight Late Interaction](http://arxiv.org/abs/2112.01488v3) | Keshav Santhanam, Omar Khattab, Jon Saad-Falcon, et al. | 2021‑12‑02 | `Docs:` [docs/integrations/retrievers/ragatouille](https://python.langchain.com/docs/integrations/retrievers/ragatouille), [docs/integrations/providers/ragatouille](https://python.langchain.com/docs/integrations/providers/ragatouille), [docs/concepts](https://python.langchain.com/docs/concepts), [docs/integrations/providers/dspy](https://python.langchain.com/docs/integrations/providers/dspy) -| `2103.00020v1` [Learning Transferable Visual Models From Natural Language Supervision](http://arxiv.org/abs/2103.00020v1) | Alec Radford, Jong Wook Kim, Chris Hallacy, et al. | 2021‑02‑26 | `API:` [langchain_experimental.open_clip](https://api.python.langchain.com/en/latest/experimental_api_reference.html#module-langchain_experimental.open_clip) +| `2103.00020v1` [Learning Transferable Visual Models From Natural Language Supervision](http://arxiv.org/abs/2103.00020v1) | Alec Radford, Jong Wook Kim, Chris Hallacy, et al. | 2021‑02‑26 | `API:` [langchain_experimental.open_clip](https://python.langchain.com/api_reference/experimental/open_clip.html) | `2005.14165v4` [Language Models are Few-Shot Learners](http://arxiv.org/abs/2005.14165v4) | Tom B. Brown, Benjamin Mann, Nick Ryder, et al. | 2020‑05‑28 | `Docs:` [docs/concepts](https://python.langchain.com/docs/concepts) | `2005.11401v4` [Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks](http://arxiv.org/abs/2005.11401v4) | Patrick Lewis, Ethan Perez, Aleksandra Piktus, et al. | 2020‑05‑22 | `Docs:` [docs/concepts](https://python.langchain.com/docs/concepts) | `1909.05858v2` [CTRL: A Conditional Transformer Language Model for Controllable Generation](http://arxiv.org/abs/1909.05858v2) | Nitish Shirish Keskar, Bryan McCann, Lav R. Varshney, et al. | 2019‑09‑11 | `API:` [langchain_huggingface...HuggingFaceEndpoint](https://api.python.langchain.com/en/latest/llms/langchain_huggingface.llms.huggingface_endpoint.HuggingFaceEndpoint.html#langchain_huggingface.llms.huggingface_endpoint.HuggingFaceEndpoint), [langchain_community...HuggingFaceTextGenInference](https://api.python.langchain.com/en/latest/llms/langchain_community.llms.huggingface_text_gen_inference.HuggingFaceTextGenInference.html#langchain_community.llms.huggingface_text_gen_inference.HuggingFaceTextGenInference), [langchain_community...HuggingFaceEndpoint](https://api.python.langchain.com/en/latest/llms/langchain_community.llms.huggingface_endpoint.HuggingFaceEndpoint.html#langchain_community.llms.huggingface_endpoint.HuggingFaceEndpoint) @@ -433,7 +433,7 @@ for retrieval-augmented LLM. - **arXiv id:** [2305.08291v1](http://arxiv.org/abs/2305.08291v1) **Published Date:** 2023-05-15 - **LangChain:** - - **API Reference:** [langchain_experimental.tot](https://api.python.langchain.com/en/latest/experimental_api_reference.html#module-langchain_experimental.tot) + - **API Reference:** [langchain_experimental.tot](https://python.langchain.com/api_reference/experimental/tot.html) - **Cookbook:** [tree_of_thought](https://github.com/langchain-ai/langchain/blob/master/cookbook/tree_of_thought.ipynb) **Abstract:** In this paper, we introduce the Tree-of-Thought (ToT) framework, a novel @@ -490,7 +490,7 @@ https://github.com/AGI-Edgerunners/Plan-and-Solve-Prompting. - **LangChain:** - **Documentation:** [docs/how_to/contextual_compression](https://python.langchain.com/docs/how_to/contextual_compression) - - **API Reference:** [langchain...LLMListwiseRerank](https://api.python.langchain.com/en/latest/retrievers/langchain.retrievers.document_compressors.listwise_rerank.LLMListwiseRerank.html#langchain.retrievers.document_compressors.listwise_rerank.LLMListwiseRerank) + - **API Reference:** [langchain...LLMListwiseRerank](https://python.langchain.com/api_reference/langchain/retrievers/langchain.retrievers.document_compressors.listwise_rerank.LLMListwiseRerank.html#) **Abstract:** Supervised ranking methods based on bi-encoder or cross-encoder architectures have shown success in multi-stage text ranking tasks, but they require large @@ -597,7 +597,7 @@ agents and beyond: https://github.com/camel-ai/camel. - **arXiv id:** [2303.17580v4](http://arxiv.org/abs/2303.17580v4) **Published Date:** 2023-03-30 - **LangChain:** - - **API Reference:** [langchain_experimental.autonomous_agents](https://api.python.langchain.com/en/latest/experimental_api_reference.html#module-langchain_experimental.autonomous_agents) + - **API Reference:** [langchain_experimental.autonomous_agents](https://python.langchain.com/api_reference/experimental/autonomous_agents.html) - **Cookbook:** [hugginggpt](https://github.com/langchain-ai/langchain/blob/master/cookbook/hugginggpt.ipynb) **Abstract:** Solving complicated AI tasks with different domains and modalities is a key @@ -704,7 +704,7 @@ labels. - **arXiv id:** [2212.07425v3](http://arxiv.org/abs/2212.07425v3) **Published Date:** 2022-12-12 - **LangChain:** - - **API Reference:** [langchain_experimental.fallacy_removal](https://api.python.langchain.com/en/latest/experimental_api_reference.html#module-langchain_experimental.fallacy_removal) + - **API Reference:** [langchain_experimental.fallacy_removal](https://python.langchain.com/api_reference/experimental/fallacy_removal.html) **Abstract:** The spread of misinformation, propaganda, and flawed argumentation has been amplified in the Internet era. Given the volume of data and the subtlety of @@ -759,7 +759,7 @@ performance across three real-world tasks on multiple LLMs. - **arXiv id:** [2211.10435v2](http://arxiv.org/abs/2211.10435v2) **Published Date:** 2022-11-18 - **LangChain:** - - **API Reference:** [langchain_experimental.pal_chain](https://api.python.langchain.com/en/latest/experimental_api_reference.html#module-langchain_experimental.pal_chain), [langchain_experimental...PALChain](https://api.python.langchain.com/en/latest/pal_chain/langchain_experimental.pal_chain.base.PALChain.html#langchain_experimental.pal_chain.base.PALChain) + - **API Reference:** [langchain_experimental.pal_chain](https://python.langchain.com/api_reference/experimental/pal_chain.html), [langchain_experimental...PALChain](https://api.python.langchain.com/en/latest/pal_chain/langchain_experimental.pal_chain.base.PALChain.html#langchain_experimental.pal_chain.base.PALChain) - **Cookbook:** [program_aided_language_model](https://github.com/langchain-ai/langchain/blob/master/cookbook/program_aided_language_model.ipynb) **Abstract:** Large language models (LLMs) have recently demonstrated an impressive ability @@ -992,7 +992,7 @@ footprint of late interaction models by 6--10$\times$. - **arXiv id:** [2103.00020v1](http://arxiv.org/abs/2103.00020v1) **Published Date:** 2021-02-26 - **LangChain:** - - **API Reference:** [langchain_experimental.open_clip](https://api.python.langchain.com/en/latest/experimental_api_reference.html#module-langchain_experimental.open_clip) + - **API Reference:** [langchain_experimental.open_clip](https://python.langchain.com/api_reference/experimental/open_clip.html) **Abstract:** State-of-the-art computer vision systems are trained to predict a fixed set of predetermined object categories. This restricted form of supervision limits diff --git a/docs/docs/concepts/embedding_models.mdx b/docs/docs/concepts/embedding_models.mdx index 28a7a8c6497..a91018036c0 100644 --- a/docs/docs/concepts/embedding_models.mdx +++ b/docs/docs/concepts/embedding_models.mdx @@ -3,7 +3,7 @@ :::info[Prerequisites] -* [Documents](https://api.python.langchain.com/en/latest/documents/langchain_core.documents.base.Document.html) +* [Documents](https://python.langchain.com/api_reference/core/documents/langchain_core.documents.base.Document.html) ::: diff --git a/docs/docs/concepts/retrieval.mdx b/docs/docs/concepts/retrieval.mdx index 8d3d75a6082..69a2f755550 100644 --- a/docs/docs/concepts/retrieval.mdx +++ b/docs/docs/concepts/retrieval.mdx @@ -221,7 +221,7 @@ They are particularly useful for storing and querying complex relationships betw LangChain provides a unified interface for interacting with various retrieval systems through the [retriever](/docs/concepts/retrievers/) concept. The interface is straightforward: 1. Input: A query (string) -2. Output: A list of documents (standardized LangChain [Document](https://api.python.langchain.com/en/latest/documents/langchain_core.documents.base.Document.html) objects) +2. Output: A list of documents (standardized LangChain [Document](https://python.langchain.com/api_reference/core/documents/langchain_core.documents.base.Document.html) objects) You can create a retriever using any of the retrieval systems mentioned earlier. The query analysis techniques we discussed are particularly useful here, as they enable natural language interfaces for databases that typically require structured query languages. For example, you can build a retriever for a SQL database using text-to-SQL conversion. This allows a natural language query (string) to be transformed into a SQL query behind the scenes. diff --git a/docs/docs/concepts/retrievers.mdx b/docs/docs/concepts/retrievers.mdx index 3af42544004..1fb55a3f1c5 100644 --- a/docs/docs/concepts/retrievers.mdx +++ b/docs/docs/concepts/retrievers.mdx @@ -18,7 +18,7 @@ Because of their importance and variability, LangChain provides a uniform interf The LangChain [retriever](/docs/concepts/retrievers/) interface is straightforward: 1. Input: A query (string) -2. Output: A list of documents (standardized LangChain [Document](https://api.python.langchain.com/en/latest/documents/langchain_core.documents.base.Document.html) objects) +2. Output: A list of documents (standardized LangChain [Document](https://python.langchain.com/api_reference/core/documents/langchain_core.documents.base.Document.html) objects) ## Key concept @@ -29,7 +29,7 @@ All retrievers implement a simple interface for retrieving documents using natur ## Interface The only requirement for a retriever is the ability to accepts a query and return documents. -In particular, [LangChain's retriever class](https://api.python.langchain.com/en/latest/retrievers/langchain_core.retrievers.BaseRetriever.html) only requires that the `_get_relevant_documents` method is implemented, which takes a `query: str` and returns a list of [Document](https://api.python.langchain.com/en/latest/documents/langchain_core.documents.base.Document.html) objects that are most relevant to the query. +In particular, [LangChain's retriever class](https://python.langchain.com/api_reference/core/retrievers/langchain_core.retrievers.BaseRetriever.html#) only requires that the `_get_relevant_documents` method is implemented, which takes a `query: str` and returns a list of [Document](https://python.langchain.com/api_reference/core/documents/langchain_core.documents.base.Document.html) objects that are most relevant to the query. The underlying logic used to get relevant documents is specified by the retriever and can be whatever is most useful for the application. A LangChain retriever is a [runnable](/docs/how_to/lcel_cheatsheet/), which is a standard interface is for LangChain components. @@ -39,7 +39,7 @@ This means that it has a few common methods, including `invoke`, that are used t docs = retriever.invoke(query) ``` -Retrievers return a list of [Document](https://api.python.langchain.com/en/latest/documents/langchain_core.documents.base.Document.html) objects, which have two attributes: +Retrievers return a list of [Document](https://python.langchain.com/api_reference/core/documents/langchain_core.documents.base.Document.html) objects, which have two attributes: * `page_content`: The content of this document. Currently is a string. * `metadata`: Arbitrary metadata associated with this document (e.g., document id, file name, source, etc). diff --git a/docs/docs/concepts/runnables.mdx b/docs/docs/concepts/runnables.mdx index dea928568a7..93af2cecadc 100644 --- a/docs/docs/concepts/runnables.mdx +++ b/docs/docs/concepts/runnables.mdx @@ -125,7 +125,7 @@ Please see the [Configurable Runnables](#configurable-runnables) section for mor LangChain will automatically try to infer the input and output types of a Runnable based on available information. -Currently, this inference does not work well for more complex Runnables that are built using [LCEL](/docs/concepts/lcel) composition, and the inferred input and / or output types may be incorrect. In these cases, we recommend that users override the inferred input and output types using the `with_types` method ([API Reference](https://api.python.langchain.com/en/latest/runnables/langchain_core.runnables.base.Runnable.html#langchain_core.runnables.base.Runnable.with_types +Currently, this inference does not work well for more complex Runnables that are built using [LCEL](/docs/concepts/lcel) composition, and the inferred input and / or output types may be incorrect. In these cases, we recommend that users override the inferred input and output types using the `with_types` method ([API Reference](https://python.langchain.com/api_reference/core/runnables/langchain_core.runnables.base.Runnable.html#langchain_core.runnables.base.Runnable.with_types ). ## RunnableConfig diff --git a/docs/docs/concepts/vectorstores.mdx b/docs/docs/concepts/vectorstores.mdx index aa5bcae7a2c..1a909453744 100644 --- a/docs/docs/concepts/vectorstores.mdx +++ b/docs/docs/concepts/vectorstores.mdx @@ -59,7 +59,7 @@ vector_store = InMemoryVectorStore(embedding=SomeEmbeddingModel()) To add documents, use the `add_documents` method. -This API works with a list of [Document](https://api.python.langchain.com/en/latest/documents/langchain_core.documents.base.Document.html) objects. +This API works with a list of [Document](https://python.langchain.com/api_reference/core/documents/langchain_core.documents.base.Document.html) objects. `Document` objects all have `page_content` and `metadata` attributes, making them a universal way to store unstructured text and associated metadata. ```python @@ -126,7 +126,7 @@ to the documentation of the specific vectorstore you are using to see what simil Given a similarity metric to measure the distance between the embedded query and any embedded document, we need an algorithm to efficiently search over *all* the embedded documents to find the most similar ones. There are various ways to do this. As an example, many vectorstores implement [HNSW (Hierarchical Navigable Small World)](https://www.pinecone.io/learn/series/faiss/hnsw/), a graph-based index structure that allows for efficient similarity search. Regardless of the search algorithm used under the hood, the LangChain vectorstore interface has a `similarity_search` method for all integrations. -This will take the search query, create an embedding, find similar documents, and return them as a list of [Documents](https://api.python.langchain.com/en/latest/documents/langchain_core.documents.base.Document.html). +This will take the search query, create an embedding, find similar documents, and return them as a list of [Documents](https://python.langchain.com/api_reference/core/documents/langchain_core.documents.base.Document.html). ```python query = "my query" diff --git a/docs/docs/how_to/custom_tools.ipynb b/docs/docs/how_to/custom_tools.ipynb index 8046b7b00e4..e9a50a72e11 100644 --- a/docs/docs/how_to/custom_tools.ipynb +++ b/docs/docs/how_to/custom_tools.ipynb @@ -162,7 +162,7 @@ "\n", "@tool\n", "def multiply_by_max(\n", - " a: Annotated[str, \"scale factor\"],\n", + " a: Annotated[int, \"scale factor\"],\n", " b: Annotated[List[int], \"list of ints over which to take maximum\"],\n", ") -> int:\n", " \"\"\"Multiply a by the maximum of b.\"\"\"\n", diff --git a/docs/docs/how_to/graph_constructing.ipynb b/docs/docs/how_to/graph_constructing.ipynb index d36ca54c8cf..d036720b674 100644 --- a/docs/docs/how_to/graph_constructing.ipynb +++ b/docs/docs/how_to/graph_constructing.ipynb @@ -245,7 +245,7 @@ " allowed_nodes=[\"Person\", \"Country\", \"Organization\"],\n", " allowed_relationships=allowed_relationships,\n", ")\n", - "llm_transformer_tuple = llm_transformer_filtered.convert_to_graph_documents(documents)\n", + "graph_documents_filtered = llm_transformer_tuple.convert_to_graph_documents(documents)\n", "print(f\"Nodes:{graph_documents_filtered[0].nodes}\")\n", "print(f\"Relationships:{graph_documents_filtered[0].relationships}\")" ] diff --git a/docs/docs/how_to/graph_semantic.ipynb b/docs/docs/how_to/graph_semantic.ipynb index 4cd717d8612..f2832853e1c 100644 --- a/docs/docs/how_to/graph_semantic.ipynb +++ b/docs/docs/how_to/graph_semantic.ipynb @@ -31,20 +31,12 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": null, "id": "ffdd48f6-bd05-4e5c-b846-d41183398a55", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Note: you may need to restart the kernel to use updated packages.\n" - ] - } - ], + "outputs": [], "source": [ - "%pip install --upgrade --quiet langchain langchain-neo4j langchain-openai neo4j" + "%pip install --upgrade --quiet langchain langchain-neo4j langchain-openai" ] }, { @@ -57,7 +49,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 1, "id": "eb11c4a8-c00c-4c2d-9309-74a6acfff91c", "metadata": {}, "outputs": [ @@ -91,7 +83,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 2, "id": "ef59a3af-31a8-4ad8-8eb9-132aca66956e", "metadata": {}, "outputs": [], @@ -111,7 +103,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 3, "id": "c84b1449-6fcd-4140-b591-cb45e8dce207", "metadata": {}, "outputs": [ @@ -121,7 +113,7 @@ "[]" ] }, - "execution_count": 4, + "execution_count": 3, "metadata": {}, "output_type": "execute_result" } @@ -129,7 +121,7 @@ "source": [ "from langchain_neo4j import Neo4jGraph\n", "\n", - "graph = Neo4jGraph()\n", + "graph = Neo4jGraph(refresh_schema=False)\n", "\n", "# Import movie information\n", "\n", @@ -170,26 +162,15 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 4, "id": "d1dc1c8c-f343-4024-924b-a8a86cf5f1af", "metadata": {}, "outputs": [], "source": [ - "from typing import Optional, Type\n", - "\n", - "from langchain_core.callbacks import (\n", - " AsyncCallbackManagerForToolRun,\n", - " CallbackManagerForToolRun,\n", - ")\n", - "from langchain_core.tools import BaseTool\n", - "\n", - "# Import things that are needed generically\n", - "from pydantic import BaseModel, Field\n", - "\n", "description_query = \"\"\"\n", "MATCH (m:Movie|Person)\n", "WHERE m.title CONTAINS $candidate OR m.name CONTAINS $candidate\n", - "MATCH (m)-[r:ACTED_IN|HAS_GENRE]-(t)\n", + "MATCH (m)-[r:ACTED_IN|IN_GENRE]-(t)\n", "WITH m, type(r) as type, collect(coalesce(t.name, t.title)) as names\n", "WITH m, type+\": \"+reduce(s=\"\", n IN names | s + n + \", \") as types\n", "WITH m, collect(types) as contexts\n", @@ -220,20 +201,14 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 5, "id": "f4cde772-0d05-475d-a2f0-b53e1669bd13", "metadata": {}, "outputs": [], "source": [ "from typing import Optional, Type\n", "\n", - "from langchain_core.callbacks import (\n", - " AsyncCallbackManagerForToolRun,\n", - " CallbackManagerForToolRun,\n", - ")\n", "from langchain_core.tools import BaseTool\n", - "\n", - "# Import things that are needed generically\n", "from pydantic import BaseModel, Field\n", "\n", "\n", @@ -251,7 +226,6 @@ " def _run(\n", " self,\n", " entity: str,\n", - " run_manager: Optional[CallbackManagerForToolRun] = None,\n", " ) -> str:\n", " \"\"\"Use the tool.\"\"\"\n", " return get_information(entity)\n", @@ -259,7 +233,6 @@ " async def _arun(\n", " self,\n", " entity: str,\n", - " run_manager: Optional[AsyncCallbackManagerForToolRun] = None,\n", " ) -> str:\n", " \"\"\"Use the tool asynchronously.\"\"\"\n", " return get_information(entity)" @@ -270,74 +243,103 @@ "id": "ff4820aa-2b57-4558-901f-6d984b326738", "metadata": {}, "source": [ - "## OpenAI Agent\n", + "## LangGraph Agent\n", "\n", - "LangChain expression language makes it very convenient to define an agent to interact with a graph database over the semantic layer." + "We will implement a straightforward ReAct agent using LangGraph.\n", + "\n", + "The agent consists of an LLM and tools step. As we interact with the agent, we will first call the LLM to decide if we should use tools. Then we will run a loop:\n", + "\n", + "If the agent said to take an action (i.e. call tool), we’ll run the tools and pass the results back to the agent.\n", + "If the agent did not ask to run tools, we will finish (respond to the user).\n", + "\n", + "The code implementation is as straightforward as it gets. First we bind the tools to the LLM and define the assistant step." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "6e959ac2-537d-4358-a43b-e3a47f68e1d6", + "metadata": {}, + "outputs": [], + "source": [ + "from langchain_core.messages import HumanMessage, SystemMessage\n", + "from langchain_openai import ChatOpenAI\n", + "from langgraph.graph import MessagesState\n", + "\n", + "llm = ChatOpenAI(model=\"gpt-4o\")\n", + "\n", + "tools = [InformationTool()]\n", + "llm_with_tools = llm.bind_tools(tools)\n", + "\n", + "# System message\n", + "sys_msg = SystemMessage(\n", + " content=\"You are a helpful assistant tasked with finding and explaining relevant information about movies.\"\n", + ")\n", + "\n", + "\n", + "# Node\n", + "def assistant(state: MessagesState):\n", + " return {\"messages\": [llm_with_tools.invoke([sys_msg] + state[\"messages\"])]}" + ] + }, + { + "cell_type": "markdown", + "id": "087e745b-6ce6-4f1f-9a52-a6de597971bf", + "metadata": {}, + "source": [ + "Next we define the LangGraph flow." ] }, { "cell_type": "code", "execution_count": 7, - "id": "6e959ac2-537d-4358-a43b-e3a47f68e1d6", + "id": "6763e87b-a6d2-44ed-9000-7440b51b325f", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAANYAAAD5CAIAAADUe1yaAAAAAXNSR0IArs4c6QAAIABJREFUeJztnWlcU8fex+ckIWSHJOwgm+yKKyqtuFWolaoXqCtaa1tvq7V6W9cutLWL1i5a6r19alute8UVFYuCe5W6YaUKqAXZRAiEBBISsuc8L+KH0hgQNefMCZnvxxdylvn/En7MmZkz8x8Mx3GAQMCDBlsAwtlBFkRABlkQARlkQQRkkAURkEEWRECGAVvA46CUG5QyQ5vSpG41GvWOMazEcMHoDIzDp3MEDLEvk8Whw1ZEFTDH+AUCAACQ3tPe+VNdWaLmChgmI84R0Ll8BpNNA47wCRiumKrZ2NZqalMa1QoT140e0pcbPoDHE7rAlgYZx7CgQmb4/XAT3QUTejFD+nA9/F1hK3pS7t3RVBar5RKduyfz6YlihovztogcwIKXjspuF7Y+PckjrD8Pthb78+dvLb/nyEakevR92g22FjhQ3YL7vq3tO1wQFSeALYRYLufJW+WGsTO8YQuBAHUtiOP4j+9WTHrdzzeEDVsLGZReUlaVqJNf8YUthGyoa8Hvl5fPzgjmChyyz/543LqiLP5dOfk/AbCFkApFLbgvs3Z4itg32Cnqv47cKFDI6nSjp3jBFkIeVOyIXcyVxY4QOKH/AACxw904fPrNy0rYQsiDchZsbtSXF6kiB/fw/kcXDBorPLNXClsFeVDOgr/nyJ6eKIatAiYMF9rgROGlozLYQkiCWhaUVGld2bTQ2B44/vdIDB0nklRpDXozbCFkQC0L3rmuEvkwSQtXXFys0+lg3d41LC69slhNUOGUgloWrCxRh/ThkhMrJydnzpw5Go0Gyu0PJaQvF1mQbJob9QIRQ+hNUi342BWYZRiLuPrPQmgsVyEzEBqCIlDIgoomA4ZhRJRcXV09b968hISE5OTk1atXm83mnJycNWvWAAASExPj4uJycnIAAEVFRW+++WZCQkJCQsLrr79+8+ZNy+0tLS1xcXHbt2/PyMhISEj497//bfN2+8JwoalajGqF0e4lUw0KvXtoU5o4AkJm0X366adVVVVLlixRq9WFhYU0Gm348OGzZs3asWNHZmYmj8cLDAwEANTV1el0urlz59JotL179y5atCgnJ4fFYlkK2bRp05QpUzZs2ECn0729vR+83e5wBQy10sh1o9DviAgo9PHUSiNBr+Pq6uqioqJSU1MBALNmzQIAiESigIAAAEDfvn3d3d0tl40fPz45Odny/5iYmHnz5hUVFcXHx1uOxMbGLliwoL3MB2+3O1w3ulphAr0IKp4qUMiCAOAMV0IexMnJyVu2bPnyyy/nzp0rEok6uwzDsNOnT+/YsaOyspLD4QAAZLK/B+eGDh1KhLYucGXRcTMVX5/aFwq1BdlcRquckKbPggULFi9enJ+fP2nSpD179nR22caNG5ctWxYTE7Nu3bq33noLAGA2/z0yx2aT/cKwpUnPcYJZGhSyIEdAb1OaiCgZw7D09PRDhw6NGjXqyy+/LCoqaj/VPktDp9Nt3rw5JSVlyZIlAwYMiI2N7U7JhE7yIK5xTCkoZEG+yMWFmAexZQCFy+XOmzcPAHDr1q32Wk0qvf82VqPR6HS66Ohoy48tLS1WtaAVVrcTAV/E4Lv3/FqQQp/Q09/1XrlG1WLk2ft7X7FiBY/Hi4+PP3/+PADA4rP+/fvT6fSvv/560qRJOp3uhRdeCAsLy8rKEovFKpXqxx9/pNFo5eXlnZX54O321VxVqnZh0jAaIX+TlIK+cuVK2Br+pkVqMGjNXoEs+xZbW1t7/vz5Y8eOaTSahQsXjh49GgAgEAi8vb2PHz9+7tw5pVI5YcKEQYMGFRQU7Nmzp7q6euHChUFBQfv37585c6bBYNi2bVtCQkJMTEx7mQ/ebl/N1063+IexvXrZ+augINSaslpzS11RrB492YkmbHZGzo91Y6Z68tx7/hJPCj2IAQCBUdxLR+WSaq1PkO2//paWlpSUFJunAgICamtrHzw+atSojz/+2N5KrZk7d67Np3Z0dHT7W5aODB48eO3atZ2VVvy7gufOcAb/Ua4WBADcK9dcOiZLe9P2+gmTydTQ0GDzFIbZ/ixsNlsoFNpbpjVSqdRgsPFKtzNVrq6uYnGn0yJ/fLfipQ+DXNk9vztMRQsCAE7vaQwfyAsI58AWAocbBQq91jx4LOF/NhSBQoMy7YyZ6nVsq0SjImSMkOLU3G6ruK5yHv9R1IIAgBnLA3/5oga2CrJpbTYc39Hwr/n+sIWQChUfxBZ0GtPONTUz3wl0kiZRQ7U2f0fDzHcDaU4wFtgR6lrQUivs+vLupNd9fXr6gs7bV5V//qaY+nZPnxVjC0pb0MLJXQ0atWn4RA/SJlSTSW1ZW0GOLCCMPXySB2wtcHAACwIAKovVBTlNobFc70BWSF9uD3hUadWmyhJ1faVW0WQYPlFs9xdCDoRjWNBC2bXWsmuqymJ19DABg4lxBQyuG92VRXeID0CnY2qlsU1pVCmMSrmxoVob0ocbMZgfGOmkY0/tOJIF26m6qVY0GtRKo1phMhrNZruO3hgMhtLS0v79+9uzUADYPDpuxjkCBs+NIfZl+vXu4a3b7uOQFiQUmUw2Y8aM/Px82EKcBYqOCyKcB2RBBGSQBa3BMCwiIgK2CicCWdAaHMf/+usv2CqcCGRBazAMc3Nz0uT3UEAWtAbHcYVCAVuFE4EsaANvb2fcfAEWyII26GxiNoIIkAWtwTCs40o5BNEgC1qD43hpaSlsFU4EsqA1GIaRnz7GmUEWtAbHceLS9yIeBFkQARlkQWtQd4RkkAWtQd0RkkEWREAGWdAaDMNISACCaAdZ0Bocx5ubm2GrcCKQBa1B8wVJBlnQGjRfkGSQBRGQQRa0Bk1ZJRlkQWvQlFWSQRZEQAZZEAEZZEEbtG+AgyABZEEb2MyRjyAIZEEEZJAFEZBBFrQGjQuSDLKgNWhckGSQBRGQQRa0BsOwoKAg2CqcCGRBa3Acr66uhq3CiUAWREAGWdAaDMPodKfY74kiIAtag+O4yeSMOzDCAlnQGrSOmGSQBa1B64hJBlnQGrR8iWTQ1jf3efXVVyUSCZ1ON5lMUqnU29sbwzCj0ZibmwtbWg8H1YL3mTp1amtra11dXUNDg9lsrq+vr6urwzCH32+R+iAL3mfcuHGhoaEdj+A4PnjwYHiKnAVkwb+ZMWMGh/P3vpg+Pj7p6elQFTkFyIJ/M27cuPa3w5YqMCoqCraong+y4D+YPXs2l8u1VIEzZsyALccpQBb8B0lJSUFBQTiODxw4EC1iIgcGbAE2MJvxFqlB2WQwwxgvSnn2ddB28LmRL1UUq8mPTqcDoRdTIHYhPzQsKDcueKtQWfK7sk1l8gvlqBVG2HLIhidk1NxSCz2ZQ8YJ/UKdIvE/tSx485Ky7E/1qCk+NJpTD8hpNab8rfeS0r28erFgayEcCrUFy4pUt/9QjZnm6+T+AwCw2PRJ8wKPbpG0SPWwtRAOhSx4/VzL8BS0/+DfPDXRqzC/5+d7pYoFNWqTvF7P4qC5on/j5sGsud0GWwXhUMWCrXKDd6BTtL67D4fPYHHoRr0ZthBioYoFAcDUrU7X/30oCpmhx0+VoI4FEU4KsiACMsiCCMggCyIggyyIgAyyIAIyyIIIyCALIiCDLIiADLIgAjLIggjIOLUFc48eSklLbGiQdHaByWS6caPoyQNJJPX1kronL6dH4tQWZDJduVwejdbpl/DV2k/XZa5+wij36mrTZ026fRulSrINFZcvkUbi2OcSxz7XxQV6ne7Jo5iMRkqtjqAaDmzBGzeKtu/YeKO4CAAQFdln3ry3IiOiAQBarTZz/Zrff/8NANCv38A331jq4+N78eL5Hzf+t66u1sfHb9LEyWmp09Z8uTIv7wgA4HjeRQaDYfOC02eOAwDGjI0DAPyy87Cvj9/RY4cPHtxTUVnOZnOGDnnqzQVL3d2FAIB9+385dTp/yuSZmzZ9J5M3hYdHLV2cERgYXC+pe+nlyQCAjz9552MAxo2b8M7ylbC/OWrhwBaUSOp0et2Ls+bSaLRDh/a+8+6iXTtzWCzWL7s25+UdeXnOPLHYIy//CJvNbmtrW/nJiuCg0CWLMyory2UyKQAgLXW62Ww+fjwXAGDzglnpr0gbG+rr7737zicAALHIAwBQWnojMDA4KSm5uVl+IDtL3ab+fFWmRc/Nm8V79mxfsiTDaDSuW7fq8y8++v67rWKRx/vvfbZqdcbLc+YNHBAnFIpgf22Uw4EtmJg4Pikp2fL/yMiYxUvm3SguGhIXXy+pY7PZ6TPmMBiM55NTLK0xnU43YsQzSYnj22+PCI8KDrqfx6i5Rf7gBQEBgW5u7vJmWWzsgPaDi99+r30OKYPB2LHzZ51O5+rqajmy6rNvRCIxACAtbfr/ff+NQqlwE7hFhEcBAAIDgzuWg2jHgS2IYdi586f37N1RXV1pSUfULJcBABLHjj958tiKdxYueGNJaGgYAMDP179Pn347dm5isdgTJ6QxmUyroh56QTsGg+FAdtbxE7mNjRJXV5bZbG5pafb29rGcZbHurz3w9vYFAMiapG4CtJfYQ3DgHvG27Rs//GhZZETMqk/XzXv9LQCAGTcDAIYNffrz1d/Km2Wv/nv612s/MxqNGIatWb1+3LMTNvyQOXtO2p9//mFV1EMvsIDj+Hvvv7Xzl5/HPzfpizX/S0pMbg9qhQvDBQBgMqO06Q/HUS1oMBh+2bX5+eSUNxcsiY0dEBMd2/HssKFPb/op6435b/+ae3BX1lYAAI/He+s/72zdsp/L5WV8sLitzXplWmcXdOzM/vnnH1f/uPyfRe9MfiE9JrpvaEgYKZ+1h+OoFtTr9TqdLiLifuYhhbIFAGA2my2nAAA0Gm3K5JkeHp5lZbcAADqdzvLATUudrlKrJA8MFNu8gMViy+UyS7HtUSxtO6ugXeDqyrI8lAn4GnoCjtoW5HK5oaFhB7KzRCKxWqXauu1HGo1WUVEOADiQnVXw+9mkxGSZTNrUJI2MjDEYDC+9/MLoUUkhwb0PHdrL4/L8/AI6ltbZBf37DTp67PC6b1bH9h3A5wtiomOZTOZPG//3/POpFRVlv+zaDACorCj3/2dpVnh5efv5+u/Zt4PFZiuVimlTX+xiMNwJceDv4oP3V7NZ7E8+fXf33u3z57/94qxX8/JyDAaDn1+AQa//fsM3v+YeTEubPm3qixqtZuCAISdOHs1cv4bh4rJ6VSaL9Y9cLZ1dkJSUnJoy9czZ4z9u/G9J6XVPT6+M91eVld9a+fHyq1cvrVv7Q3x8woHsrK51YhiWkbGaw+H+77uvj+XlWCppRDtUSWvUeFd3Mqtxwmu9YAuhFjs+u/Pa6lC6S09eSuzAtSCiZ4AsiIAMsiACMsiCCMggCyIggyyIgAyyIAIyyIIIyCALIiCDLIiADLIgAjLIggjIIAsiIEMVC9LomEDkqJMXicMzwJVG78nTZChkQQ8/ZmWJmiIzxyiCXKIz6MwYVX5FREGhzxc1hF9fqYGtgkI01GjCB/JgqyAcCllwzFSv8wcaNGq0AQ4AAFSVtFYVt8Yl9fyl71SZNW1BpzFtX1UzYIyI5+7i7sUEFJJGEjgA8nptq8xQc0s15e2AHr/1EuUsaKHwhLy2TIPjmKKTrVBNJpPBYLBa/2EvcBzXarVsNkkb4mk0GldX1/YFTR7+rgCAoCh2bII7OQLggzsgCxcuJK7wzMzMhISEw4cPExeiI42NjR9++CE5sagJFWvBLjh16tQzzzxDXPn19fULFy6sqqqKjo7evn07cYEeZNu2bWPHjvX39yczKBWgUHfkoUybNo3o39DevXurqqoAADU1NUeOHCE0lhXJycnz58/X2SOjoWPhGLWgRCJxc3O7d+9eWBiBOTTu3bu3aNGi6upqy4/kV4SWpuH169djYmL4fD7JoWHhALXg3r17L168yGazCfUfACA7O7vdfwCA6urqQ4cOERrxQdhsdnh4+MSJE1UqFcmhYeEAFqyurk5JSSE6Sl1d3enTpzseUavVO3fuJDrug4hEojNnzmi12sbGRvKjkw+lLXjhwgUAwNKlS0mIlZWVZakC29MUYRh29+5dEkLbxMPDg8fjxcfHl5eXw9JAErC75LbRarVDhgxpbW0lP7RMJps2bRr5cW2i1+u3bNkCWwWxULEWlMvl1dXVFy5c4PEgvCHFcVwul5Mf1yYuLi4vvfQSAGD58uVSac9MD0c5C27cuFEul0dERNDpdNhaKMTixYs/++wz2CoIgVoWLCsrMxgMRPd8uwbDsPb05dTBx8fn22+/BQDk5ubC1mJnKGRBiUQiFArnz58PVwaO41QeHw4JCXnuuedMpp6TxZoqFkxOThYKhR4eHrCFAAzDYmJiYKvoFMuAeWtra0NDA2wt9gG+BU0m09GjRzdv3kyRx5/JZKL4gJynp6e7u7tSqfz8889ha7EDkC1YVVXV0NAwfvx4b29vuEra0ev1DvFmIjw8PDw8/Pr167CFPCkwLdja2rpkyRI/Pz+IGh5Er9dHRkbCVtEtJk+eHBoaWl1dXVtbC1vL4wPTgmVlZfv374cowCYNDQ0ETYYlAh6PFxQUtGDBAoo3HroAjgUlEkl2dvagQYOgRO+asrIysVgMW8WjcejQobt372q1WthCHgcIFiwtLV22bFlqair5obuDTCbr168fbBWPzODBg00m0w8//ABbyCMDwYKRkZHkz8PrPtnZ2UOHDoWt4nHgcrkYhhUWFsIW8miQakGj0bht2zYqv3krLCwcMWIElHfTduG1115zc3OwvT9JteDUqVOfffZZMiM+KllZWWPHjoWt4okIDw//7bffoMx0fDwcY+I+OdTX169YsWLbtm2whdiBgoICjUaTmJgIW8jDIcmCtbW1KpUqKiqKhFiPzXvvvTdq1Khx48bBFuJckPEgNplMaWlpFPffrVu3tFptD/PfqlWrOq6GoSgkTIu9du1aVVUVCYGehJSUlOrqatgq7IxKpZo6dSpsFQ8BtQUBAGDXrl0AgBkzZsAW4owQ/iDevXs3xRv4V65cOXv2bA/23/79++vr62Gr6BTCLXjkyJG4uDiiozw2ZrP5448/3rBhA2whBBIcHLxy5UrYKjqF2AcxjuNqtZrKI73Tp0//9NNPw8PDYQshlhs3bvTq1cvdnYrZupy6LYhGYagAsQ/iS5cuLVq0iNAQj01WVlbfvn2dxH9Go3HKlCmwVdiGWAvSaDS93naaSrgcPHiwrKwsPT0dthCSYDAYIpGImjMYiH0Q6/V6pVJJhUVJHSkoKNi9e/f69ethCyEVk8mE4ziDQbmdNZyuLVhSUrJ27dqff/4ZthDEfQgflElJSZHJZERH6SaVlZUfffSRc/qvpKTklVdega3CBoRbcNCgQXfu3CE6SndobGxcv379vn37YAuBg1AobG5uhq3CBs7yIG5qapo5c2ZeXh5sIQhr4C9lJ4Gamprp06cj/1EzDQjhFpTJZBMnTiQ6ShdIpdKMjIwTJ05A1EAFdDodNaesE95FF4vFPj4+zc3NQqGQ6FgPIpVKZ82aheo/S66ctrY22CpsQFJb8F//+pdarVYqlV5eXqRtplBTU5OZmblu3TpywlEfjUZD2q5S3YfAWnDkyJGWPzscxy17qeE4TlrSqjt37ixdujQ7O5uccA4BBf1HbFvwmWeesWyt1r6XH51OHzZsGHER2ykuLv7pp5+Q/zpiMBio+ZqYQAuuXLkyJiam44Pey8urf//+xEW0UFRU9NVXX61Zs4boQI4FjuPUzH5EbI/4iy++CA4Otvwfx3E+n090Et9z584dOXJk69athEZxRJhMJslbmnUTYi3o7e399ttvW6YpYBhGdBWYl5e3f//+jIwMQqM4LtRM10T4uGBCQkJaWhqXy+XxeIQ2BA8ePHj27NnMzEziQjg0BoNhwoQJsFXYoFs9YqPBrFGZHzvGjCmvVN9pLCsrCw3s09psfOxyuuD06dMlNypWr15NROE9A8uuPrBV2OAh44I3Lyuvn1PIJXo274lyEbWPyxCEXq/38ufV3WkL7ccbkiQU+1EibTUVWLZs2cmTJ9sHxSwtIhzH//jjD9jS7tNVLXg5X95UZxiR5sMXuZAo6fExm/AWqT53iyQx3ds32GEypRLK/PnzS0tLLen522uB9j4iFei0LXjpmFwhNY5I9XYU/wEAaHRM5OOasiDo5K7GhhqHTDlqd0JDQwcPHtzxWYdh2MiRI6GK+ge2LdjcqG+6p4uf4EW6HvvwzAzfwnwqzo2DwuzZsztuaBAQEDB9+nSoiv6BbQs23dPhOIFNN6LhC13ulrXpdY/fhepJhIWFteeNxXF8xIgR1Nlio1MLqhQmz16O3ZYKiuHK66m7jxfJvPjii15eXgAAf3//mTNnwpbzD2xb0KAzG7SOXYUoZUYAHLgity+9e/ceNmwYjuOjRo2iVBVIxnxBxGNgNuM1t9pUzUa10mg04Bq1HWY79/ebpR0YHikafmKXHTavY7HpTDaNI6ALhC6BUZwnKQpZkFrcvKy8fVVVW9bmFyEw6nG6C53mwgCYPQYlaKyhTz1vMAODPeattqpwk8FoMhpcXHSHf6gLiuFGDORFxvEfoyhkQapQekl5/lCTZyCfweX3TaLWs7JrhEGi1sa2kqvaghzZiBRx+MBHMyKyIHw0KlPu5gaDiRY6LIDBpO6OGJ2BYZjAmwsAl+cpKDwlv3lF9fyrPnR6dxviTrGCjsrU3FZvW1XN8xf5RHo6ov86wmQzfGO8mEL3DcvvNN7t7qsBZEGYNNzVnj0gjxwZ5Mp2mFdQD4XFY/ZJDMnd3KCUdSujFbIgNCpLVPk7pL0GUGsvXHsRPCTgwP9JJNUPrwuRBeGgajGe3NVj/WchOM7/wH/vGQ0PGWBGFoTDsW0NwUP9YasgnN7xfr/+/JBhSGRBCBQebzYBJsPFsTsf3cGVy1SrsZILii6uQRaEwMVcmVcYhNwSUPAKFRXkyLu4wJ4WLL1ZrNM90cyAM2dPjBkbV1NTZT9RlOPqCbl/jIjQOeSPzSdfTth3yM6LXxmudHEgv/j3TitCu1nwWF7OgjfnaLUaexXYU7l5RcVyc+xZSI+KK491q1DV2Vm7WfAJ6z8nQSk3aNVmNt+5lrbwxGzpXa2hk+mb9nlBdywvJ/PbNQCAlLREAMCK5R89N24iACA//9eduzbX1dWKxR7PJ6fOTH/ZkuLDaDRu3rIhL/+IQtESFBQy56XXE4aPfrDYixfP/7jxv3V1tT4+fpMmTk5LnWYXtRC5e7tNGEDURkDlFVdzj/9fneQvPk8UFhI3Pmm+gO8BAMhYNfaFiSuKb54pvV3AZvHih6Q+O2au5RaTyXTizKaLhQf1ek3v0MEGA1GrHTyC+dU328IG2Pjs9qkFhw0dPnXKLADA56sy12duHDZ0OAAgL+/I5198FB4e9UHG6tGjkn7e/P3OXzZbrv967We792yf8Hzq++995uPj98GHS69fv2ZVZltb28pPVjBdmEsWZzz91EiZTGoXqXBpqjfgOCFdwLI7V37atsjbK2Rqyvsjn06vqLq2YfMCvf6+pbIOfOznE/HGqxsG9R+ff+qn0tsFluPZR746fmZTVMTTqROWMl1YGm0rEdoAACYT1iy1/bLEPrWgUCjy8wsAAERH93Vzc7dMEN/483exsQMy3vsMADByxDOtrcqs3VtfSJvR1NSYl39k9otz57z0OgBg1Mixs2anbtn6w7q1/9gIrrlFrtPpRox4JilxvF1EUgG1wshwJSS91cFf18bHpaZOWGr5MSJs2Ffrp90uvxgbMxoAMHTQpLGj5gAA/HwiLl899Ff5xZjI4bV1ty4WZo8d9fL4xHkAgLiBz9+pJGplp4srQ9XJEnKiZsrU1tY0NUmnTX2x/ciQIU/lHj1Ue6/m9u1SAEBCwhjLcQzDhsTFHz+Ra1WCn69/nz79duzcxGKxJ05IYzKZBEklE43K5Cq0/3CgvLm+QVrZJL97sfBgx+MtivvDwkzmfd/T6XQ3gZdCKQUA3Cg9AwAY+fTfW5BiGFGDdAxXWpuSXAuq1CoAgLu7qP0Iny8AADRJG9VqFQBA2OGUQODW1tamVqs7loBh2JrV6zdu+t+GHzL37tvx7opP+vcfRJBa0iAon2irSgYASBozt1/MmI7H+Xwbmw7RaAyz2QQAaGmRsFg8LseNEE1W4Ji5k89uZ9e3r1f18vQGACgULe2nmpvlFiN6eHgBAJTKvweK5HIZg8FgsayHKng83lv/eWfrlv1cLi/jg8XUzFP7SHDd6Ead/XOOs1l8AIDBoPPyDO74j83qquvD5Qq1WpXBSMYObUadkS+0Xd/ZzYJsFhsA0NR0v9MgFnv4ePtevlzQfsHZsydYLFZYWGR0dF8Mwy5eOm85rtfrL14636dPPzqdznRhdnSnZaDHz9c/LXW6Sq2SSOrspRYWfDeGUW9/C3p6BLq7+Vz5I0envz8uazIZjUZD13cF+EcBAK5dJyMRt1Fv4rvbtiDd5mbJ9+5oTEbgE/wIDWcWm3Po8N6q6goMYKU3b0RGxvB5gt17d0ilDQaD4UB21omTR2emvzIkLl7AF0gk9dkHdwOANTVJv//+m8qqO8uWfujr689wcck+uPvW7ZLAwGAPsefsOWlNTVKZrCn74G69TvfqK290fwu1smvK4GgOr5OPDQuVwiCTGNnudu6RYBgmdPe9fPVw6a1zOMCr797IPrLWZNIH9YoFAJw6ty3ALyoy7H5as4tXDrJY3IH9nvXyCLlecvLqtVyNVqVSN1+4kn2nsjDALzomKsG+8gAAWoU6JIYl8rbRoLebBQV8gaen95kzxy9cONfaqhw3bkJYWIRQKDp1Ov/oscMtzfL09JdnzXzF8mJqSNxTarXq6LFDp07lcTncpUsyhgx5CgDA5/F9ffz+uHaFhtGiY2Jra2vOF5w+d/6UWOz5zvKV/v7App5YAAADXUlEQVQB3ddDTQtyBIzLvzaJg+zf/PL2DA7wj6moKrpalFtTW+LrGzZ4wHjLuGBnFqTRaNERCdKm6uslJyuqiny8QuXNdd6eIURYsPJqQ+JMbxrNxmtJ25m1LufJ9VrQf7TowVOOQu6m2lFpHj7US270y5d33QPFHDcnekHS2tRmVLamLrA9OZJalYQzEBPPKy/RdGHBv8ovb9v97oPH2Sx+Z0PHE8YtjI9LsZfCm7cLdu778MHjOI4DgNscuJn38ncBflGdFahT6foM5XZ2FlmQbAaMFF44ckcYIKAzbPcFgwP7LX5j+4PHcRx0Nr2Gw7bnk713yGCbAsxmM47jdLqNcU0B37Oz0vQag1Kiih7SaTo5ZEEIDJ8oLr0q94m0vVM4k8kSMWFO6LevgKaK5hEpXeW4RlNWIdBvhDubZdJpHjJo0gPQturcxVjXi9uRBeEw/mWfiov3YKsgFrMZr7hcl/yyT9eXIQvCgelKS5nvV3m5J7uw4mLtjOWBD70MWRAaviHstDd9Ki9TcUekJ8RkNJcV1KSvCBB6PXxyCbIgTNzEzIlzfYrzKzXKnpMZW92sLTtfM21xAIfXrc4usiBkPPxdF6zrbVYp7xU36NRkzBggDo1Sd/fPehezat4XvQXdzpKPBmXgg2HY86/6Vharf8tu5LizGBxXgSeH7jirjI06k1KqNun0BrVudJpHr4hHy3iJLEgVQvpyQ/py79xQlV1TlxfIRQEcg85MZzIYrgwKZizGcdykM5oMRhcmrVmiCenLDR/OC455nLSIyILUoncsr3csDwBQX6lRK0xqhVGvM2vtkejXvrhyaCwOkyPg8IV078CHDLt0DbIgRfENoeIO6kRg24JMFmamXuX/SLh5uhC2EAJhT2z/lvhCF2m1Y+dFqLyuEvv2hBVPPR7bFvTq5UrJnCfdpUWqD+7DYbigatAB6LQW9A9j/bZfQroe+3ByZ118MhV3IEc8SFf7EZdcUJQVqfqPEgu9mZ1NbqMUGpVR0WT4bZ/khYX+7t14NYSgAg/ZEruyRF10tkVSqaUzqP5gFvm6KqT60L6coePFXAHq6TsMD7FgOzoN1bekw3HA4jhAVY2worsWRCAIAlUbCMggCyIggyyIgAyyIAIyyIIIyCALIiDz/x8c2UhUcKGwAAAAAElFTkSuQmCC", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], "source": [ - "from typing import List, Tuple\n", + "from IPython.display import Image, display\n", + "from langgraph.graph import END, START, StateGraph\n", + "from langgraph.prebuilt import ToolNode, tools_condition\n", "\n", - "from langchain.agents import AgentExecutor\n", - "from langchain.agents.format_scratchpad import format_to_openai_function_messages\n", - "from langchain.agents.output_parsers import OpenAIFunctionsAgentOutputParser\n", - "from langchain_core.messages import AIMessage, HumanMessage\n", - "from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder\n", - "from langchain_core.utils.function_calling import convert_to_openai_function\n", - "from langchain_openai import ChatOpenAI\n", + "# Graph\n", + "builder = StateGraph(MessagesState)\n", "\n", - "llm = ChatOpenAI(model=\"gpt-3.5-turbo\", temperature=0)\n", - "tools = [InformationTool()]\n", + "# Define nodes: these do the work\n", + "builder.add_node(\"assistant\", assistant)\n", + "builder.add_node(\"tools\", ToolNode(tools))\n", "\n", - "llm_with_tools = llm.bind(functions=[convert_to_openai_function(t) for t in tools])\n", - "\n", - "prompt = ChatPromptTemplate.from_messages(\n", - " [\n", - " (\n", - " \"system\",\n", - " \"You are a helpful assistant that finds information about movies \"\n", - " \" and recommends them. If tools require follow up questions, \"\n", - " \"make sure to ask the user for clarification. Make sure to include any \"\n", - " \"available options that need to be clarified in the follow up questions \"\n", - " \"Do only the things the user specifically requested. \",\n", - " ),\n", - " MessagesPlaceholder(variable_name=\"chat_history\"),\n", - " (\"user\", \"{input}\"),\n", - " MessagesPlaceholder(variable_name=\"agent_scratchpad\"),\n", - " ]\n", + "# Define edges: these determine how the control flow moves\n", + "builder.add_edge(START, \"assistant\")\n", + "builder.add_conditional_edges(\n", + " \"assistant\",\n", + " # If the latest message (result) from assistant is a tool call -> tools_condition routes to tools\n", + " # If the latest message (result) from assistant is a not a tool call -> tools_condition routes to END\n", + " tools_condition,\n", ")\n", + "builder.add_edge(\"tools\", \"assistant\")\n", + "react_graph = builder.compile()\n", "\n", - "\n", - "def _format_chat_history(chat_history: List[Tuple[str, str]]):\n", - " buffer = []\n", - " for human, ai in chat_history:\n", - " buffer.append(HumanMessage(content=human))\n", - " buffer.append(AIMessage(content=ai))\n", - " return buffer\n", - "\n", - "\n", - "agent = (\n", - " {\n", - " \"input\": lambda x: x[\"input\"],\n", - " \"chat_history\": lambda x: _format_chat_history(x[\"chat_history\"])\n", - " if x.get(\"chat_history\")\n", - " else [],\n", - " \"agent_scratchpad\": lambda x: format_to_openai_function_messages(\n", - " x[\"intermediate_steps\"]\n", - " ),\n", - " }\n", - " | prompt\n", - " | llm_with_tools\n", - " | OpenAIFunctionsAgentOutputParser()\n", - ")\n", - "\n", - "agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)" + "# Show\n", + "display(Image(react_graph.get_graph(xray=True).draw_mermaid_png()))" + ] + }, + { + "cell_type": "markdown", + "id": "c038c048-5a1a-4d6a-a904-387a85e3e549", + "metadata": {}, + "source": [ + "Let's test the workflow now with an example question." ] }, { @@ -350,42 +352,48 @@ "name": "stdout", "output_type": "stream", "text": [ + "================================\u001b[1m Human Message \u001b[0m=================================\n", "\n", + "Who played in the Casino?\n", + "==================================\u001b[1m Ai Message \u001b[0m==================================\n", + "Tool Calls:\n", + " Information (call_j4usgFStGtBM16fuguRaeoGc)\n", + " Call ID: call_j4usgFStGtBM16fuguRaeoGc\n", + " Args:\n", + " entity: Casino\n", + "=================================\u001b[1m Tool Message \u001b[0m=================================\n", + "Name: Information\n", "\n", - "\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n", - "\u001b[32;1m\u001b[1;3m\n", - "Invoking: `Information` with `{'entity': 'Casino'}`\n", - "\n", - "\n", - "\u001b[0m\u001b[36;1m\u001b[1;3mtype:Movie\n", + "type:Movie\n", "title: Casino\n", "year: 1995-11-22\n", - "ACTED_IN: Joe Pesci, Robert De Niro, Sharon Stone, James Woods\n", - "\u001b[0m\u001b[32;1m\u001b[1;3mThe movie \"Casino\" starred Joe Pesci, Robert De Niro, Sharon Stone, and James Woods.\u001b[0m\n", + "ACTED_IN: Robert De Niro, Joe Pesci, Sharon Stone, James Woods\n", + "IN_GENRE: Drama, Crime\n", "\n", - "\u001b[1m> Finished chain.\u001b[0m\n" + "==================================\u001b[1m Ai Message \u001b[0m==================================\n", + "\n", + "The movie \"Casino,\" released in 1995, features the following actors:\n", + "\n", + "- Robert De Niro\n", + "- Joe Pesci\n", + "- Sharon Stone\n", + "- James Woods\n", + "\n", + "The film is in the Drama and Crime genres.\n" ] - }, - { - "data": { - "text/plain": [ - "{'input': 'Who played in Casino?',\n", - " 'output': 'The movie \"Casino\" starred Joe Pesci, Robert De Niro, Sharon Stone, and James Woods.'}" - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" } ], "source": [ - "agent_executor.invoke({\"input\": \"Who played in Casino?\"})" + "input_messages = [HumanMessage(content=\"Who played in the Casino?\")]\n", + "messages = react_graph.invoke({\"messages\": input_messages})\n", + "for m in messages[\"messages\"]:\n", + " m.pretty_print()" ] }, { "cell_type": "code", "execution_count": null, - "id": "c2759973-de8a-4624-8930-c90a21d6caa3", + "id": "a9fe9d6b-2eb6-47e5-a085-ca35dc5e3654", "metadata": {}, "outputs": [], "source": [] @@ -407,7 +415,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.1" + "version": "3.11.5" } }, "nbformat": 4, diff --git a/docs/docs/how_to/installation.mdx b/docs/docs/how_to/installation.mdx index f56946f921a..081fe32fd85 100644 --- a/docs/docs/how_to/installation.mdx +++ b/docs/docs/how_to/installation.mdx @@ -51,7 +51,7 @@ pip install langchain-core Certain integrations like OpenAI and Anthropic have their own packages. Any integrations that require their own package will be documented as such in the [Integration docs](/docs/integrations/providers/). -You can see a list of all integration packages in the [API reference](https://api.python.langchain.com) under the "Partner libs" dropdown. +You can see a list of all integration packages in the [API reference](https://python.langchain.com/api_reference/) under the "Partner libs" dropdown. To install one of these run: ```bash diff --git a/docs/docs/integrations/chat/cerebras.ipynb b/docs/docs/integrations/chat/cerebras.ipynb index 76c0fb8e172..e6ad0cf8938 100644 --- a/docs/docs/integrations/chat/cerebras.ipynb +++ b/docs/docs/integrations/chat/cerebras.ipynb @@ -17,7 +17,7 @@ "source": [ "# ChatCerebras\n", "\n", - "This notebook provides a quick overview for getting started with Cerebras [chat models](/docs/concepts/chat_models). For detailed documentation of all ChatCerebras features and configurations head to the [API reference](https://api.python.langchain.com/en/latest/chat_models/langchain_cerebras.chat_models.ChatCerebras.html).\n", + "This notebook provides a quick overview for getting started with Cerebras [chat models](/docs/concepts/chat_models). For detailed documentation of all ChatCerebras features and configurations head to the [API reference](https://python.langchain.com/api_reference/cerebras/chat_models/langchain_cerebras.chat_models.ChatCerebras.html#).\n", "\n", "At Cerebras, we've developed the world's largest and fastest AI processor, the Wafer-Scale Engine-3 (WSE-3). The Cerebras CS-3 system, powered by the WSE-3, represents a new class of AI supercomputer that sets the standard for generative AI training and inference with unparalleled performance and scalability.\n", "\n", @@ -37,7 +37,7 @@ "\n", "| Class | Package | Local | Serializable | [JS support](https://js.langchain.com/docs/integrations/chat/cerebras) | Package downloads | Package latest |\n", "| :--- | :--- | :---: | :---: | :---: | :---: | :---: |\n", - "| [ChatCerebras](https://api.python.langchain.com/en/latest/chat_models/langchain_cerebras.chat_models.ChatCerebras.html) | [langchain-cerebras](https://api.python.langchain.com/en/latest/cerebras_api_reference.html) | ❌ | beta | ❌ | ![PyPI - Downloads](https://img.shields.io/pypi/dm/langchain-cerebras?style=flat-square&label=%20) | ![PyPI - Version](https://img.shields.io/pypi/v/langchain-cerebras?style=flat-square&label=%20) |\n", + "| [ChatCerebras](https://python.langchain.com/api_reference/cerebras/chat_models/langchain_cerebras.chat_models.ChatCerebras.html#) | [langchain-cerebras](https://python.langchain.com/api_reference/cerebras/index.html) | ❌ | beta | ❌ | ![PyPI - Downloads](https://img.shields.io/pypi/dm/langchain-cerebras?style=flat-square&label=%20) | ![PyPI - Version](https://img.shields.io/pypi/v/langchain-cerebras?style=flat-square&label=%20) |\n", "\n", "### Model features\n", "| [Tool calling](/docs/how_to/tool_calling/) | [Structured output](/docs/how_to/structured_output/) | JSON mode | [Image input](/docs/how_to/multimodal_inputs/) | Audio input | Video input | [Token-level streaming](/docs/how_to/chat_streaming/) | Native async | [Token usage](/docs/how_to/chat_token_usage_tracking/) | [Logprobs](/docs/how_to/logprobs/) |\n", @@ -396,7 +396,7 @@ "source": [ "## API reference\n", "\n", - "For detailed documentation of all ChatCerebras features and configurations head to the API reference: https://api.python.langchain.com/en/latest/chat_models/langchain_cerebras.chat_models.ChatCerebras.html" + "For detailed documentation of all ChatCerebras features and configurations head to the API reference: https://python.langchain.com/api_reference/cerebras/chat_models/langchain_cerebras.chat_models.ChatCerebras.html#" ] } ], diff --git a/docs/docs/integrations/chat/oci_data_science.ipynb b/docs/docs/integrations/chat/oci_data_science.ipynb index b5a8f040d90..6196d2025c0 100644 --- a/docs/docs/integrations/chat/oci_data_science.ipynb +++ b/docs/docs/integrations/chat/oci_data_science.ipynb @@ -19,7 +19,7 @@ "source": [ "# ChatOCIModelDeployment\n", "\n", - "This will help you getting started with OCIModelDeployment [chat models](/docs/concepts/chat_models). For detailed documentation of all ChatOCIModelDeployment features and configurations head to the [API reference](https://api.python.langchain.com/en/latest/chat_models/langchain_community.chat_models.ChatOCIModelDeployment.html).\n", + "This will help you getting started with OCIModelDeployment [chat models](/docs/concepts/chat_models). For detailed documentation of all ChatOCIModelDeployment features and configurations head to the [API reference](https://python.langchain.com/api_reference/community/chat_models/langchain_community.chat_models.oci_data_science.ChatOCIModelDeployment.html).\n", "\n", "[OCI Data Science](https://docs.oracle.com/en-us/iaas/data-science/using/home.htm) is a fully managed and serverless platform for data science teams to build, train, and manage machine learning models in the Oracle Cloud Infrastructure. You can use [AI Quick Actions](https://blogs.oracle.com/ai-and-datascience/post/ai-quick-actions-in-oci-data-science) to easily deploy LLMs on [OCI Data Science Model Deployment Service](https://docs.oracle.com/en-us/iaas/data-science/using/model-dep-about.htm). You may choose to deploy the model with popular inference frameworks such as vLLM or TGI. By default, the model deployment endpoint mimics the OpenAI API protocol.\n", "\n", @@ -30,7 +30,7 @@ "\n", "| Class | Package | Local | Serializable | JS support | Package downloads | Package latest |\n", "| :--- | :--- | :---: | :---: | :---: | :---: | :---: |\n", - "| [ChatOCIModelDeployment](https://api.python.langchain.com/en/latest/chat_models/langchain_community.chat_models.ChatOCIModelDeployment.html) | [langchain-community](https://api.python.langchain.com/en/latest/community_api_reference.html) | ❌ | beta | ❌ | ![PyPI - Downloads](https://img.shields.io/pypi/dm/langchain-community?style=flat-square&label=%20) | ![PyPI - Version](https://img.shields.io/pypi/v/langchain-community?style=flat-square&label=%20) |\n", + "| [ChatOCIModelDeployment](https://python.langchain.com/api_reference/community/chat_models/langchain_community.chat_models.oci_data_science.ChatOCIModelDeployment.html) | [langchain-community](https://python.langchain.com/api_reference/community/index.html) | ❌ | beta | ❌ | ![PyPI - Downloads](https://img.shields.io/pypi/dm/langchain-community?style=flat-square&label=%20) | ![PyPI - Version](https://img.shields.io/pypi/v/langchain-community?style=flat-square&label=%20) |\n", "\n", "### Model features\n", "\n", @@ -430,9 +430,9 @@ "\n", "For comprehensive details on all features and configurations, please refer to the API reference documentation for each class:\n", "\n", - "* [ChatOCIModelDeployment](https://api.python.langchain.com/en/latest/chat_models/langchain_community.chat_models.oci_data_science.ChatOCIModelDeployment.html)\n", - "* [ChatOCIModelDeploymentVLLM](https://api.python.langchain.com/en/latest/chat_models/langchain_community.chat_models.oci_data_science.ChatOCIModelDeploymentVLLM.html)\n", - "* [ChatOCIModelDeploymentTGI](https://api.python.langchain.com/en/latest/chat_models/langchain_community.chat_models.oci_data_science.ChatOCIModelDeploymentTGI.html)" + "* [ChatOCIModelDeployment](https://python.langchain.com/api_reference/community/chat_models/langchain_community.chat_models.oci_data_science.ChatOCIModelDeployment.html)\n", + "* [ChatOCIModelDeploymentVLLM](https://python.langchain.com/api_reference/community/chat_models/langchain_community.chat_models.oci_data_science.ChatOCIModelDeploymentVLLM.html)\n", + "* [ChatOCIModelDeploymentTGI](https://python.langchain.com/api_reference/community/chat_models/langchain_community.chat_models.oci_data_science.ChatOCIModelDeploymentTGI.html)" ] } ], diff --git a/docs/docs/integrations/chat/outlines.ipynb b/docs/docs/integrations/chat/outlines.ipynb index 1d53def18b9..001ecf1d2b4 100644 --- a/docs/docs/integrations/chat/outlines.ipynb +++ b/docs/docs/integrations/chat/outlines.ipynb @@ -17,7 +17,7 @@ "source": [ "# ChatOutlines\n", "\n", - "This will help you getting started with Outlines [chat models](/docs/concepts/chat_models/). For detailed documentation of all ChatOutlines features and configurations head to the [API reference](https://api.python.langchain.com/en/latest/chat_models/outlines.chat_models.ChatOutlines.html).\n", + "This will help you getting started with Outlines [chat models](/docs/concepts/chat_models/). For detailed documentation of all ChatOutlines features and configurations head to the [API reference](https://python.langchain.com/api_reference/community/chat_models/langchain_community.chat_models.outlines.ChatOutlines.html).\n", "\n", "[Outlines](https://github.com/outlines-dev/outlines) is a library for constrained language generation. It allows you to use large language models (LLMs) with various backends while applying constraints to the generated output.\n", "\n", @@ -26,7 +26,7 @@ "\n", "| Class | Package | Local | Serializable | JS support | Package downloads | Package latest |\n", "| :--- | :--- | :---: | :---: | :---: | :---: | :---: |\n", - "| [ChatOutlines](https://api.python.langchain.com/en/latest/chat_models/outlines.chat_models.ChatOutlines.html) | [langchain-community](https://api.python.langchain.com/en/latest/community_api_reference.html) | ✅ | ❌ | ❌ | ![PyPI - Downloads](https://img.shields.io/pypi/dm/langchain-community?style=flat-square&label=%20) | ![PyPI - Version](https://img.shields.io/pypi/v/langchain-community?style=flat-square&label=%20) |\n", + "| [ChatOutlines](https://python.langchain.com/api_reference/community/chat_models/langchain_community.chat_models.outlines.ChatOutlines.html) | [langchain-community](https://python.langchain.com/api_reference/community/index.html) | ✅ | ❌ | ❌ | ![PyPI - Downloads](https://img.shields.io/pypi/dm/langchain-community?style=flat-square&label=%20) | ![PyPI - Version](https://img.shields.io/pypi/v/langchain-community?style=flat-square&label=%20) |\n", "\n", "### Model features\n", "| [Tool calling](/docs/how_to/tool_calling) | [Structured output](/docs/how_to/structured_output/) | JSON mode | [Image input](/docs/how_to/multimodal_inputs/) | Audio input | Video input | [Token-level streaming](/docs/how_to/chat_streaming/) | Native async | [Token usage](/docs/how_to/chat_token_usage_tracking/) | [Logprobs](/docs/how_to/logprobs/) |\n", @@ -316,7 +316,7 @@ "source": [ "## API reference\n", "\n", - "For detailed documentation of all ChatOutlines features and configurations head to the API reference: https://api.python.langchain.com/en/latest/chat_models/outlines.chat_models.ChatOutlines.html\n", + "For detailed documentation of all ChatOutlines features and configurations head to the API reference: https://python.langchain.com/api_reference/community/chat_models/langchain_community.chat_models.outlines.ChatOutlines.html\n", "\n", "## Full Outlines Documentation: \n", "\n", diff --git a/docs/docs/integrations/chat/sambastudio.ipynb b/docs/docs/integrations/chat/sambastudio.ipynb index 64dd05fd96b..1ad3ff28050 100644 --- a/docs/docs/integrations/chat/sambastudio.ipynb +++ b/docs/docs/integrations/chat/sambastudio.ipynb @@ -19,7 +19,7 @@ "source": [ "# ChatSambaStudio\n", "\n", - "This will help you getting started with SambaStudio [chat models](/docs/concepts/chat_models). For detailed documentation of all ChatStudio features and configurations head to the [API reference](https://api.python.langchain.com/en/latest/chat_models/langchain_community.chat_models.sambanova.ChatSambaStudio.html).\n", + "This will help you getting started with SambaStudio [chat models](/docs/concepts/chat_models). For detailed documentation of all ChatStudio features and configurations head to the [API reference](https://python.langchain.com/api_reference/community/chat_models/langchain_community.chat_models.sambanova.ChatSambaStudio.html).\n", "\n", "**[SambaNova](https://sambanova.ai/)'s** [SambaStudio](https://docs.sambanova.ai/sambastudio/latest/sambastudio-intro.html) SambaStudio is a rich, GUI-based platform that provides the functionality to train, deploy, and manage models in SambaNova [DataScale](https://sambanova.ai/products/datascale) systems.\n", "\n", @@ -28,7 +28,7 @@ "\n", "| Class | Package | Local | Serializable | JS support | Package downloads | Package latest |\n", "| :--- | :--- | :---: | :---: | :---: | :---: | :---: |\n", - "| [ChatSambaStudio](https://api.python.langchain.com/en/latest/chat_models/langchain_community.chat_models.sambanova.ChatSambaStudio.html) | [langchain-community](https://python.langchain.com/api_reference/community/index.html) | ❌ | ❌ | ❌ | ![PyPI - Downloads](https://img.shields.io/pypi/dm/langchain_community?style=flat-square&label=%20) | ![PyPI - Version](https://img.shields.io/pypi/v/langchain_community?style=flat-square&label=%20) |\n", + "| [ChatSambaStudio](https://python.langchain.com/api_reference/community/chat_models/langchain_community.chat_models.sambanova.ChatSambaStudio.html) | [langchain-community](https://python.langchain.com/api_reference/community/index.html) | ❌ | ❌ | ❌ | ![PyPI - Downloads](https://img.shields.io/pypi/dm/langchain_community?style=flat-square&label=%20) | ![PyPI - Version](https://img.shields.io/pypi/v/langchain_community?style=flat-square&label=%20) |\n", "\n", "### Model features\n", "\n", @@ -355,7 +355,7 @@ "source": [ "## API reference\n", "\n", - "For detailed documentation of all ChatSambaStudio features and configurations head to the API reference: https://api.python.langchain.com/en/latest/chat_models/langchain_community.chat_models.sambanova.ChatSambaStudio.html" + "For detailed documentation of all ChatSambaStudio features and configurations head to the API reference: https://python.langchain.com/api_reference/community/chat_models/langchain_community.chat_models.sambanova.ChatSambaStudio.html" ] } ], diff --git a/docs/docs/integrations/document_loaders/needle.ipynb b/docs/docs/integrations/document_loaders/needle.ipynb new file mode 100644 index 00000000000..1ea13845611 --- /dev/null +++ b/docs/docs/integrations/document_loaders/needle.ipynb @@ -0,0 +1,253 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Needle Document Loader\n", + "[Needle](https://needle-ai.com) makes it easy to create your RAG pipelines with minimal effort. \n", + "\n", + "For more details, refer to our [API documentation](https://docs.needle-ai.com/docs/api-reference/needle-api)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Overview\n", + "The Needle Document Loader is a utility for integrating Needle collections with LangChain. It enables seamless storage, retrieval, and utilization of documents for Retrieval-Augmented Generation (RAG) workflows.\n", + "\n", + "This example demonstrates:\n", + "\n", + "* Storing documents into a Needle collection.\n", + "* Setting up a retriever to fetch documents.\n", + "* Building a Retrieval-Augmented Generation (RAG) pipeline." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Setup\n", + "Before starting, ensure you have the following environment variables set:\n", + "\n", + "* NEEDLE_API_KEY: Your API key for authenticating with Needle.\n", + "* OPENAI_API_KEY: Your OpenAI API key for language model operations." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "import os" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "os.environ[\"NEEDLE_API_KEY\"] = \"\"" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "os.environ[\"OPENAI_API_KEY\"] = \"\"" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Initialization\n", + "To initialize the NeedleLoader, you need the following parameters:\n", + "\n", + "* needle_api_key: Your Needle API key (or set it as an environment variable).\n", + "* collection_id: The ID of the Needle collection to work with." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Instantiation" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from langchain_community.document_loaders.needle import NeedleLoader\n", + "\n", + "collection_id = \"clt_01J87M9T6B71DHZTHNXYZQRG5H\"\n", + "\n", + "# Initialize NeedleLoader to store documents to the collection\n", + "document_loader = NeedleLoader(\n", + " needle_api_key=os.getenv(\"NEEDLE_API_KEY\"),\n", + " collection_id=collection_id,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Load\n", + "To add files to the Needle collection:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "files = {\n", + " \"tech-radar-30.pdf\": \"https://www.thoughtworks.com/content/dam/thoughtworks/documents/radar/2024/04/tr_technology_radar_vol_30_en.pdf\"\n", + "}\n", + "\n", + "document_loader.add_files(files=files)" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [], + "source": [ + "# Show the documents in the collection\n", + "# collections_documents = document_loader.load()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Lazy Load\n", + "The lazy_load method allows you to iteratively load documents from the Needle collection, yielding each document as it is fetched:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Show the documents in the collection\n", + "# collections_documents = document_loader.lazy_load()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Usage\n", + "### Use within a chain\n", + "Below is a complete example of setting up a RAG pipeline with Needle within a chain:" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'input': 'Did RAG move to accepted?',\n", + " 'context': [Document(metadata={}, page_content='New Moved in/out No change\\n\\n© Thoughtworks, Inc. All Rights Reserved. 12\\n\\nTechniques\\n\\n1. Retrieval-augmented generation (RAG)\\nAdopt\\n\\nRetrieval-augmented generation (RAG) is the preferred pattern for our teams to improve the quality of \\nresponses generated by a large language model (LLM). We’ve successfully used it in several projects, \\nincluding the popular Jugalbandi AI Platform. With RAG, information about relevant and trustworthy \\ndocuments — in formats like HTML and PDF — are stored in databases that supports a vector data \\ntype or efficient document search, such as pgvector, Qdrant or Elasticsearch Relevance Engine. For \\na given prompt, the database is queried to retrieve relevant documents, which are then combined \\nwith the prompt to provide richer context to the LLM. This results in higher quality output and greatly \\nreduced hallucinations. The context window — which determines the maximum size of the LLM input \\n— is limited, which means that selecting the most relevant documents is crucial. We improve the \\nrelevancy of the content that is added to the prompt by reranking. Similarly, the documents are usually \\ntoo large to calculate an embedding, which means they must be split into smaller chunks. This is often \\na difficult problem, and one approach is to have the chunks overlap to a certain extent.'),\n", + " Document(metadata={}, page_content='New Moved in/out No change\\n\\n© Thoughtworks, Inc. All Rights Reserved. 12\\n\\nTechniques\\n\\n1. Retrieval-augmented generation (RAG)\\nAdopt\\n\\nRetrieval-augmented generation (RAG) is the preferred pattern for our teams to improve the quality of \\nresponses generated by a large language model (LLM). We’ve successfully used it in several projects, \\nincluding the popular Jugalbandi AI Platform. With RAG, information about relevant and trustworthy \\ndocuments — in formats like HTML and PDF — are stored in databases that supports a vector data \\ntype or efficient document search, such as pgvector, Qdrant or Elasticsearch Relevance Engine. For \\na given prompt, the database is queried to retrieve relevant documents, which are then combined \\nwith the prompt to provide richer context to the LLM. This results in higher quality output and greatly \\nreduced hallucinations. The context window — which determines the maximum size of the LLM input \\n— is limited, which means that selecting the most relevant documents is crucial. We improve the \\nrelevancy of the content that is added to the prompt by reranking. Similarly, the documents are usually \\ntoo large to calculate an embedding, which means they must be split into smaller chunks. This is often \\na difficult problem, and one approach is to have the chunks overlap to a certain extent.'),\n", + " Document(metadata={}, page_content='New Moved in/out No change\\n\\n© Thoughtworks, Inc. All Rights Reserved. 12\\n\\nTechniques\\n\\n1. Retrieval-augmented generation (RAG)\\nAdopt\\n\\nRetrieval-augmented generation (RAG) is the preferred pattern for our teams to improve the quality of \\nresponses generated by a large language model (LLM). We’ve successfully used it in several projects, \\nincluding the popular Jugalbandi AI Platform. With RAG, information about relevant and trustworthy \\ndocuments — in formats like HTML and PDF — are stored in databases that supports a vector data \\ntype or efficient document search, such as pgvector, Qdrant or Elasticsearch Relevance Engine. For \\na given prompt, the database is queried to retrieve relevant documents, which are then combined \\nwith the prompt to provide richer context to the LLM. This results in higher quality output and greatly \\nreduced hallucinations. The context window — which determines the maximum size of the LLM input \\n— is limited, which means that selecting the most relevant documents is crucial. We improve the \\nrelevancy of the content that is added to the prompt by reranking. Similarly, the documents are usually \\ntoo large to calculate an embedding, which means they must be split into smaller chunks. This is often \\na difficult problem, and one approach is to have the chunks overlap to a certain extent.'),\n", + " Document(metadata={}, page_content='New Moved in/out No change\\n\\n© Thoughtworks, Inc. All Rights Reserved. 12\\n\\nTechniques\\n\\n1. Retrieval-augmented generation (RAG)\\nAdopt\\n\\nRetrieval-augmented generation (RAG) is the preferred pattern for our teams to improve the quality of \\nresponses generated by a large language model (LLM). We’ve successfully used it in several projects, \\nincluding the popular Jugalbandi AI Platform. With RAG, information about relevant and trustworthy \\ndocuments — in formats like HTML and PDF — are stored in databases that supports a vector data \\ntype or efficient document search, such as pgvector, Qdrant or Elasticsearch Relevance Engine. For \\na given prompt, the database is queried to retrieve relevant documents, which are then combined \\nwith the prompt to provide richer context to the LLM. This results in higher quality output and greatly \\nreduced hallucinations. The context window — which determines the maximum size of the LLM input \\n— is limited, which means that selecting the most relevant documents is crucial. We improve the \\nrelevancy of the content that is added to the prompt by reranking. Similarly, the documents are usually \\ntoo large to calculate an embedding, which means they must be split into smaller chunks. This is often \\na difficult problem, and one approach is to have the chunks overlap to a certain extent.'),\n", + " Document(metadata={}, page_content='New Moved in/out No change\\n\\n© Thoughtworks, Inc. All Rights Reserved. 12\\n\\nTechniques\\n\\n1. Retrieval-augmented generation (RAG)\\nAdopt\\n\\nRetrieval-augmented generation (RAG) is the preferred pattern for our teams to improve the quality of \\nresponses generated by a large language model (LLM). We’ve successfully used it in several projects, \\nincluding the popular Jugalbandi AI Platform. With RAG, information about relevant and trustworthy \\ndocuments — in formats like HTML and PDF — are stored in databases that supports a vector data \\ntype or efficient document search, such as pgvector, Qdrant or Elasticsearch Relevance Engine. For \\na given prompt, the database is queried to retrieve relevant documents, which are then combined \\nwith the prompt to provide richer context to the LLM. This results in higher quality output and greatly \\nreduced hallucinations. The context window — which determines the maximum size of the LLM input \\n— is limited, which means that selecting the most relevant documents is crucial. We improve the \\nrelevancy of the content that is added to the prompt by reranking. Similarly, the documents are usually \\ntoo large to calculate an embedding, which means they must be split into smaller chunks. This is often \\na difficult problem, and one approach is to have the chunks overlap to a certain extent.')],\n", + " 'answer': 'Yes, RAG has been adopted as the preferred pattern for improving the quality of responses generated by a large language model.'}" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import os\n", + "\n", + "from langchain.chains import create_retrieval_chain\n", + "from langchain.chains.combine_documents import create_stuff_documents_chain\n", + "from langchain_community.retrievers.needle import NeedleRetriever\n", + "from langchain_core.prompts import ChatPromptTemplate\n", + "from langchain_openai import ChatOpenAI\n", + "\n", + "llm = ChatOpenAI(temperature=0)\n", + "\n", + "# Initialize the Needle retriever (make sure your Needle API key is set as an environment variable)\n", + "retriever = NeedleRetriever(\n", + " needle_api_key=os.getenv(\"NEEDLE_API_KEY\"),\n", + " collection_id=\"clt_01J87M9T6B71DHZTHNXYZQRG5H\",\n", + ")\n", + "\n", + "# Define system prompt for the assistant\n", + "system_prompt = \"\"\"\n", + " You are an assistant for question-answering tasks. \n", + " Use the following pieces of retrieved context to answer the question.\n", + " If you don't know, say so concisely.\\n\\n{context}\n", + " \"\"\"\n", + "\n", + "prompt = ChatPromptTemplate.from_messages(\n", + " [(\"system\", system_prompt), (\"human\", \"{input}\")]\n", + ")\n", + "\n", + "# Define the question-answering chain using a document chain (stuff chain) and the retriever\n", + "question_answer_chain = create_stuff_documents_chain(llm, prompt)\n", + "\n", + "# Create the RAG (Retrieval-Augmented Generation) chain by combining the retriever and the question-answering chain\n", + "rag_chain = create_retrieval_chain(retriever, question_answer_chain)\n", + "\n", + "# Define the input query\n", + "query = {\"input\": \"Did RAG move to accepted?\"}\n", + "\n", + "response = rag_chain.invoke(query)\n", + "\n", + "response" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## API reference\n", + "\n", + "For detailed documentation of all `Needle` features and configurations head to the API reference: https://docs.needle-ai.com" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": ".venv", + "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.9" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/docs/docs/integrations/document_loaders/sitemap.ipynb b/docs/docs/integrations/document_loaders/sitemap.ipynb index e930b12de31..ed6c74d406b 100644 --- a/docs/docs/integrations/document_loaders/sitemap.ipynb +++ b/docs/docs/integrations/document_loaders/sitemap.ipynb @@ -103,7 +103,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ diff --git a/docs/docs/integrations/document_loaders/tomarkdown.ipynb b/docs/docs/integrations/document_loaders/tomarkdown.ipynb index ffc41ea4e5f..0f3ce0de36a 100644 --- a/docs/docs/integrations/document_loaders/tomarkdown.ipynb +++ b/docs/docs/integrations/document_loaders/tomarkdown.ipynb @@ -153,7 +153,7 @@ "\n", "Best practices for developing with LangChain.\n", "\n", - "### [API reference](https://api.python.langchain.com) [​](\\#api-reference \"Direct link to api-reference\")\n", + "### [API reference](https://python.langchain.com/api_reference/) [​](\\#api-reference \"Direct link to api-reference\")\n", "\n", "Head to the reference section for full documentation of all classes and methods in the LangChain and LangChain Experimental Python packages.\n", "\n", diff --git a/docs/docs/integrations/llms/ai21.ipynb b/docs/docs/integrations/llms/ai21.ipynb index cf83e033e0d..628755f9e1c 100644 --- a/docs/docs/integrations/llms/ai21.ipynb +++ b/docs/docs/integrations/llms/ai21.ipynb @@ -17,6 +17,9 @@ "source": [ "# AI21LLM\n", "\n", + ":::caution This service is deprecated.\n", + "See [this page](https://python.langchain.com/docs/integrations/chat/ai21/) for the updated ChatAI21 object. :::\n", + "\n", "This example goes over how to use LangChain to interact with `AI21` Jurassic models. To use the Jamba model, use the [ChatAI21 object](https://python.langchain.com/docs/integrations/chat/ai21/) instead.\n", "\n", "[See a full list of AI21 models and tools on LangChain.](https://pypi.org/project/langchain-ai21/)\n", diff --git a/docs/docs/integrations/llms/oci_model_deployment_endpoint.ipynb b/docs/docs/integrations/llms/oci_model_deployment_endpoint.ipynb index 0110a9d5756..1449e6789f2 100644 --- a/docs/docs/integrations/llms/oci_model_deployment_endpoint.ipynb +++ b/docs/docs/integrations/llms/oci_model_deployment_endpoint.ipynb @@ -180,9 +180,9 @@ "\n", "For comprehensive details on all features and configurations, please refer to the API reference documentation for each class:\n", "\n", - "* [OCIModelDeploymentLLM](https://api.python.langchain.com/en/latest/llms/langchain_community.llms.oci_data_science_model_deployment_endpoint.OCIModelDeploymentLLM.html)\n", - "* [OCIModelDeploymentVLLM](https://api.python.langchain.com/en/latest/llms/langchain_community.llms.oci_data_science_model_deployment_endpoint.OCIModelDeploymentVLLM.html)\n", - "* [OCIModelDeploymentTGI](https://api.python.langchain.com/en/latest/llms/langchain_community.llms.oci_data_science_model_deployment_endpoint.OCIModelDeploymentTGI.html)" + "* [OCIModelDeploymentLLM](https://python.langchain.com/api_reference/community/llms/langchain_community.llms.oci_data_science_model_deployment_endpoint.OCIModelDeploymentLLM.html)\n", + "* [OCIModelDeploymentVLLM](https://python.langchain.com/api_reference/community/llms/langchain_community.llms.oci_data_science_model_deployment_endpoint.OCIModelDeploymentVLLM.html)\n", + "* [OCIModelDeploymentTGI](https://python.langchain.com/api_reference/community/llms/langchain_community.llms.oci_data_science_model_deployment_endpoint.OCIModelDeploymentTGI.html)" ] } ], diff --git a/docs/docs/integrations/llms/outlines.ipynb b/docs/docs/integrations/llms/outlines.ipynb index f9c434ef974..0f29e87300a 100644 --- a/docs/docs/integrations/llms/outlines.ipynb +++ b/docs/docs/integrations/llms/outlines.ipynb @@ -6,7 +6,7 @@ "source": [ "# Outlines\n", "\n", - "This will help you getting started with Outlines LLM. For detailed documentation of all Outlines features and configurations head to the [API reference](https://api.python.langchain.com/en/latest/llms/outlines.llms.Outlines.html).\n", + "This will help you getting started with Outlines LLM. For detailed documentation of all Outlines features and configurations head to the [API reference](https://python.langchain.com/api_reference/community/llms/langchain_community.llms.outlines.Outlines.html).\n", "\n", "[Outlines](https://github.com/outlines-dev/outlines) is a library for constrained language generation. It allows you to use large language models (LLMs) with various backends while applying constraints to the generated output.\n", "\n", @@ -236,7 +236,7 @@ "source": [ "## API reference\n", "\n", - "For detailed documentation of all ChatOutlines features and configurations head to the API reference: https://api.python.langchain.com/en/latest/chat_models/outlines.chat_models.ChatOutlines.html\n", + "For detailed documentation of all ChatOutlines features and configurations head to the API reference: https://python.langchain.com/api_reference/community/chat_models/langchain_community.chat_models.outlines.ChatOutlines.html\n", "\n", "## Outlines Documentation: \n", "\n", diff --git a/docs/docs/integrations/providers/aerospike.mdx b/docs/docs/integrations/providers/aerospike.mdx new file mode 100644 index 00000000000..9dfbaa68091 --- /dev/null +++ b/docs/docs/integrations/providers/aerospike.mdx @@ -0,0 +1,24 @@ +# Aerospike + +>[Aerospike](https://aerospike.com/docs/vector) is a high-performance, distributed database known for its speed and scalability, now with support for vector storage and search, enabling retrieval and search of embedding vectors for machine learning and AI applications. +> See the documentation for Aerospike Vector Search (AVS) [here](https://aerospike.com/docs/vector). + +## Installation and Setup + +Install the AVS Python SDK and AVS langchain vector store: + +```bash +pip install aerospike-vector-search langchain-community + +See the documentation for the Ptyhon SDK [here](https://aerospike-vector-search-python-client.readthedocs.io/en/latest/index.html). +The documentation for the AVS langchain vector store is [here](https://python.langchain.com/api_reference/community/vectorstores/langchain_community.vectorstores.aerospike.Aerospike.html). + +## Vector Store + +To import this vectorstore: + +```python +from langchain_community.vectorstores import Aerospike + +See a usage example [here](https://python.langchain.com/docs/integrations/vectorstores/aerospike/). + diff --git a/docs/docs/integrations/providers/ai21.mdx b/docs/docs/integrations/providers/ai21.mdx index 60a925363b1..140e755da8b 100644 --- a/docs/docs/integrations/providers/ai21.mdx +++ b/docs/docs/integrations/providers/ai21.mdx @@ -15,26 +15,6 @@ This page covers how to use the `AI21` ecosystem within `LangChain`. pip install langchain-ai21 ``` -## LLMs - -See a [usage example](/docs/integrations/llms/ai21). - -### AI21 LLM - -```python -from langchain_ai21 import AI21LLM -``` - -### AI21 Contextual Answer - -You can use AI21’s contextual answers model to receive text or document, -serving as a context, and a question and return an answer based entirely on this context. - -```python -from langchain_ai21 import AI21ContextualAnswers -``` - - ## Chat models ### AI21 Chat @@ -45,23 +25,32 @@ See a [usage example](/docs/integrations/chat/ai21). from langchain_ai21 import ChatAI21 ``` -## Embedding models +## Deprecated features + +:::caution The following features are deprecated. +::: + +### AI21 LLM + +```python +from langchain_ai21 import AI21LLM +``` + +### AI21 Contextual Answer + +```python +from langchain_ai21 import AI21ContextualAnswers +``` ### AI21 Embeddings -See a [usage example](/docs/integrations/text_embedding/ai21). - ```python from langchain_ai21 import AI21Embeddings ``` - ## Text splitters ### AI21 Semantic Text Splitter -See a [usage example](/docs/integrations/document_transformers/ai21_semantic_text_splitter). - ```python from langchain_ai21 import AI21SemanticTextSplitter -``` - +``` \ No newline at end of file diff --git a/docs/docs/integrations/providers/unstructured.mdx b/docs/docs/integrations/providers/unstructured.mdx index 312a28d6f68..8425ff1faa2 100644 --- a/docs/docs/integrations/providers/unstructured.mdx +++ b/docs/docs/integrations/providers/unstructured.mdx @@ -22,7 +22,7 @@ dependencies running. - To run everything locally, install the open-source python package with `pip install unstructured` along with `pip install langchain-community` and use the same `UnstructuredLoader` as mentioned above. - - You can install document specific dependencies with extras, e.g. `pip install "unstructured[docx]"`. + - You can install document specific dependencies with extras, e.g. `pip install "unstructured[docx]"`. Learn more about extras [here](https://docs.unstructured.io/open-source/installation/full-installation). - To install the dependencies for all document types, use `pip install "unstructured[all-docs]"`. - Install the following system dependencies if they are not already available on your system with e.g. `brew install` for Mac. Depending on what document types you're parsing, you may not need all of these. diff --git a/docs/docs/integrations/retrievers/fleet_context.ipynb b/docs/docs/integrations/retrievers/fleet_context.ipynb index db3e6e79cba..2c2d7e6083c 100644 --- a/docs/docs/integrations/retrievers/fleet_context.ipynb +++ b/docs/docs/integrations/retrievers/fleet_context.ipynb @@ -9,7 +9,7 @@ "\n", ">[Fleet AI Context](https://www.fleet.so/context) is a dataset of high-quality embeddings of the top 1200 most popular & permissive Python Libraries & their documentation.\n", ">\n", - ">The `Fleet AI` team is on a mission to embed the world's most important data. They've started by embedding the top 1200 Python libraries to enable code generation with up-to-date knowledge. They've been kind enough to share their embeddings of the [LangChain docs](/docs/introduction) and [API reference](https://api.python.langchain.com/en/latest/api_reference.html).\n", + ">The `Fleet AI` team is on a mission to embed the world's most important data. They've started by embedding the top 1200 Python libraries to enable code generation with up-to-date knowledge. They've been kind enough to share their embeddings of the [LangChain docs](/docs/introduction) and [API reference](https://python.langchain.com/api_reference/).\n", "\n", "Let's take a look at how we can use these embeddings to power a docs retrieval system and ultimately a simple code-generating chain!" ] diff --git a/docs/docs/integrations/retrievers/needle.ipynb b/docs/docs/integrations/retrievers/needle.ipynb new file mode 100644 index 00000000000..616b6c0a896 --- /dev/null +++ b/docs/docs/integrations/retrievers/needle.ipynb @@ -0,0 +1,235 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Needle Retriever\n", + "[Needle](https://needle-ai.com) makes it easy to create your RAG pipelines with minimal effort. \n", + "\n", + "For more details, refer to our [API documentation](https://docs.needle-ai.com/docs/api-reference/needle-api)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Overview\n", + "The Needle Document Loader is a utility for integrating Needle collections with LangChain. It enables seamless storage, retrieval, and utilization of documents for Retrieval-Augmented Generation (RAG) workflows.\n", + "\n", + "This example demonstrates:\n", + "\n", + "* Storing documents into a Needle collection.\n", + "* Setting up a retriever to fetch documents.\n", + "* Building a Retrieval-Augmented Generation (RAG) pipeline." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Setup\n", + "Before starting, ensure you have the following environment variables set:\n", + "\n", + "* NEEDLE_API_KEY: Your API key for authenticating with Needle.\n", + "* OPENAI_API_KEY: Your OpenAI API key for language model operations." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Initialization\n", + "To initialize the NeedleLoader, you need the following parameters:\n", + "\n", + "* needle_api_key: Your Needle API key (or set it as an environment variable).\n", + "* collection_id: The ID of the Needle collection to work with." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import os" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "os.environ[\"NEEDLE_API_KEY\"] = \"\"" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "os.environ[\"OPENAI_API_KEY\"] = \"\"" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Instantiation" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from langchain_community.document_loaders.needle import NeedleLoader\n", + "\n", + "collection_id = \"clt_01J87M9T6B71DHZTHNXYZQRG5H\"\n", + "\n", + "# Initialize NeedleLoader to store documents to the collection\n", + "document_loader = NeedleLoader(\n", + " needle_api_key=os.getenv(\"NEEDLE_API_KEY\"),\n", + " collection_id=collection_id,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Load\n", + "To add files to the Needle collection:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "files = {\n", + " \"tech-radar-30.pdf\": \"https://www.thoughtworks.com/content/dam/thoughtworks/documents/radar/2024/04/tr_technology_radar_vol_30_en.pdf\"\n", + "}\n", + "\n", + "document_loader.add_files(files=files)" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "# Show the documents in the collection\n", + "# collections_documents = document_loader.load()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Usage\n", + "### Use within a chain\n", + "Below is a complete example of setting up a RAG pipeline with Needle within a chain:" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'input': 'Did RAG move to accepted?',\n", + " 'context': [Document(metadata={}, page_content='New Moved in/out No change\\n\\n© Thoughtworks, Inc. All Rights Reserved. 12\\n\\nTechniques\\n\\n1. Retrieval-augmented generation (RAG)\\nAdopt\\n\\nRetrieval-augmented generation (RAG) is the preferred pattern for our teams to improve the quality of \\nresponses generated by a large language model (LLM). We’ve successfully used it in several projects, \\nincluding the popular Jugalbandi AI Platform. With RAG, information about relevant and trustworthy \\ndocuments — in formats like HTML and PDF — are stored in databases that supports a vector data \\ntype or efficient document search, such as pgvector, Qdrant or Elasticsearch Relevance Engine. For \\na given prompt, the database is queried to retrieve relevant documents, which are then combined \\nwith the prompt to provide richer context to the LLM. This results in higher quality output and greatly \\nreduced hallucinations. The context window — which determines the maximum size of the LLM input \\n— is limited, which means that selecting the most relevant documents is crucial. We improve the \\nrelevancy of the content that is added to the prompt by reranking. Similarly, the documents are usually \\ntoo large to calculate an embedding, which means they must be split into smaller chunks. This is often \\na difficult problem, and one approach is to have the chunks overlap to a certain extent.'),\n", + " Document(metadata={}, page_content='New Moved in/out No change\\n\\n© Thoughtworks, Inc. All Rights Reserved. 12\\n\\nTechniques\\n\\n1. Retrieval-augmented generation (RAG)\\nAdopt\\n\\nRetrieval-augmented generation (RAG) is the preferred pattern for our teams to improve the quality of \\nresponses generated by a large language model (LLM). We’ve successfully used it in several projects, \\nincluding the popular Jugalbandi AI Platform. With RAG, information about relevant and trustworthy \\ndocuments — in formats like HTML and PDF — are stored in databases that supports a vector data \\ntype or efficient document search, such as pgvector, Qdrant or Elasticsearch Relevance Engine. For \\na given prompt, the database is queried to retrieve relevant documents, which are then combined \\nwith the prompt to provide richer context to the LLM. This results in higher quality output and greatly \\nreduced hallucinations. The context window — which determines the maximum size of the LLM input \\n— is limited, which means that selecting the most relevant documents is crucial. We improve the \\nrelevancy of the content that is added to the prompt by reranking. Similarly, the documents are usually \\ntoo large to calculate an embedding, which means they must be split into smaller chunks. This is often \\na difficult problem, and one approach is to have the chunks overlap to a certain extent.'),\n", + " Document(metadata={}, page_content='New Moved in/out No change\\n\\n© Thoughtworks, Inc. All Rights Reserved. 12\\n\\nTechniques\\n\\n1. Retrieval-augmented generation (RAG)\\nAdopt\\n\\nRetrieval-augmented generation (RAG) is the preferred pattern for our teams to improve the quality of \\nresponses generated by a large language model (LLM). We’ve successfully used it in several projects, \\nincluding the popular Jugalbandi AI Platform. With RAG, information about relevant and trustworthy \\ndocuments — in formats like HTML and PDF — are stored in databases that supports a vector data \\ntype or efficient document search, such as pgvector, Qdrant or Elasticsearch Relevance Engine. For \\na given prompt, the database is queried to retrieve relevant documents, which are then combined \\nwith the prompt to provide richer context to the LLM. This results in higher quality output and greatly \\nreduced hallucinations. The context window — which determines the maximum size of the LLM input \\n— is limited, which means that selecting the most relevant documents is crucial. We improve the \\nrelevancy of the content that is added to the prompt by reranking. Similarly, the documents are usually \\ntoo large to calculate an embedding, which means they must be split into smaller chunks. This is often \\na difficult problem, and one approach is to have the chunks overlap to a certain extent.'),\n", + " Document(metadata={}, page_content='New Moved in/out No change\\n\\n© Thoughtworks, Inc. All Rights Reserved. 12\\n\\nTechniques\\n\\n1. Retrieval-augmented generation (RAG)\\nAdopt\\n\\nRetrieval-augmented generation (RAG) is the preferred pattern for our teams to improve the quality of \\nresponses generated by a large language model (LLM). We’ve successfully used it in several projects, \\nincluding the popular Jugalbandi AI Platform. With RAG, information about relevant and trustworthy \\ndocuments — in formats like HTML and PDF — are stored in databases that supports a vector data \\ntype or efficient document search, such as pgvector, Qdrant or Elasticsearch Relevance Engine. For \\na given prompt, the database is queried to retrieve relevant documents, which are then combined \\nwith the prompt to provide richer context to the LLM. This results in higher quality output and greatly \\nreduced hallucinations. The context window — which determines the maximum size of the LLM input \\n— is limited, which means that selecting the most relevant documents is crucial. We improve the \\nrelevancy of the content that is added to the prompt by reranking. Similarly, the documents are usually \\ntoo large to calculate an embedding, which means they must be split into smaller chunks. This is often \\na difficult problem, and one approach is to have the chunks overlap to a certain extent.'),\n", + " Document(metadata={}, page_content='https://www.thoughtworks.com/radar/tools/nemo-guardrails\\nhttps://www.thoughtworks.com/radar/platforms/langfuse\\nhttps://www.thoughtworks.com/radar/techniques/retrieval-augmented-generation-rag\\nhttps://cruisecontrol.sourceforge.net/\\nhttps://martinfowler.com/articles/continuousIntegration.html\\nhttps://www.thoughtworks.com/radar/techniques/peer-review-equals-pull-request\\nhttps://martinfowler.com/bliki/ContinuousIntegrationCertification.html\\nhttps://linearb.io/platform/gitstream\\nhttps://www.thoughtworks.com/radar/tools/github-merge-queue\\nhttps://stacking.dev/\\n\\n© Thoughtworks, Inc. All Rights Reserved. 8\\n\\nHold HoldAssess AssessTrial TrialAdopt Adopt\\n\\n18\\n\\n8\\n\\n24\\n\\n29\\n\\n30\\n31\\n\\n32\\n33\\n\\n34 35\\n\\n36\\n37\\n\\n38 39\\n\\n40\\n41\\n\\n42\\n43\\n\\n26\\n\\n2\\n\\n3\\n\\n4\\n\\n5\\n\\n6 7\\n\\n9\\n\\n15\\n\\n16\\n\\n17\\n\\n10\\n\\n11\\n\\n12\\n\\n13 14\\n\\n44\\n\\n47\\n49\\n\\n50\\n\\n65\\n66\\n\\n67 68\\n69\\n\\n70\\n71\\n\\n72\\n\\n73 74\\n\\n75\\n\\n76 77\\n\\n78\\n79\\n\\n80\\n81\\n\\n82\\n\\n83\\n\\n51\\n\\n52 54\\n\\n59\\n\\n53\\n56\\n\\n58\\n\\n61\\n\\n62\\n63\\n\\n64\\n\\n85\\n\\n88 89\\n\\n90 91\\n\\n92\\n93\\n\\n94\\n95 96\\n\\n97\\n\\n98 99\\n\\n100\\n\\n101\\n102\\n\\n103\\n\\n104\\n\\n86\\n\\n87\\n1921\\n\\n22\\n\\n20\\n28\\n\\n25\\n\\n27\\n\\n23\\n\\n84\\n\\n105\\n\\n1\\n45\\n\\n46\\n\\n48\\n\\n55\\n57')],\n", + " 'answer': 'Yes, RAG has moved to the \"Adopt\" status.'}" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import os\n", + "\n", + "from langchain.chains import create_retrieval_chain\n", + "from langchain.chains.combine_documents import create_stuff_documents_chain\n", + "from langchain_community.retrievers.needle import NeedleRetriever\n", + "from langchain_core.prompts import ChatPromptTemplate\n", + "from langchain_openai import ChatOpenAI\n", + "\n", + "llm = ChatOpenAI(temperature=0)\n", + "\n", + "# Initialize the Needle retriever (make sure your Needle API key is set as an environment variable)\n", + "retriever = NeedleRetriever(\n", + " needle_api_key=os.getenv(\"NEEDLE_API_KEY\"),\n", + " collection_id=\"clt_01J87M9T6B71DHZTHNXYZQRG5H\",\n", + ")\n", + "\n", + "# Define system prompt for the assistant\n", + "system_prompt = \"\"\"\n", + " You are an assistant for question-answering tasks. \n", + " Use the following pieces of retrieved context to answer the question.\n", + " If you don't know, say so concisely.\\n\\n{context}\n", + " \"\"\"\n", + "\n", + "prompt = ChatPromptTemplate.from_messages(\n", + " [(\"system\", system_prompt), (\"human\", \"{input}\")]\n", + ")\n", + "\n", + "# Define the question-answering chain using a document chain (stuff chain) and the retriever\n", + "question_answer_chain = create_stuff_documents_chain(llm, prompt)\n", + "\n", + "# Create the RAG (Retrieval-Augmented Generation) chain by combining the retriever and the question-answering chain\n", + "rag_chain = create_retrieval_chain(retriever, question_answer_chain)\n", + "\n", + "# Define the input query\n", + "query = {\"input\": \"Did RAG move to accepted?\"}\n", + "\n", + "response = rag_chain.invoke(query)\n", + "\n", + "response" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## API reference\n", + "\n", + "For detailed documentation of all `Needle` features and configurations head to the API reference: https://docs.needle-ai.com" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": ".venv", + "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.9" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/docs/docs/integrations/text_embedding/ai21.ipynb b/docs/docs/integrations/text_embedding/ai21.ipynb index 7cf6de22454..d77ba9bbf6e 100644 --- a/docs/docs/integrations/text_embedding/ai21.ipynb +++ b/docs/docs/integrations/text_embedding/ai21.ipynb @@ -17,6 +17,8 @@ "source": [ "# AI21Embeddings\n", "\n", + ":::caution This service is deprecated. :::\n", + "\n", "This will help you get started with AI21 embedding models using LangChain. For detailed documentation on `AI21Embeddings` features and configuration options, please refer to the [API reference](https://python.langchain.com/api_reference/ai21/embeddings/langchain_ai21.embeddings.AI21Embeddings.html).\n", "\n", "## Overview\n", diff --git a/docs/docs/integrations/text_embedding/databricks.ipynb b/docs/docs/integrations/text_embedding/databricks.ipynb index 8dfb6237dd9..31505992ca7 100644 --- a/docs/docs/integrations/text_embedding/databricks.ipynb +++ b/docs/docs/integrations/text_embedding/databricks.ipynb @@ -28,7 +28,7 @@ "\n", "| Class | Package |\n", "| :--- | :--- |\n", - "| [DatabricksEmbeddings](https://api.python.langchain.com/en/latest/embeddings/langchain_databricks.embeddings.DatabricksEmbeddings.html) | [databricks-langchain](https://python.langchain.com/docs/integrations/providers/databricks/) |\n", + "| [DatabricksEmbeddings](https://python.langchain.com/api_reference/community/embeddings/langchain_community.embeddings.databricks.DatabricksEmbeddings.html) | [databricks-langchain](https://python.langchain.com/docs/integrations/providers/databricks/) |\n", "\n", "### Supported Methods\n", "\n", diff --git a/docs/docs/integrations/text_embedding/zhipuai.ipynb b/docs/docs/integrations/text_embedding/zhipuai.ipynb index da5de5fbf19..d33ac41c93e 100644 --- a/docs/docs/integrations/text_embedding/zhipuai.ipynb +++ b/docs/docs/integrations/text_embedding/zhipuai.ipynb @@ -251,7 +251,7 @@ "source": [ "## API Reference\n", "\n", - "For detailed documentation on `ZhipuAIEmbeddings` features and configuration options, please refer to the [API reference](https://api.python.langchain.com/en/latest/embeddings/langchain_community.embeddings.zhipuai.ZhipuAIEmbeddings.html).\n" + "For detailed documentation on `ZhipuAIEmbeddings` features and configuration options, please refer to the [API reference](https://python.langchain.com/api_reference/community/embeddings/langchain_community.embeddings.zhipuai.ZhipuAIEmbeddings.html).\n" ] } ], diff --git a/docs/docs/integrations/vectorstores/databricks_vector_search.ipynb b/docs/docs/integrations/vectorstores/databricks_vector_search.ipynb index 28685cbd0e2..65ed390b9da 100644 --- a/docs/docs/integrations/vectorstores/databricks_vector_search.ipynb +++ b/docs/docs/integrations/vectorstores/databricks_vector_search.ipynb @@ -506,7 +506,7 @@ "source": [ "## API reference\n", "\n", - "For detailed documentation of all DatabricksVectorSearch features and configurations head to the API reference: https://api.python.langchain.com/en/latest/vectorstores/langchain_databricks.vectorstores.DatabricksVectorSearch.html" + "For detailed documentation of all DatabricksVectorSearch features and configurations head to the API reference: https://python.langchain.com/api_reference/databricks/vectorstores/langchain_databricks.vectorstores.DatabricksVectorSearch.html" ] } ], diff --git a/docs/docs/integrations/vectorstores/mongodb_atlas.ipynb b/docs/docs/integrations/vectorstores/mongodb_atlas.ipynb index 65d19ce6733..a891a53f80b 100644 --- a/docs/docs/integrations/vectorstores/mongodb_atlas.ipynb +++ b/docs/docs/integrations/vectorstores/mongodb_atlas.ipynb @@ -439,7 +439,7 @@ "source": [ "#### Other search methods\n", "\n", - "There are a variety of other search methods that are not covered in this notebook, such as MMR search or searching by vector. For a full list of the search abilities available for `MongoDBAtlasVectorStore` check out the [API reference](https://api.python.langchain.com/en/latest/vectorstores/langchain_mongodb.vectorstores.MongoDBAtlasVectorSearch.html)." + "There are a variety of other search methods that are not covered in this notebook, such as MMR search or searching by vector. For a full list of the search abilities available for `MongoDBAtlasVectorStore` check out the [API reference](https://python.langchain.com/api_reference/mongodb/vectorstores/langchain_mongodb.vectorstores.MongoDBAtlasVectorSearch.html)." ] }, { diff --git a/docs/docs/integrations/vectorstores/sqlitevec.ipynb b/docs/docs/integrations/vectorstores/sqlitevec.ipynb index 33eb5b854d5..2df878ad238 100644 --- a/docs/docs/integrations/vectorstores/sqlitevec.ipynb +++ b/docs/docs/integrations/vectorstores/sqlitevec.ipynb @@ -155,7 +155,7 @@ "cell_type": "markdown", "source": [ "## API reference\n", - "For detailed documentation of all SQLiteVec features and configurations head to the API reference:https://api.python.langchain.com/en/latest/vectorstores/langchain_community.vectorstores.sqlitevec.SQLiteVec.html" + "For detailed documentation of all SQLiteVec features and configurations head to the API reference: https://python.langchain.com/api_reference/community/vectorstores/langchain_community.vectorstores.sqlitevec.SQLiteVec.html" ] }, { diff --git a/docs/docs/security.md b/docs/docs/security.md deleted file mode 100644 index 08e841c89a2..00000000000 --- a/docs/docs/security.md +++ /dev/null @@ -1,30 +0,0 @@ -# Security - -LangChain has a large ecosystem of integrations with various external resources like local and remote file systems, APIs and databases. These integrations allow developers to create versatile applications that combine the power of LLMs with the ability to access, interact with and manipulate external resources. - -## Best practices - -When building such applications developers should remember to follow good security practices: - -* [**Limit Permissions**](https://en.wikipedia.org/wiki/Principle_of_least_privilege): Scope permissions specifically to the application's need. Granting broad or excessive permissions can introduce significant security vulnerabilities. To avoid such vulnerabilities, consider using read-only credentials, disallowing access to sensitive resources, using sandboxing techniques (such as running inside a container), specifying proxy configurations to control external requests, etc. as appropriate for your application. -* **Anticipate Potential Misuse**: Just as humans can err, so can Large Language Models (LLMs). Always assume that any system access or credentials may be used in any way allowed by the permissions they are assigned. For example, if a pair of database credentials allows deleting data, it’s safest to assume that any LLM able to use those credentials may in fact delete data. -* [**Defense in Depth**](https://en.wikipedia.org/wiki/Defense_in_depth_(computing)): No security technique is perfect. Fine-tuning and good chain design can reduce, but not eliminate, the odds that a Large Language Model (LLM) may make a mistake. It’s best to combine multiple layered security approaches rather than relying on any single layer of defense to ensure security. For example: use both read-only permissions and sandboxing to ensure that LLMs are only able to access data that is explicitly meant for them to use. - -Risks of not doing so include, but are not limited to: -* Data corruption or loss. -* Unauthorized access to confidential information. -* Compromised performance or availability of critical resources. - -Example scenarios with mitigation strategies: - -* A user may ask an agent with access to the file system to delete files that should not be deleted or read the content of files that contain sensitive information. To mitigate, limit the agent to only use a specific directory and only allow it to read or write files that are safe to read or write. Consider further sandboxing the agent by running it in a container. -* A user may ask an agent with write access to an external API to write malicious data to the API, or delete data from that API. To mitigate, give the agent read-only API keys, or limit it to only use endpoints that are already resistant to such misuse. -* A user may ask an agent with access to a database to drop a table or mutate the schema. To mitigate, scope the credentials to only the tables that the agent needs to access and consider issuing READ-ONLY credentials. - -If you're building applications that access external resources like file systems, APIs -or databases, consider speaking with your company's security team to determine how to best -design and secure your applications. - -## Reporting a vulnerability - -Please report security vulnerabilities by email to security@langchain.dev. This will ensure the issue is promptly triaged and acted upon as needed. diff --git a/docs/docs/versions/migrating_memory/conversation_buffer_window_memory.ipynb b/docs/docs/versions/migrating_memory/conversation_buffer_window_memory.ipynb index f031e1dbb70..4e53e5506b8 100644 --- a/docs/docs/versions/migrating_memory/conversation_buffer_window_memory.ipynb +++ b/docs/docs/versions/migrating_memory/conversation_buffer_window_memory.ipynb @@ -426,7 +426,7 @@ "\n", "## Usage with a pre-built langgraph agent\n", "\n", - "This example shows usage of an Agent Executor with a pre-built agent constructed using the [create_tool_calling_agent](https://api.python.langchain.com/en/latest/agents/langchain.agents.tool_calling_agent.base.create_tool_calling_agent.html) function.\n", + "This example shows usage of an Agent Executor with a pre-built agent constructed using the [create_tool_calling_agent](https://python.langchain.com/api_reference/langchain/agents/langchain.agents.tool_calling_agent.base.create_tool_calling_agent.html) function.\n", "\n", "If you are using one of the [old LangChain pre-built agents](https://python.langchain.com/v0.1/docs/modules/agents/agent_types/), you should be able\n", "to replace that code with the new [langgraph pre-built agent](https://langchain-ai.github.io/langgraph/how-tos/create-react-agent/) which leverages\n", @@ -673,7 +673,7 @@ "\n", "\n", "If you need to implement more efficient logic and want to use `RunnableWithMessageHistory` for now the way to achieve this\n", - "is to subclass from [BaseChatMessageHistory](https://api.python.langchain.com/en/latest/chat_history/langchain_core.chat_history.BaseChatMessageHistory.html) and\n", + "is to subclass from [BaseChatMessageHistory](https://python.langchain.com/api_reference/core/chat_history/langchain_core.chat_history.BaseChatMessageHistory.html) and\n", "define appropriate logic for `add_messages` (that doesn't simply append the history, but instead re-writes it).\n", "\n", "Unless you have a good reason to implement this solution, you should instead use LangGraph." diff --git a/libs/cli/.gitignore b/libs/cli/.gitignore index 68bc17f9ff2..413adb3d0f4 100644 --- a/libs/cli/.gitignore +++ b/libs/cli/.gitignore @@ -158,3 +158,5 @@ cython_debug/ # and can be added to the global gitignore or merged into this file. For a more nuclear # option (not recommended) you can uncomment the following to ignore the entire idea folder. #.idea/ + +.integration_test diff --git a/libs/cli/Makefile b/libs/cli/Makefile index 445235c22c8..ac855bd4dc5 100644 --- a/libs/cli/Makefile +++ b/libs/cli/Makefile @@ -1,8 +1,47 @@ -lint lint_diff: - poetry run poe lint -test: - poetry run poe test +###################### +# LINTING AND FORMATTING +###################### -format: - poetry run poe format +# Define a variable for Python and notebook files. +PYTHON_FILES=. +MYPY_CACHE=.mypy_cache +lint format: PYTHON_FILES=. +lint_diff format_diff: PYTHON_FILES=$(shell git diff --relative=libs/cli --name-only --diff-filter=d master | grep -E '\.py$$|\.ipynb$$') +lint_package: PYTHON_FILES=langchain_cli +lint_tests: PYTHON_FILES=tests +lint_tests: MYPY_CACHE=.mypy_cache_test + +lint lint_diff lint_package lint_tests: + [ "$(PYTHON_FILES)" = "" ] || poetry run ruff check $(PYTHON_FILES) + [ "$(PYTHON_FILES)" = "" ] || poetry run ruff format $(PYTHON_FILES) --diff + [ "$(PYTHON_FILES)" = "" ] || mkdir -p $(MYPY_CACHE) && poetry run mypy $(PYTHON_FILES) --cache-dir $(MYPY_CACHE) + +format format_diff: + [ "$(PYTHON_FILES)" = "" ] || poetry run ruff format $(PYTHON_FILES) + [ "$(PYTHON_FILES)" = "" ] || poetry run ruff check --select I --fix $(PYTHON_FILES) + +test tests: _test _e2e_test + +PYTHON = .venv/bin/python + +_test: + poetry run pytest tests + +# custom integration testing for cli integration flow +# currently ignores vectorstores test because lacks implementation +_e2e_test: + rm -rf .integration_test + mkdir .integration_test + cd .integration_test && \ + python3 -m venv .venv && \ + $(PYTHON) -m pip install --upgrade poetry && \ + $(PYTHON) -m pip install -e .. && \ + $(PYTHON) -m langchain_cli.cli integration new --name parrot-link --name-class ParrotLink && \ + cd langchain-parrot-link && \ + poetry install --with lint,typing,test && \ + poetry run pip install -e ../../../standard-tests && \ + make format lint tests && \ + poetry install --with test_integration && \ + rm tests/integration_tests/test_vectorstores.py && \ + make integration_test diff --git a/libs/cli/langchain_cli/dev_scripts.py b/libs/cli/langchain_cli/dev_scripts.py index cccd9689e44..ebb9331a9c6 100644 --- a/libs/cli/langchain_cli/dev_scripts.py +++ b/libs/cli/langchain_cli/dev_scripts.py @@ -1,3 +1,4 @@ +# type: ignore """ Development Scripts for template packages """ diff --git a/libs/cli/langchain_cli/integration_template/Makefile b/libs/cli/langchain_cli/integration_template/Makefile index b30039ace1f..4c4bbf237d9 100644 --- a/libs/cli/langchain_cli/integration_template/Makefile +++ b/libs/cli/langchain_cli/integration_template/Makefile @@ -33,13 +33,13 @@ lint_tests: PYTHON_FILES=tests lint_tests: MYPY_CACHE=.mypy_cache_test lint lint_diff lint_package lint_tests: - [ "$(PYTHON_FILES)" = "" ] || poetry run ruff $(PYTHON_FILES) + [ "$(PYTHON_FILES)" = "" ] || poetry run ruff check $(PYTHON_FILES) [ "$(PYTHON_FILES)" = "" ] || poetry run ruff format $(PYTHON_FILES) --diff [ "$(PYTHON_FILES)" = "" ] || mkdir -p $(MYPY_CACHE) && poetry run mypy $(PYTHON_FILES) --cache-dir $(MYPY_CACHE) format format_diff: [ "$(PYTHON_FILES)" = "" ] || poetry run ruff format $(PYTHON_FILES) - [ "$(PYTHON_FILES)" = "" ] || poetry run ruff --select I --fix $(PYTHON_FILES) + [ "$(PYTHON_FILES)" = "" ] || poetry run ruff check --select I --fix $(PYTHON_FILES) spell_check: poetry run codespell --toml pyproject.toml diff --git a/libs/cli/langchain_cli/integration_template/integration_template/__init__.py b/libs/cli/langchain_cli/integration_template/integration_template/__init__.py index 60d8dac5d00..44bec467eaa 100644 --- a/libs/cli/langchain_cli/integration_template/integration_template/__init__.py +++ b/libs/cli/langchain_cli/integration_template/integration_template/__init__.py @@ -1,8 +1,11 @@ from importlib import metadata from __module_name__.chat_models import Chat__ModuleName__ +from __module_name__.document_loaders import __ModuleName__Loader from __module_name__.embeddings import __ModuleName__Embeddings -from __module_name__.llms import __ModuleName__LLM +from __module_name__.retrievers import __ModuleName__Retriever +from __module_name__.toolkits import __ModuleName__Toolkit +from __module_name__.tools import __ModuleName__Tool from __module_name__.vectorstores import __ModuleName__VectorStore try: @@ -14,8 +17,11 @@ del metadata # optional, avoids polluting the results of dir(__package__) __all__ = [ "Chat__ModuleName__", - "__ModuleName__LLM", "__ModuleName__VectorStore", "__ModuleName__Embeddings", + "__ModuleName__Loader", + "__ModuleName__Retriever", + "__ModuleName__Toolkit", + "__ModuleName__Tool", "__version__", ] diff --git a/libs/cli/langchain_cli/integration_template/integration_template/chat_models.py b/libs/cli/langchain_cli/integration_template/integration_template/chat_models.py index d299fb2ff26..917feb2df0b 100644 --- a/libs/cli/langchain_cli/integration_template/integration_template/chat_models.py +++ b/libs/cli/langchain_cli/integration_template/integration_template/chat_models.py @@ -1,13 +1,19 @@ """__ModuleName__ chat models.""" -from typing import Any, List, Optional +from typing import Any, Dict, Iterator, List, Optional from langchain_core.callbacks import ( CallbackManagerForLLMRun, ) -from langchain_core.language_models.chat_models import BaseChatModel -from langchain_core.messages import BaseMessage -from langchain_core.outputs import ChatResult +from langchain_core.language_models import BaseChatModel +from langchain_core.messages import ( + AIMessage, + AIMessageChunk, + BaseMessage, +) +from langchain_core.messages.ai import UsageMetadata +from langchain_core.outputs import ChatGeneration, ChatGenerationChunk, ChatResult +from pydantic import Field class Chat__ModuleName__(BaseChatModel): @@ -15,6 +21,8 @@ class Chat__ModuleName__(BaseChatModel): # https://github.com/langchain-ai/langchain/blob/7ff05357bac6eaedf5058a2af88f23a1817d40fe/libs/partners/openai/langchain_openai/chat_models/base.py#L1120 """__ModuleName__ chat model integration. + The default implementation echoes the first `parrot_buffer_length` characters of the input. + # TODO: Replace with relevant packages, env vars. Setup: Install ``__package_name__`` and set environment variable ``__MODULE_NAME___API_KEY``. @@ -258,7 +266,36 @@ class Chat__ModuleName__(BaseChatModel): """ # noqa: E501 - # TODO: This method must be implemented to generate chat responses. + model_name: str = Field(alias="model") + """The name of the model""" + parrot_buffer_length: int + """The number of characters from the last message of the prompt to be echoed.""" + temperature: Optional[float] = None + max_tokens: Optional[int] = None + timeout: Optional[int] = None + stop: Optional[List[str]] = None + max_retries: int = 2 + + @property + def _llm_type(self) -> str: + """Return type of chat model.""" + return "chat-__package_name_short__" + + @property + def _identifying_params(self) -> Dict[str, Any]: + """Return a dictionary of identifying parameters. + + This information is used by the LangChain callback system, which + is used for tracing purposes make it possible to monitor LLMs. + """ + return { + # The model name allows users to specify custom token counting + # rules in LLM monitoring applications (e.g., in LangSmith users + # can provide per token pricing for their model and monitor + # costs for the given LLM.) + "model_name": self.model_name, + } + def _generate( self, messages: List[BaseMessage], @@ -266,16 +303,101 @@ class Chat__ModuleName__(BaseChatModel): run_manager: Optional[CallbackManagerForLLMRun] = None, **kwargs: Any, ) -> ChatResult: - raise NotImplementedError() + """Override the _generate method to implement the chat model logic. - # TODO: Implement if Chat__ModuleName__ supports streaming. Otherwise delete method. - # def _stream( - # self, - # messages: List[BaseMessage], - # stop: Optional[List[str]] = None, - # run_manager: Optional[CallbackManagerForLLMRun] = None, - # **kwargs: Any, - # ) -> Iterator[ChatGenerationChunk]: + This can be a call to an API, a call to a local model, or any other + implementation that generates a response to the input prompt. + + Args: + messages: the prompt composed of a list of messages. + stop: a list of strings on which the model should stop generating. + If generation stops due to a stop token, the stop token itself + SHOULD BE INCLUDED as part of the output. This is not enforced + across models right now, but it's a good practice to follow since + it makes it much easier to parse the output of the model + downstream and understand why generation stopped. + run_manager: A run manager with callbacks for the LLM. + """ + # Replace this with actual logic to generate a response from a list + # of messages. + last_message = messages[-1] + tokens = last_message.content[: self.parrot_buffer_length] + ct_input_tokens = sum(len(message.content) for message in messages) + ct_output_tokens = len(tokens) + message = AIMessage( + content=tokens, + additional_kwargs={}, # Used to add additional payload to the message + response_metadata={ # Use for response metadata + "time_in_seconds": 3, + }, + usage_metadata={ + "input_tokens": ct_input_tokens, + "output_tokens": ct_output_tokens, + "total_tokens": ct_input_tokens + ct_output_tokens, + }, + ) + ## + + generation = ChatGeneration(message=message) + return ChatResult(generations=[generation]) + + def _stream( + self, + messages: List[BaseMessage], + stop: Optional[List[str]] = None, + run_manager: Optional[CallbackManagerForLLMRun] = None, + **kwargs: Any, + ) -> Iterator[ChatGenerationChunk]: + """Stream the output of the model. + + This method should be implemented if the model can generate output + in a streaming fashion. If the model does not support streaming, + do not implement it. In that case streaming requests will be automatically + handled by the _generate method. + + Args: + messages: the prompt composed of a list of messages. + stop: a list of strings on which the model should stop generating. + If generation stops due to a stop token, the stop token itself + SHOULD BE INCLUDED as part of the output. This is not enforced + across models right now, but it's a good practice to follow since + it makes it much easier to parse the output of the model + downstream and understand why generation stopped. + run_manager: A run manager with callbacks for the LLM. + """ + last_message = messages[-1] + tokens = str(last_message.content[: self.parrot_buffer_length]) + ct_input_tokens = sum(len(message.content) for message in messages) + + for token in tokens: + usage_metadata = UsageMetadata( + { + "input_tokens": ct_input_tokens, + "output_tokens": 1, + "total_tokens": ct_input_tokens + 1, + } + ) + ct_input_tokens = 0 + chunk = ChatGenerationChunk( + message=AIMessageChunk(content=token, usage_metadata=usage_metadata) + ) + + if run_manager: + # This is optional in newer versions of LangChain + # The on_llm_new_token will be called automatically + run_manager.on_llm_new_token(token, chunk=chunk) + + yield chunk + + # Let's add some other information (e.g., response metadata) + chunk = ChatGenerationChunk( + message=AIMessageChunk(content="", response_metadata={"time_in_sec": 3}) + ) + if run_manager: + # This is optional in newer versions of LangChain + # The on_llm_new_token will be called automatically + run_manager.on_llm_new_token(token, chunk=chunk) + yield chunk # TODO: Implement if Chat__ModuleName__ supports async streaming. Otherwise delete. # async def _astream( @@ -294,8 +416,3 @@ class Chat__ModuleName__(BaseChatModel): # run_manager: Optional[AsyncCallbackManagerForLLMRun] = None, # **kwargs: Any, # ) -> ChatResult: - - @property - def _llm_type(self) -> str: - """Return type of chat model.""" - return "chat-__package_name_short__" diff --git a/libs/cli/langchain_cli/integration_template/integration_template/embeddings.py b/libs/cli/langchain_cli/integration_template/integration_template/embeddings.py index 174c567da8d..5df2bbfbd40 100644 --- a/libs/cli/langchain_cli/integration_template/integration_template/embeddings.py +++ b/libs/cli/langchain_cli/integration_template/integration_template/embeddings.py @@ -8,7 +8,8 @@ class __ModuleName__Embeddings(Embeddings): # TODO: Replace with relevant packages, env vars. Setup: - Install ``__package_name__`` and set environment variable ``__MODULE_NAME___API_KEY``. + Install ``__package_name__`` and set environment variable + ``__MODULE_NAME___API_KEY``. .. code-block:: bash @@ -70,21 +71,26 @@ class __ModuleName__Embeddings(Embeddings): """ + def __init__(self, model: str): + self.model = model + def embed_documents(self, texts: List[str]) -> List[List[float]]: """Embed search docs.""" - raise NotImplementedError + return [[0.5, 0.6, 0.7] for _ in texts] def embed_query(self, text: str) -> List[float]: """Embed query text.""" - raise NotImplementedError + return self.embed_documents([text])[0] - # only keep aembed_documents and aembed_query if they're implemented! - # delete them otherwise to use the base class' default - # implementation, which calls the sync version in an executor - async def aembed_documents(self, texts: List[str]) -> List[List[float]]: - """Asynchronous Embed search docs.""" - raise NotImplementedError + # optional: add custom async implementations here + # you can also delete these, and the base class will + # use the default implementation, which calls the sync + # version in an async executor: - async def aembed_query(self, text: str) -> List[float]: - """Asynchronous Embed query text.""" - raise NotImplementedError + # async def aembed_documents(self, texts: List[str]) -> List[List[float]]: + # """Asynchronous Embed search docs.""" + # ... + + # async def aembed_query(self, text: str) -> List[float]: + # """Asynchronous Embed query text.""" + # ... diff --git a/libs/cli/langchain_cli/integration_template/integration_template/llms.py b/libs/cli/langchain_cli/integration_template/integration_template/llms.py deleted file mode 100644 index 2dbe4ac9183..00000000000 --- a/libs/cli/langchain_cli/integration_template/integration_template/llms.py +++ /dev/null @@ -1,155 +0,0 @@ -"""__ModuleName__ large language models.""" - -from typing import ( - Any, - List, - Optional, -) - -from langchain_core.callbacks import ( - CallbackManagerForLLMRun, -) -from langchain_core.language_models import BaseLLM -from langchain_core.outputs import LLMResult - - -class __ModuleName__LLM(BaseLLM): - """__ModuleName__ completion model integration. - - # TODO: Replace with relevant packages, env vars. - Setup: - Install ``__package_name__`` and set environment variable ``__MODULE_NAME___API_KEY``. - - .. code-block:: bash - - pip install -U __package_name__ - export __MODULE_NAME___API_KEY="your-api-key" - - # TODO: Populate with relevant params. - Key init args — completion params: - model: str - Name of __ModuleName__ model to use. - temperature: float - Sampling temperature. - max_tokens: Optional[int] - Max number of tokens to generate. - - # TODO: Populate with relevant params. - Key init args — client params: - timeout: Optional[float] - Timeout for requests. - max_retries: int - Max number of retries. - api_key: Optional[str] - __ModuleName__ API key. If not passed in will be read from env var __MODULE_NAME___API_KEY. - - See full list of supported init args and their descriptions in the params section. - - # TODO: Replace with relevant init params. - Instantiate: - .. code-block:: python - - from __module_name__ import __ModuleName__LLM - - llm = __ModuleName__LLM( - model="...", - temperature=0, - max_tokens=None, - timeout=None, - max_retries=2, - # api_key="...", - # other params... - ) - - Invoke: - .. code-block:: python - - input_text = "The meaning of life is " - llm.invoke(input_text) - - .. code-block:: python - - # TODO: Example output. - - # TODO: Delete if token-level streaming isn't supported. - Stream: - .. code-block:: python - - for chunk in llm.stream(input_text): - print(chunk) - - .. code-block:: python - - # TODO: Example output. - - .. code-block:: python - - ''.join(llm.stream(input_text)) - - .. code-block:: python - - # TODO: Example output. - - # TODO: Delete if native async isn't supported. - Async: - .. code-block:: python - - await llm.ainvoke(input_text) - - # stream: - # async for chunk in (await llm.astream(input_text)) - - # batch: - # await llm.abatch([input_text]) - - .. code-block:: python - - # TODO: Example output. - """ - - # TODO: This method must be implemented to generate text completions. - def _generate( - self, - prompts: List[str], - stop: Optional[List[str]] = None, - run_manager: Optional[CallbackManagerForLLMRun] = None, - **kwargs: Any, - ) -> LLMResult: - raise NotImplementedError - - # TODO: Implement if __ModuleName__LLM supports async generation. Otherwise - # delete method. - # async def _agenerate( - # self, - # prompts: List[str], - # stop: Optional[List[str]] = None, - # run_manager: Optional[AsyncCallbackManagerForLLMRun] = None, - # **kwargs: Any, - # ) -> LLMResult: - # raise NotImplementedError - - # TODO: Implement if __ModuleName__LLM supports streaming. Otherwise delete method. - # def _stream( - # self, - # prompt: str, - # stop: Optional[List[str]] = None, - # run_manager: Optional[CallbackManagerForLLMRun] = None, - # **kwargs: Any, - # ) -> Iterator[GenerationChunk]: - # raise NotImplementedError - - # TODO: Implement if __ModuleName__LLM supports async streaming. Otherwise delete - # method. - # async def _astream( - # self, - # prompt: str, - # stop: Optional[List[str]] = None, - # run_manager: Optional[AsyncCallbackManagerForLLMRun] = None, - # **kwargs: Any, - # ) -> AsyncIterator[GenerationChunk]: - # raise NotImplementedError - - @property - def _llm_type(self) -> str: - """Return type of LLM.""" - return "__package_name_short__-llm" diff --git a/libs/cli/langchain_cli/integration_template/integration_template/retrievers.py b/libs/cli/langchain_cli/integration_template/integration_template/retrievers.py index c48661873c8..242103f3a40 100644 --- a/libs/cli/langchain_cli/integration_template/integration_template/retrievers.py +++ b/libs/cli/langchain_cli/integration_template/integration_template/retrievers.py @@ -1,7 +1,8 @@ """__ModuleName__ retrievers.""" -from typing import List +from typing import Any, List +from langchain_core.callbacks import CallbackManagerForRetrieverRun from langchain_core.documents import Document from langchain_core.retrievers import BaseRetriever @@ -13,7 +14,8 @@ class __ModuleName__Retriever(BaseRetriever): # TODO: Replace with relevant packages, env vars, etc. Setup: - Install ``__package_name__`` and set environment variable ``__MODULE_NAME___API_KEY``. + Install ``__package_name__`` and set environment variable + ``__MODULE_NAME___API_KEY``. .. code-block:: bash @@ -82,8 +84,24 @@ class __ModuleName__Retriever(BaseRetriever): # TODO: Example output. - """ # noqa: E501 + """ + + k: int = 3 # TODO: This method must be implemented to retrieve documents. - def _get_relevant_documents(self, query: str) -> List[Document]: - raise NotImplementedError() + def _get_relevant_documents( + self, query: str, *, run_manager: CallbackManagerForRetrieverRun, **kwargs: Any + ) -> List[Document]: + k = kwargs.get("k", self.k) + return [ + Document(page_content=f"Result {i} for query: {query}") for i in range(k) + ] + + # optional: add custom async implementations here + # async def _aget_relevant_documents( + # self, + # query: str, + # *, + # run_manager: AsyncCallbackManagerForRetrieverRun, + # **kwargs: Any, + # ) -> List[Document]: ... diff --git a/libs/cli/langchain_cli/integration_template/integration_template/toolkits.py b/libs/cli/langchain_cli/integration_template/integration_template/toolkits.py index 5a803988911..b3eda23bd23 100644 --- a/libs/cli/langchain_cli/integration_template/integration_template/toolkits.py +++ b/libs/cli/langchain_cli/integration_template/integration_template/toolkits.py @@ -2,10 +2,10 @@ from typing import List -from langchain_core.tools import BaseTool, BaseToolKit +from langchain_core.tools import BaseTool, BaseToolkit -class __ModuleName__Toolkit(BaseToolKit): +class __ModuleName__Toolkit(BaseToolkit): # TODO: Replace all TODOs in docstring. See example docstring: # https://github.com/langchain-ai/langchain/blob/c123cb2b304f52ab65db4714eeec46af69a861ec/libs/community/langchain_community/agent_toolkits/sql/toolkit.py#L19 """__ModuleName__ toolkit. diff --git a/libs/cli/langchain_cli/integration_template/integration_template/tools.py b/libs/cli/langchain_cli/integration_template/integration_template/tools.py index 57deb006f06..1904c9865b7 100644 --- a/libs/cli/langchain_cli/integration_template/integration_template/tools.py +++ b/libs/cli/langchain_cli/integration_template/integration_template/tools.py @@ -6,10 +6,10 @@ from langchain_core.callbacks import ( CallbackManagerForToolRun, ) from langchain_core.tools import BaseTool -from pydantic import BaseModel +from pydantic import BaseModel, Field -class __ModuleName__Input(BaseModel): +class __ModuleName__ToolInput(BaseModel): """Input schema for __ModuleName__ tool. This docstring is **not** part of what is sent to the model when performing tool @@ -18,12 +18,11 @@ class __ModuleName__Input(BaseModel): """ # TODO: Add input args and descriptions. - # a: int = Field(..., description="first number") - # b: int = Field(0, description="second number") - ... + a: int = Field(..., description="first number to add") + b: int = Field(..., description="second number to add") -class __ModuleName__Tool(BaseTool): +class __ModuleName__Tool(BaseTool): # type: ignore[override] """__ModuleName__ tool. Setup: @@ -69,24 +68,26 @@ class __ModuleName__Tool(BaseTool): """The name that is passed to the model when performing tool calling.""" description: str = "TODO: Tool description." """The description that is passed to the model when performing tool calling.""" - args_schema: Type[BaseModel] = __ModuleName__Input + args_schema: Type[BaseModel] = __ModuleName__ToolInput """The schema that is passed to the model when performing tool calling.""" # TODO: Add any other init params for the tool. # param1: Optional[str] # """param1 determines foobar""" - # TODO: Replaced *args with real tool arguments. + # TODO: Replaced (a, b) with real tool arguments. def _run( - self, *args, run_manager: Optional[CallbackManagerForToolRun] = None + self, a: int, b: int, *, run_manager: Optional[CallbackManagerForToolRun] = None ) -> str: - raise NotImplementedError + return str(a + b + 80) # TODO: Implement if tool has native async functionality, otherwise delete. # async def _arun( # self, - # *args, + # a: int, + # b: int, + # *, # run_manager: Optional[AsyncCallbackManagerForToolRun] = None, # ) -> str: # ... diff --git a/libs/cli/langchain_cli/integration_template/integration_template/vectorstores.py b/libs/cli/langchain_cli/integration_template/integration_template/vectorstores.py index 4236e8c037e..02ab2c7fccd 100644 --- a/libs/cli/langchain_cli/integration_template/integration_template/vectorstores.py +++ b/libs/cli/langchain_cli/integration_template/integration_template/vectorstores.py @@ -2,8 +2,6 @@ from __future__ import annotations -import asyncio -from functools import partial from typing import ( TYPE_CHECKING, Any, @@ -160,6 +158,8 @@ class __ModuleName__VectorStore(VectorStore): """ # noqa: E501 + _database: dict[str, tuple[Document, list[float]]] = {} + def add_texts( self, texts: Iterable[str], @@ -168,65 +168,70 @@ class __ModuleName__VectorStore(VectorStore): ) -> List[str]: raise NotImplementedError - async def aadd_texts( - self, - texts: Iterable[str], - metadatas: Optional[List[dict]] = None, - **kwargs: Any, - ) -> List[str]: - return await asyncio.get_running_loop().run_in_executor( - None, partial(self.add_texts, **kwargs), texts, metadatas - ) + # optional: add custom async implementations + # async def aadd_texts( + # self, + # texts: Iterable[str], + # metadatas: Optional[List[dict]] = None, + # **kwargs: Any, + # ) -> List[str]: + # return await asyncio.get_running_loop().run_in_executor( + # None, partial(self.add_texts, **kwargs), texts, metadatas + # ) def delete(self, ids: Optional[List[str]] = None, **kwargs: Any) -> Optional[bool]: raise NotImplementedError - async def adelete( - self, ids: Optional[List[str]] = None, **kwargs: Any - ) -> Optional[bool]: - raise NotImplementedError + # optional: add custom async implementations + # async def adelete( + # self, ids: Optional[List[str]] = None, **kwargs: Any + # ) -> Optional[bool]: + # raise NotImplementedError def similarity_search( self, query: str, k: int = 4, **kwargs: Any ) -> List[Document]: raise NotImplementedError - async def asimilarity_search( - self, query: str, k: int = 4, **kwargs: Any - ) -> List[Document]: - # This is a temporary workaround to make the similarity search - # asynchronous. The proper solution is to make the similarity search - # asynchronous in the vector store implementations. - func = partial(self.similarity_search, query, k=k, **kwargs) - return await asyncio.get_event_loop().run_in_executor(None, func) + # optional: add custom async implementations + # async def asimilarity_search( + # self, query: str, k: int = 4, **kwargs: Any + # ) -> List[Document]: + # # This is a temporary workaround to make the similarity search + # # asynchronous. The proper solution is to make the similarity search + # # asynchronous in the vector store implementations. + # func = partial(self.similarity_search, query, k=k, **kwargs) + # return await asyncio.get_event_loop().run_in_executor(None, func) def similarity_search_with_score( self, *args: Any, **kwargs: Any ) -> List[Tuple[Document, float]]: raise NotImplementedError - async def asimilarity_search_with_score( - self, *args: Any, **kwargs: Any - ) -> List[Tuple[Document, float]]: - # This is a temporary workaround to make the similarity search - # asynchronous. The proper solution is to make the similarity search - # asynchronous in the vector store implementations. - func = partial(self.similarity_search_with_score, *args, **kwargs) - return await asyncio.get_event_loop().run_in_executor(None, func) + # optional: add custom async implementations + # async def asimilarity_search_with_score( + # self, *args: Any, **kwargs: Any + # ) -> List[Tuple[Document, float]]: + # # This is a temporary workaround to make the similarity search + # # asynchronous. The proper solution is to make the similarity search + # # asynchronous in the vector store implementations. + # func = partial(self.similarity_search_with_score, *args, **kwargs) + # return await asyncio.get_event_loop().run_in_executor(None, func) def similarity_search_by_vector( self, embedding: List[float], k: int = 4, **kwargs: Any ) -> List[Document]: raise NotImplementedError - async def asimilarity_search_by_vector( - self, embedding: List[float], k: int = 4, **kwargs: Any - ) -> List[Document]: - # This is a temporary workaround to make the similarity search - # asynchronous. The proper solution is to make the similarity search - # asynchronous in the vector store implementations. - func = partial(self.similarity_search_by_vector, embedding, k=k, **kwargs) - return await asyncio.get_event_loop().run_in_executor(None, func) + # optional: add custom async implementations + # async def asimilarity_search_by_vector( + # self, embedding: List[float], k: int = 4, **kwargs: Any + # ) -> List[Document]: + # # This is a temporary workaround to make the similarity search + # # asynchronous. The proper solution is to make the similarity search + # # asynchronous in the vector store implementations. + # func = partial(self.similarity_search_by_vector, embedding, k=k, **kwargs) + # return await asyncio.get_event_loop().run_in_executor(None, func) def max_marginal_relevance_search( self, @@ -238,26 +243,27 @@ class __ModuleName__VectorStore(VectorStore): ) -> List[Document]: raise NotImplementedError - async def amax_marginal_relevance_search( - self, - query: str, - k: int = 4, - fetch_k: int = 20, - lambda_mult: float = 0.5, - **kwargs: Any, - ) -> List[Document]: - # This is a temporary workaround to make the similarity search - # asynchronous. The proper solution is to make the similarity search - # asynchronous in the vector store implementations. - func = partial( - self.max_marginal_relevance_search, - query, - k=k, - fetch_k=fetch_k, - lambda_mult=lambda_mult, - **kwargs, - ) - return await asyncio.get_event_loop().run_in_executor(None, func) + # optional: add custom async implementations + # async def amax_marginal_relevance_search( + # self, + # query: str, + # k: int = 4, + # fetch_k: int = 20, + # lambda_mult: float = 0.5, + # **kwargs: Any, + # ) -> List[Document]: + # # This is a temporary workaround to make the similarity search + # # asynchronous. The proper solution is to make the similarity search + # # asynchronous in the vector store implementations. + # func = partial( + # self.max_marginal_relevance_search, + # query, + # k=k, + # fetch_k=fetch_k, + # lambda_mult=lambda_mult, + # **kwargs, + # ) + # return await asyncio.get_event_loop().run_in_executor(None, func) def max_marginal_relevance_search_by_vector( self, @@ -269,15 +275,16 @@ class __ModuleName__VectorStore(VectorStore): ) -> List[Document]: raise NotImplementedError - async def amax_marginal_relevance_search_by_vector( - self, - embedding: List[float], - k: int = 4, - fetch_k: int = 20, - lambda_mult: float = 0.5, - **kwargs: Any, - ) -> List[Document]: - raise NotImplementedError + # optional: add custom async implementations + # async def amax_marginal_relevance_search_by_vector( + # self, + # embedding: List[float], + # k: int = 4, + # fetch_k: int = 20, + # lambda_mult: float = 0.5, + # **kwargs: Any, + # ) -> List[Document]: + # raise NotImplementedError @classmethod def from_texts( @@ -289,17 +296,18 @@ class __ModuleName__VectorStore(VectorStore): ) -> VST: raise NotImplementedError - @classmethod - async def afrom_texts( - cls: Type[VST], - texts: List[str], - embedding: Embeddings, - metadatas: Optional[List[dict]] = None, - **kwargs: Any, - ) -> VST: - return await asyncio.get_running_loop().run_in_executor( - None, partial(cls.from_texts, **kwargs), texts, embedding, metadatas - ) + # optional: add custom async implementations + # @classmethod + # async def afrom_texts( + # cls: Type[VST], + # texts: List[str], + # embedding: Embeddings, + # metadatas: Optional[List[dict]] = None, + # **kwargs: Any, + # ) -> VST: + # return await asyncio.get_running_loop().run_in_executor( + # None, partial(cls.from_texts, **kwargs), texts, embedding, metadatas + # ) def _select_relevance_score_fn(self) -> Callable[[float], float]: raise NotImplementedError diff --git a/libs/cli/langchain_cli/integration_template/pyproject.toml b/libs/cli/langchain_cli/integration_template/pyproject.toml index efdcb9efead..fa3c596b069 100644 --- a/libs/cli/langchain_cli/integration_template/pyproject.toml +++ b/libs/cli/langchain_cli/integration_template/pyproject.toml @@ -1,5 +1,5 @@ [build-system] -requires = [ "poetry-core>=1.0.0",] +requires = ["poetry-core>=1.0.0"] build-backend = "poetry.core.masonry.api" [tool.poetry] @@ -23,14 +23,16 @@ python = ">=3.9,<4.0" langchain-core = "^0.3.15" [tool.ruff.lint] -select = [ "E", "F", "I", "T201",] +select = ["E", "F", "I", "T201"] [tool.coverage.run] -omit = [ "tests/*",] +omit = ["tests/*"] [tool.pytest.ini_options] addopts = "--strict-markers --strict-config --durations=5" -markers = [ "compile: mark placeholder test used to compile integration tests without running them",] +markers = [ + "compile: mark placeholder test used to compile integration tests without running them", +] asyncio_mode = "auto" [tool.poetry.group.test] @@ -48,11 +50,14 @@ optional = true [tool.poetry.group.dev] optional = true +[tool.poetry.group.dev.dependencies] + [tool.poetry.group.test.dependencies] pytest = "^7.4.3" pytest-asyncio = "^0.23.2" pytest-socket = "^0.7.0" pytest-watcher = "^0.3.4" +langchain-tests = "^0.3.5" [tool.poetry.group.codespell.dependencies] codespell = "^2.2.6" @@ -64,15 +69,3 @@ ruff = "^0.5" [tool.poetry.group.typing.dependencies] mypy = "^1.10" - -[tool.poetry.group.test.dependencies.langchain-core] -path = "../../core" -develop = true - -[tool.poetry.group.dev.dependencies.langchain-core] -path = "../../core" -develop = true - -[tool.poetry.group.typing.dependencies.langchain-core] -path = "../../core" -develop = true diff --git a/libs/cli/langchain_cli/integration_template/tests/integration_tests/test_chat_models.py b/libs/cli/langchain_cli/integration_template/tests/integration_tests/test_chat_models.py index 26b63bd706b..c84dafa973a 100644 --- a/libs/cli/langchain_cli/integration_template/tests/integration_tests/test_chat_models.py +++ b/libs/cli/langchain_cli/integration_template/tests/integration_tests/test_chat_models.py @@ -1,64 +1,21 @@ """Test Chat__ModuleName__ chat model.""" +from typing import Type + from __module_name__.chat_models import Chat__ModuleName__ +from langchain_tests.integration_tests import ChatModelIntegrationTests -def test_stream() -> None: - """Test streaming tokens from OpenAI.""" - llm = Chat__ModuleName__() +class TestChatParrotLinkIntegration(ChatModelIntegrationTests): + @property + def chat_model_class(self) -> Type[Chat__ModuleName__]: + return Chat__ModuleName__ - for token in llm.stream("I'm Pickle Rick"): - assert isinstance(token.content, str) - - -async def test_astream() -> None: - """Test streaming tokens from OpenAI.""" - llm = Chat__ModuleName__() - - async for token in llm.astream("I'm Pickle Rick"): - assert isinstance(token.content, str) - - -async def test_abatch() -> None: - """Test streaming tokens from Chat__ModuleName__.""" - llm = Chat__ModuleName__() - - result = await llm.abatch(["I'm Pickle Rick", "I'm not Pickle Rick"]) - for token in result: - assert isinstance(token.content, str) - - -async def test_abatch_tags() -> None: - """Test batch tokens from Chat__ModuleName__.""" - llm = Chat__ModuleName__() - - result = await llm.abatch( - ["I'm Pickle Rick", "I'm not Pickle Rick"], config={"tags": ["foo"]} - ) - for token in result: - assert isinstance(token.content, str) - - -def test_batch() -> None: - """Test batch tokens from Chat__ModuleName__.""" - llm = Chat__ModuleName__() - - result = llm.batch(["I'm Pickle Rick", "I'm not Pickle Rick"]) - for token in result: - assert isinstance(token.content, str) - - -async def test_ainvoke() -> None: - """Test invoke tokens from Chat__ModuleName__.""" - llm = Chat__ModuleName__() - - result = await llm.ainvoke("I'm Pickle Rick", config={"tags": ["foo"]}) - assert isinstance(result.content, str) - - -def test_invoke() -> None: - """Test invoke tokens from Chat__ModuleName__.""" - llm = Chat__ModuleName__() - - result = llm.invoke("I'm Pickle Rick", config=dict(tags=["foo"])) - assert isinstance(result.content, str) + @property + def chat_model_params(self) -> dict: + # These should be parameters used to initialize your integration for testing + return { + "model": "bird-brain-001", + "temperature": 0, + "parrot_buffer_length": 50, + } diff --git a/libs/cli/langchain_cli/integration_template/tests/integration_tests/test_embeddings.py b/libs/cli/langchain_cli/integration_template/tests/integration_tests/test_embeddings.py index 51937d157d2..f7bd526d04b 100644 --- a/libs/cli/langchain_cli/integration_template/tests/integration_tests/test_embeddings.py +++ b/libs/cli/langchain_cli/integration_template/tests/integration_tests/test_embeddings.py @@ -1,20 +1,16 @@ """Test __ModuleName__ embeddings.""" +from typing import Type + from __module_name__.embeddings import __ModuleName__Embeddings +from langchain_tests.integration_tests import EmbeddingsIntegrationTests -def test___module_name___embedding_documents() -> None: - """Test cohere embeddings.""" - documents = ["foo bar"] - embedding = __ModuleName__Embeddings() - output = embedding.embed_documents(documents) - assert len(output) == 1 - assert len(output[0]) > 0 +class TestParrotLinkEmbeddingsIntegration(EmbeddingsIntegrationTests): + @property + def embeddings_class(self) -> Type[__ModuleName__Embeddings]: + return __ModuleName__Embeddings - -def test___module_name___embedding_query() -> None: - """Test cohere embeddings.""" - document = "foo bar" - embedding = __ModuleName__Embeddings() - output = embedding.embed_query(document) - assert len(output) > 0 + @property + def embedding_model_params(self) -> dict: + return {"model": "nest-embed-001"} diff --git a/libs/cli/langchain_cli/integration_template/tests/integration_tests/test_llms.py b/libs/cli/langchain_cli/integration_template/tests/integration_tests/test_llms.py deleted file mode 100644 index 9fd6e0a628e..00000000000 --- a/libs/cli/langchain_cli/integration_template/tests/integration_tests/test_llms.py +++ /dev/null @@ -1,64 +0,0 @@ -"""Test __ModuleName__LLM llm.""" - -from __module_name__.llms import __ModuleName__LLM - - -def test_stream() -> None: - """Test streaming tokens from OpenAI.""" - llm = __ModuleName__LLM() - - for token in llm.stream("I'm Pickle Rick"): - assert isinstance(token, str) - - -async def test_astream() -> None: - """Test streaming tokens from OpenAI.""" - llm = __ModuleName__LLM() - - async for token in llm.astream("I'm Pickle Rick"): - assert isinstance(token, str) - - -async def test_abatch() -> None: - """Test streaming tokens from __ModuleName__LLM.""" - llm = __ModuleName__LLM() - - result = await llm.abatch(["I'm Pickle Rick", "I'm not Pickle Rick"]) - for token in result: - assert isinstance(token, str) - - -async def test_abatch_tags() -> None: - """Test batch tokens from __ModuleName__LLM.""" - llm = __ModuleName__LLM() - - result = await llm.abatch( - ["I'm Pickle Rick", "I'm not Pickle Rick"], config={"tags": ["foo"]} - ) - for token in result: - assert isinstance(token, str) - - -def test_batch() -> None: - """Test batch tokens from __ModuleName__LLM.""" - llm = __ModuleName__LLM() - - result = llm.batch(["I'm Pickle Rick", "I'm not Pickle Rick"]) - for token in result: - assert isinstance(token, str) - - -async def test_ainvoke() -> None: - """Test invoke tokens from __ModuleName__LLM.""" - llm = __ModuleName__LLM() - - result = await llm.ainvoke("I'm Pickle Rick", config={"tags": ["foo"]}) - assert isinstance(result, str) - - -def test_invoke() -> None: - """Test invoke tokens from __ModuleName__LLM.""" - llm = __ModuleName__LLM() - - result = llm.invoke("I'm Pickle Rick", config=dict(tags=["foo"])) - assert isinstance(result, str) diff --git a/libs/cli/langchain_cli/integration_template/tests/integration_tests/test_retrievers.py b/libs/cli/langchain_cli/integration_template/tests/integration_tests/test_retrievers.py new file mode 100644 index 00000000000..487c4a41cd7 --- /dev/null +++ b/libs/cli/langchain_cli/integration_template/tests/integration_tests/test_retrievers.py @@ -0,0 +1,24 @@ +from typing import Type + +from __module_name__.retrievers import __ModuleName__Retriever +from langchain_tests.integration_tests import ( + RetrieversIntegrationTests, +) + + +class Test__ModuleName__Retriever(RetrieversIntegrationTests): + @property + def retriever_constructor(self) -> Type[__ModuleName__Retriever]: + """Get an empty vectorstore for unit tests.""" + return __ModuleName__Retriever + + @property + def retriever_constructor_params(self) -> dict: + return {"k": 2} + + @property + def retriever_query_example(self) -> str: + """ + Returns a dictionary representing the "args" of an example retriever call. + """ + return "example query" diff --git a/libs/cli/langchain_cli/integration_template/tests/integration_tests/test_tools.py b/libs/cli/langchain_cli/integration_template/tests/integration_tests/test_tools.py new file mode 100644 index 00000000000..529bd7fe7ea --- /dev/null +++ b/libs/cli/langchain_cli/integration_template/tests/integration_tests/test_tools.py @@ -0,0 +1,27 @@ +from typing import Type + +from __module_name__.tools import __ModuleName__Tool +from langchain_tests.integration_tests import ToolsIntegrationTests + + +class TestParrotMultiplyToolIntegration(ToolsIntegrationTests): + @property + def tool_constructor(self) -> Type[__ModuleName__Tool]: + return __ModuleName__Tool + + @property + def tool_constructor_params(self) -> dict: + # if your tool constructor instead required initialization arguments like + # `def __init__(self, some_arg: int):`, you would return those here + # as a dictionary, e.g.: `return {'some_arg': 42}` + return {} + + @property + def tool_invoke_params_example(self) -> dict: + """ + Returns a dictionary representing the "args" of an example tool call. + + This should NOT be a ToolCall dict - i.e. it should not + have {"name", "id", "args"} keys. + """ + return {"a": 2, "b": 3} diff --git a/libs/cli/langchain_cli/integration_template/tests/integration_tests/test_vectorstores.py b/libs/cli/langchain_cli/integration_template/tests/integration_tests/test_vectorstores.py new file mode 100644 index 00000000000..2d0820348a3 --- /dev/null +++ b/libs/cli/langchain_cli/integration_template/tests/integration_tests/test_vectorstores.py @@ -0,0 +1,37 @@ +from typing import AsyncGenerator, Generator + +import pytest +from __module_name__.vectorstores import __ModuleName__VectorStore +from langchain_core.vectorstores import VectorStore +from langchain_tests.integration_tests import ( + AsyncReadWriteTestSuite, + ReadWriteTestSuite, +) + + +class Test__ModuleName__VectorStoreSync(ReadWriteTestSuite): + @pytest.fixture() + def vectorstore(self) -> Generator[VectorStore, None, None]: # type: ignore + """Get an empty vectorstore for unit tests.""" + store = __ModuleName__VectorStore() + # note: store should be EMPTY at this point + # if you need to delete data, you may do so here + try: + yield store + finally: + # cleanup operations, or deleting data + pass + + +class Test__ModuleName__VectorStoreAsync(AsyncReadWriteTestSuite): + @pytest.fixture() + async def vectorstore(self) -> AsyncGenerator[VectorStore, None]: # type: ignore + """Get an empty vectorstore for unit tests.""" + store = __ModuleName__VectorStore() + # note: store should be EMPTY at this point + # if you need to delete data, you may do so here + try: + yield store + finally: + # cleanup operations, or deleting data + pass diff --git a/libs/cli/langchain_cli/integration_template/tests/unit_tests/test_chat_models.py b/libs/cli/langchain_cli/integration_template/tests/unit_tests/test_chat_models.py index 70cc82c75dc..c83081a4479 100644 --- a/libs/cli/langchain_cli/integration_template/tests/unit_tests/test_chat_models.py +++ b/libs/cli/langchain_cli/integration_template/tests/unit_tests/test_chat_models.py @@ -1,8 +1,21 @@ """Test chat model integration.""" +from typing import Type + from __module_name__.chat_models import Chat__ModuleName__ +from langchain_tests.unit_tests import ChatModelUnitTests -def test_initialization() -> None: - """Test chat model initialization.""" - Chat__ModuleName__() +class TestChat__ModuleName__Unit(ChatModelUnitTests): + @property + def chat_model_class(self) -> Type[Chat__ModuleName__]: + return Chat__ModuleName__ + + @property + def chat_model_params(self) -> dict: + # These should be parameters used to initialize your integration for testing + return { + "model": "bird-brain-001", + "temperature": 0, + "parrot_buffer_length": 50, + } diff --git a/libs/cli/langchain_cli/integration_template/tests/unit_tests/test_embeddings.py b/libs/cli/langchain_cli/integration_template/tests/unit_tests/test_embeddings.py index ab4f45a9b73..5fdf8feb083 100644 --- a/libs/cli/langchain_cli/integration_template/tests/unit_tests/test_embeddings.py +++ b/libs/cli/langchain_cli/integration_template/tests/unit_tests/test_embeddings.py @@ -1,8 +1,16 @@ """Test embedding model integration.""" +from typing import Type + from __module_name__.embeddings import __ModuleName__Embeddings +from langchain_tests.unit_tests import EmbeddingsUnitTests -def test_initialization() -> None: - """Test embedding model initialization.""" - __ModuleName__Embeddings() +class TestParrotLinkEmbeddingsUnit(EmbeddingsUnitTests): + @property + def embeddings_class(self) -> Type[__ModuleName__Embeddings]: + return __ModuleName__Embeddings + + @property + def embedding_model_params(self) -> dict: + return {"model": "nest-embed-001"} diff --git a/libs/cli/langchain_cli/integration_template/tests/unit_tests/test_imports.py b/libs/cli/langchain_cli/integration_template/tests/unit_tests/test_imports.py deleted file mode 100644 index 1dfa3389141..00000000000 --- a/libs/cli/langchain_cli/integration_template/tests/unit_tests/test_imports.py +++ /dev/null @@ -1,12 +0,0 @@ -from __module_name__ import __all__ - -EXPECTED_ALL = [ - "__ModuleName__LLM", - "Chat__ModuleName__", - "__ModuleName__VectorStore", - "__ModuleName__Embeddings", -] - - -def test_all_imports() -> None: - assert sorted(EXPECTED_ALL) == sorted(__all__) diff --git a/libs/cli/langchain_cli/integration_template/tests/unit_tests/test_llms.py b/libs/cli/langchain_cli/integration_template/tests/unit_tests/test_llms.py deleted file mode 100644 index 7d53dad10ac..00000000000 --- a/libs/cli/langchain_cli/integration_template/tests/unit_tests/test_llms.py +++ /dev/null @@ -1,8 +0,0 @@ -"""Test __ModuleName__ Chat API wrapper.""" - -from __module_name__ import __ModuleName__LLM - - -def test_initialization() -> None: - """Test integration initialization.""" - __ModuleName__LLM() diff --git a/libs/cli/langchain_cli/integration_template/tests/unit_tests/test_tools.py b/libs/cli/langchain_cli/integration_template/tests/unit_tests/test_tools.py new file mode 100644 index 00000000000..23231276d41 --- /dev/null +++ b/libs/cli/langchain_cli/integration_template/tests/unit_tests/test_tools.py @@ -0,0 +1,27 @@ +from typing import Type + +from __module_name__.tools import __ModuleName__Tool +from langchain_tests.unit_tests import ToolsUnitTests + + +class TestParrotMultiplyToolUnit(ToolsUnitTests): + @property + def tool_constructor(self) -> Type[__ModuleName__Tool]: + return __ModuleName__Tool + + @property + def tool_constructor_params(self) -> dict: + # if your tool constructor instead required initialization arguments like + # `def __init__(self, some_arg: int):`, you would return those here + # as a dictionary, e.g.: `return {'some_arg': 42}` + return {} + + @property + def tool_invoke_params_example(self) -> dict: + """ + Returns a dictionary representing the "args" of an example tool call. + + This should NOT be a ToolCall dict - i.e. it should not + have {"name", "id", "args"} keys. + """ + return {"a": 2, "b": 3} diff --git a/libs/cli/langchain_cli/integration_template/tests/unit_tests/test_vectorstores.py b/libs/cli/langchain_cli/integration_template/tests/unit_tests/test_vectorstores.py deleted file mode 100644 index 6c044a9a66f..00000000000 --- a/libs/cli/langchain_cli/integration_template/tests/unit_tests/test_vectorstores.py +++ /dev/null @@ -1,6 +0,0 @@ -from __module_name__.vectorstores import __ModuleName__VectorStore - - -def test_initialization() -> None: - """Test integration vectorstore initialization.""" - __ModuleName__VectorStore() diff --git a/libs/cli/langchain_cli/namespaces/integration.py b/libs/cli/langchain_cli/namespaces/integration.py index e78af97c25d..eca98043585 100644 --- a/libs/cli/langchain_cli/namespaces/integration.py +++ b/libs/cli/langchain_cli/namespaces/integration.py @@ -6,7 +6,7 @@ import re import shutil import subprocess from pathlib import Path -from typing import Optional +from typing import Dict, Optional, cast import typer from typing_extensions import Annotated, TypedDict @@ -15,19 +15,17 @@ from langchain_cli.utils.find_replace import replace_file, replace_glob integration_cli = typer.Typer(no_args_is_help=True, add_completion=False) -Replacements = TypedDict( - "Replacements", - { - "__package_name__": str, - "__module_name__": str, - "__ModuleName__": str, - "__MODULE_NAME__": str, - "__package_name_short__": str, - }, -) + +class Replacements(TypedDict): + __package_name__: str + __module_name__: str + __ModuleName__: str + __MODULE_NAME__: str + __package_name_short__: str + __package_name_short_snake__: str -def _process_name(name: str, *, community: bool = False): +def _process_name(name: str, *, community: bool = False) -> Replacements: preprocessed = name.replace("_", "-").lower() if preprocessed.startswith("langchain-"): @@ -42,7 +40,7 @@ def _process_name(name: str, *, community: bool = False): raise ValueError("Name should not end with `-`.") if preprocessed.find("--") != -1: raise ValueError("Name should not contain consecutive hyphens.") - replacements = { + replacements: Replacements = { "__package_name__": f"langchain-{preprocessed}", "__module_name__": "langchain_" + preprocessed.replace("-", "_"), "__ModuleName__": preprocessed.title().replace("-", ""), @@ -52,7 +50,7 @@ def _process_name(name: str, *, community: bool = False): } if community: replacements["__module_name__"] = preprocessed.replace("-", "_") - return Replacements(replacements) + return replacements @integration_cli.command() @@ -74,16 +72,7 @@ def new( ): """ Creates a new integration package. - - Should be run from libs/partners """ - # confirm that we are in the right directory - if not Path.cwd().name == "partners" or not Path.cwd().parent.name == "libs": - typer.echo( - "This command should be run from the `libs/partners` directory in the " - "langchain-ai/langchain monorepo. Continuing is NOT recommended." - ) - typer.confirm("Are you sure you want to continue?", abort=True) try: replacements = _process_name(name) @@ -104,7 +93,7 @@ def new( "Name of integration in PascalCase", default=replacements["__ModuleName__"] ) - destination_dir = Path.cwd() / replacements["__package_name_short__"] + destination_dir = Path.cwd() / replacements["__package_name__"] if destination_dir.exists(): typer.echo(f"Folder {destination_dir} exists.") raise typer.Exit(code=1) @@ -118,7 +107,7 @@ def new( shutil.move(destination_dir / "integration_template", package_dir) # replacements in files - replace_glob(destination_dir, "**/*", replacements) + replace_glob(destination_dir, "**/*", cast(Dict[str, str], replacements)) # poetry install subprocess.run( @@ -226,4 +215,4 @@ def create_doc( shutil.copy(docs_template, destination_path) # replacements in file - replace_file(destination_path, replacements) + replace_file(destination_path, cast(Dict[str, str], replacements)) diff --git a/libs/cli/langchain_cli/namespaces/migrate/generate/utils.py b/libs/cli/langchain_cli/namespaces/migrate/generate/utils.py index 57fd457f19e..51b8b79bd3b 100644 --- a/libs/cli/langchain_cli/namespaces/migrate/generate/utils.py +++ b/libs/cli/langchain_cli/namespaces/migrate/generate/utils.py @@ -17,7 +17,7 @@ PARTNER_PKGS = PKGS_ROOT / "partners" class ImportExtractor(ast.NodeVisitor): def __init__(self, *, from_package: Optional[str] = None) -> None: """Extract all imports from the given code, optionally filtering by package.""" - self.imports = [] + self.imports: list = [] self.package = from_package def visit_ImportFrom(self, node): @@ -68,7 +68,7 @@ def find_subclasses_in_module(module, classes_: List[Type]) -> List[str]: return subclasses -def _get_all_classnames_from_file(file: str, pkg: str) -> List[Tuple[str, str]]: +def _get_all_classnames_from_file(file: Path, pkg: str) -> List[Tuple[str, str]]: """Extract all class names from a file.""" with open(file, encoding="utf-8") as f: code = f.read() @@ -145,7 +145,7 @@ def find_imports_from_package( return extractor.imports -def _get_current_module(path: str, pkg_root: str) -> str: +def _get_current_module(path: Path, pkg_root: str) -> str: """Convert a path to a module name.""" path_as_pathlib = pathlib.Path(os.path.abspath(path)) relative_path = path_as_pathlib.relative_to(pkg_root).with_suffix("") diff --git a/libs/cli/langchain_cli/namespaces/migrate/main.py b/libs/cli/langchain_cli/namespaces/migrate/main.py index 483fa9f6ea6..0956f9d4f68 100644 --- a/libs/cli/langchain_cli/namespaces/migrate/main.py +++ b/libs/cli/langchain_cli/namespaces/migrate/main.py @@ -4,7 +4,7 @@ from pathlib import Path import rich import typer -from gritql import run +from gritql import run # type: ignore from typer import Option diff --git a/libs/cli/langchain_cli/utils/find_replace.py b/libs/cli/langchain_cli/utils/find_replace.py index cfea68d3dfa..12cb9bb4a13 100644 --- a/libs/cli/langchain_cli/utils/find_replace.py +++ b/libs/cli/langchain_cli/utils/find_replace.py @@ -13,7 +13,7 @@ def find_and_replace(source: str, replacements: Dict[str, str]) -> str: return rtn -def replace_file(source: Path, replacements: Dict[str, str]) -> None: +def replace_file(source: Path, replacements: dict[str, str]) -> None: try: content = source.read_text() except UnicodeDecodeError: @@ -24,7 +24,7 @@ def replace_file(source: Path, replacements: Dict[str, str]) -> None: source.write_text(new_content) -def replace_glob(parent: Path, glob: str, replacements: Dict[str, str]) -> None: +def replace_glob(parent: Path, glob: str, replacements: dict[str, str]) -> None: for file in parent.glob(glob): if not file.is_file(): continue diff --git a/libs/cli/poetry.lock b/libs/cli/poetry.lock index d2026cb3a11..c53e81acdd0 100644 --- a/libs/cli/poetry.lock +++ b/libs/cli/poetry.lock @@ -1,5 +1,128 @@ # This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. +[[package]] +name = "aiohappyeyeballs" +version = "2.4.4" +description = "Happy Eyeballs for asyncio" +optional = false +python-versions = ">=3.8" +files = [ + {file = "aiohappyeyeballs-2.4.4-py3-none-any.whl", hash = "sha256:a980909d50efcd44795c4afeca523296716d50cd756ddca6af8c65b996e27de8"}, + {file = "aiohappyeyeballs-2.4.4.tar.gz", hash = "sha256:5fdd7d87889c63183afc18ce9271f9b0a7d32c2303e394468dd45d514a757745"}, +] + +[[package]] +name = "aiohttp" +version = "3.11.9" +description = "Async http client/server framework (asyncio)" +optional = false +python-versions = ">=3.9" +files = [ + {file = "aiohttp-3.11.9-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:0411777249f25d11bd2964a230b3ffafcbed6cd65d0f2b132bc2b8f5b8c347c7"}, + {file = "aiohttp-3.11.9-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:499368eb904566fbdf1a3836a1532000ef1308f34a1bcbf36e6351904cced771"}, + {file = "aiohttp-3.11.9-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0b5a5009b0159a8f707879dc102b139466d8ec6db05103ec1520394fdd8ea02c"}, + {file = "aiohttp-3.11.9-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:176f8bb8931da0613bb0ed16326d01330066bb1e172dd97e1e02b1c27383277b"}, + {file = "aiohttp-3.11.9-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6435a66957cdba1a0b16f368bde03ce9c79c57306b39510da6ae5312a1a5b2c1"}, + {file = "aiohttp-3.11.9-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:202f40fb686e5f93908eee0c75d1e6fbe50a43e9bd4909bf3bf4a56b560ca180"}, + {file = "aiohttp-3.11.9-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:39625703540feb50b6b7f938b3856d1f4886d2e585d88274e62b1bd273fae09b"}, + {file = "aiohttp-3.11.9-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c6beeac698671baa558e82fa160be9761cf0eb25861943f4689ecf9000f8ebd0"}, + {file = "aiohttp-3.11.9-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:96726839a42429318017e67a42cca75d4f0d5248a809b3cc2e125445edd7d50d"}, + {file = "aiohttp-3.11.9-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:3f5461c77649358610fb9694e790956b4238ac5d9e697a17f63619c096469afe"}, + {file = "aiohttp-3.11.9-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:4313f3bc901255b22f01663eeeae167468264fdae0d32c25fc631d5d6e15b502"}, + {file = "aiohttp-3.11.9-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:d6e274661c74195708fc4380a4ef64298926c5a50bb10fbae3d01627d7a075b7"}, + {file = "aiohttp-3.11.9-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:db2914de2559809fdbcf3e48f41b17a493b58cb7988d3e211f6b63126c55fe82"}, + {file = "aiohttp-3.11.9-cp310-cp310-win32.whl", hash = "sha256:27935716f8d62c1c73010428db310fd10136002cfc6d52b0ba7bdfa752d26066"}, + {file = "aiohttp-3.11.9-cp310-cp310-win_amd64.whl", hash = "sha256:afbe85b50ade42ddff5669947afde9e8a610e64d2c80be046d67ec4368e555fa"}, + {file = "aiohttp-3.11.9-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:afcda759a69c6a8be3aae764ec6733155aa4a5ad9aad4f398b52ba4037942fe3"}, + {file = "aiohttp-3.11.9-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c5bba6b83fde4ca233cfda04cbd4685ab88696b0c8eaf76f7148969eab5e248a"}, + {file = "aiohttp-3.11.9-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:442356e8924fe1a121f8c87866b0ecdc785757fd28924b17c20493961b3d6697"}, + {file = "aiohttp-3.11.9-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f737fef6e117856400afee4f17774cdea392b28ecf058833f5eca368a18cf1bf"}, + {file = "aiohttp-3.11.9-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ea142255d4901b03f89cb6a94411ecec117786a76fc9ab043af8f51dd50b5313"}, + {file = "aiohttp-3.11.9-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6e1e9e447856e9b7b3d38e1316ae9a8c92e7536ef48373de758ea055edfd5db5"}, + {file = "aiohttp-3.11.9-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e7f6173302f8a329ca5d1ee592af9e628d3ade87816e9958dcf7cdae2841def7"}, + {file = "aiohttp-3.11.9-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a7c6147c6306f537cff59409609508a1d2eff81199f0302dd456bb9e7ea50c39"}, + {file = "aiohttp-3.11.9-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:e9d036a9a41fc78e8a3f10a86c2fc1098fca8fab8715ba9eb999ce4788d35df0"}, + {file = "aiohttp-3.11.9-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:2ac9fd83096df36728da8e2f4488ac3b5602238f602706606f3702f07a13a409"}, + {file = "aiohttp-3.11.9-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:d3108f0ad5c6b6d78eec5273219a5bbd884b4aacec17883ceefaac988850ce6e"}, + {file = "aiohttp-3.11.9-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:96bbec47beb131bbf4bae05d8ef99ad9e5738f12717cfbbf16648b78b0232e87"}, + {file = "aiohttp-3.11.9-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:fc726c3fa8f606d07bd2b500e5dc4c0fd664c59be7788a16b9e34352c50b6b6b"}, + {file = "aiohttp-3.11.9-cp311-cp311-win32.whl", hash = "sha256:5720ebbc7a1b46c33a42d489d25d36c64c419f52159485e55589fbec648ea49a"}, + {file = "aiohttp-3.11.9-cp311-cp311-win_amd64.whl", hash = "sha256:17af09d963fa1acd7e4c280e9354aeafd9e3d47eaa4a6bfbd2171ad7da49f0c5"}, + {file = "aiohttp-3.11.9-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:c1f2d7fd583fc79c240094b3e7237d88493814d4b300d013a42726c35a734bc9"}, + {file = "aiohttp-3.11.9-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d4b8a1b6c7a68c73191f2ebd3bf66f7ce02f9c374e309bdb68ba886bbbf1b938"}, + {file = "aiohttp-3.11.9-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:bd3f711f4c99da0091ced41dccdc1bcf8be0281dc314d6d9c6b6cf5df66f37a9"}, + {file = "aiohttp-3.11.9-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:44cb1a1326a0264480a789e6100dc3e07122eb8cd1ad6b784a3d47d13ed1d89c"}, + {file = "aiohttp-3.11.9-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7a7ddf981a0b953ade1c2379052d47ccda2f58ab678fca0671c7c7ca2f67aac2"}, + {file = "aiohttp-3.11.9-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6ffa45cc55b18d4ac1396d1ddb029f139b1d3480f1594130e62bceadf2e1a838"}, + {file = "aiohttp-3.11.9-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cca505829cdab58c2495ff418c96092d225a1bbd486f79017f6de915580d3c44"}, + {file = "aiohttp-3.11.9-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:44d323aa80a867cb6db6bebb4bbec677c6478e38128847f2c6b0f70eae984d72"}, + {file = "aiohttp-3.11.9-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b2fab23003c4bb2249729a7290a76c1dda38c438300fdf97d4e42bf78b19c810"}, + {file = "aiohttp-3.11.9-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:be0c7c98e38a1e3ad7a6ff64af8b6d6db34bf5a41b1478e24c3c74d9e7f8ed42"}, + {file = "aiohttp-3.11.9-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:5cc5e0d069c56645446c45a4b5010d4b33ac6c5ebfd369a791b5f097e46a3c08"}, + {file = "aiohttp-3.11.9-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:9bcf97b971289be69638d8b1b616f7e557e1342debc7fc86cf89d3f08960e411"}, + {file = "aiohttp-3.11.9-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c7333e7239415076d1418dbfb7fa4df48f3a5b00f8fdf854fca549080455bc14"}, + {file = "aiohttp-3.11.9-cp312-cp312-win32.whl", hash = "sha256:9384b07cfd3045b37b05ed002d1c255db02fb96506ad65f0f9b776b762a7572e"}, + {file = "aiohttp-3.11.9-cp312-cp312-win_amd64.whl", hash = "sha256:f5252ba8b43906f206048fa569debf2cd0da0316e8d5b4d25abe53307f573941"}, + {file = "aiohttp-3.11.9-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:282e0a7ddd36ebc411f156aeaa0491e8fe7f030e2a95da532cf0c84b0b70bc66"}, + {file = "aiohttp-3.11.9-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ebd3e6b0c7d4954cca59d241970011f8d3327633d555051c430bd09ff49dc494"}, + {file = "aiohttp-3.11.9-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:30f9f89ae625d412043f12ca3771b2ccec227cc93b93bb1f994db6e1af40a7d3"}, + {file = "aiohttp-3.11.9-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7a3b5b2c012d70c63d9d13c57ed1603709a4d9d7d473e4a9dfece0e4ea3d5f51"}, + {file = "aiohttp-3.11.9-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6ef1550bb5f55f71b97a6a395286db07f7f2c01c8890e613556df9a51da91e8d"}, + {file = "aiohttp-3.11.9-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:317251b9c9a2f1a9ff9cd093775b34c6861d1d7df9439ce3d32a88c275c995cd"}, + {file = "aiohttp-3.11.9-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21cbe97839b009826a61b143d3ca4964c8590d7aed33d6118125e5b71691ca46"}, + {file = "aiohttp-3.11.9-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:618b18c3a2360ac940a5503da14fa4f880c5b9bc315ec20a830357bcc62e6bae"}, + {file = "aiohttp-3.11.9-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a0cf4d814689e58f57ecd5d8c523e6538417ca2e72ff52c007c64065cef50fb2"}, + {file = "aiohttp-3.11.9-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:15c4e489942d987d5dac0ba39e5772dcbed4cc9ae3710d1025d5ba95e4a5349c"}, + {file = "aiohttp-3.11.9-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:ec8df0ff5a911c6d21957a9182402aad7bf060eaeffd77c9ea1c16aecab5adbf"}, + {file = "aiohttp-3.11.9-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:ed95d66745f53e129e935ad726167d3a6cb18c5d33df3165974d54742c373868"}, + {file = "aiohttp-3.11.9-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:647ec5bee7e4ec9f1034ab48173b5fa970d9a991e565549b965e93331f1328fe"}, + {file = "aiohttp-3.11.9-cp313-cp313-win32.whl", hash = "sha256:ef2c9499b7bd1e24e473dc1a85de55d72fd084eea3d8bdeec7ee0720decb54fa"}, + {file = "aiohttp-3.11.9-cp313-cp313-win_amd64.whl", hash = "sha256:84de955314aa5e8d469b00b14d6d714b008087a0222b0f743e7ffac34ef56aff"}, + {file = "aiohttp-3.11.9-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e738aabff3586091221044b7a584865ddc4d6120346d12e28e788307cd731043"}, + {file = "aiohttp-3.11.9-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:28f29bce89c3b401a53d6fd4bee401ee943083bf2bdc12ef297c1d63155070b0"}, + {file = "aiohttp-3.11.9-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:31de2f10f63f96cc19e04bd2df9549559beadd0b2ee2da24a17e7ed877ca8c60"}, + {file = "aiohttp-3.11.9-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77f31cebd8c27a36af6c7346055ac564946e562080ee1a838da724585c67474f"}, + {file = "aiohttp-3.11.9-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0bcb7f6976dc0b6b56efde13294862adf68dd48854111b422a336fa729a82ea6"}, + {file = "aiohttp-3.11.9-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1a8b13b9950d8b2f8f58b6e5842c4b842b5887e2c32e3f4644d6642f1659a530"}, + {file = "aiohttp-3.11.9-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c9c23e62f3545c2216100603614f9e019e41b9403c47dd85b8e7e5015bf1bde0"}, + {file = "aiohttp-3.11.9-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ec656680fc53a13f849c71afd0c84a55c536206d524cbc831cde80abbe80489e"}, + {file = "aiohttp-3.11.9-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:36df00e0541f264ce42d62280281541a47474dfda500bc5b7f24f70a7f87be7a"}, + {file = "aiohttp-3.11.9-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:8dcfd14c712aa9dd18049280bfb2f95700ff6a8bde645e09f17c3ed3f05a0130"}, + {file = "aiohttp-3.11.9-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:14624d96f0d69cf451deed3173079a68c322279be6030208b045ab77e1e8d550"}, + {file = "aiohttp-3.11.9-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:4b01d9cfcb616eeb6d40f02e66bebfe7b06d9f2ef81641fdd50b8dd981166e0b"}, + {file = "aiohttp-3.11.9-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:928f92f80e2e8d6567b87d3316c1fd9860ccfe36e87a9a7f5237d4cda8baa1ba"}, + {file = "aiohttp-3.11.9-cp39-cp39-win32.whl", hash = "sha256:c8a02f74ae419e3955af60f570d83187423e42e672a6433c5e292f1d23619269"}, + {file = "aiohttp-3.11.9-cp39-cp39-win_amd64.whl", hash = "sha256:0a97d657f6cf8782a830bb476c13f7d777cfcab8428ac49dde15c22babceb361"}, + {file = "aiohttp-3.11.9.tar.gz", hash = "sha256:a9266644064779840feec0e34f10a89b3ff1d2d6b751fe90017abcad1864fa7c"}, +] + +[package.dependencies] +aiohappyeyeballs = ">=2.3.0" +aiosignal = ">=1.1.2" +async-timeout = {version = ">=4.0,<6.0", markers = "python_version < \"3.11\""} +attrs = ">=17.3.0" +frozenlist = ">=1.1.1" +multidict = ">=4.5,<7.0" +propcache = ">=0.2.0" +yarl = ">=1.17.0,<2.0" + +[package.extras] +speedups = ["Brotli", "aiodns (>=3.2.0)", "brotlicffi"] + +[[package]] +name = "aiosignal" +version = "1.3.1" +description = "aiosignal: a list of registered asynchronous callbacks" +optional = false +python-versions = ">=3.7" +files = [ + {file = "aiosignal-1.3.1-py3-none-any.whl", hash = "sha256:f8376fb07dd1e86a584e4fcdec80b36b7f81aac666ebc724e2c090300dd83b17"}, + {file = "aiosignal-1.3.1.tar.gz", hash = "sha256:54cd96e15e1649b75d6c87526a6ff0b6c1b0dd3459f43d9ca11d48c339b68cfc"}, +] + +[package.dependencies] +frozenlist = ">=1.1.0" + [[package]] name = "annotated-types" version = "0.7.0" @@ -33,6 +156,36 @@ doc = ["Sphinx (>=7.4,<8.0)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", 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", "truststore (>=0.9.1)", "uvloop (>=0.21.0b1)"] trio = ["trio (>=0.26.1)"] +[[package]] +name = "async-timeout" +version = "4.0.3" +description = "Timeout context manager for asyncio programs" +optional = false +python-versions = ">=3.7" +files = [ + {file = "async-timeout-4.0.3.tar.gz", hash = "sha256:4640d96be84d82d02ed59ea2b7105a0f7b33abe8703703cd0ab0bf87c427522f"}, + {file = "async_timeout-4.0.3-py3-none-any.whl", hash = "sha256:7405140ff1230c310e51dc27b3145b9092d659ce68ff733fb0cefe3ee42be028"}, +] + +[[package]] +name = "attrs" +version = "24.2.0" +description = "Classes Without Boilerplate" +optional = false +python-versions = ">=3.7" +files = [ + {file = "attrs-24.2.0-py3-none-any.whl", hash = "sha256:81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2"}, + {file = "attrs-24.2.0.tar.gz", hash = "sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346"}, +] + +[package.extras] +benchmark = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-codspeed", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +cov = ["cloudpickle", "coverage[toml] (>=5.3)", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +dev = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pre-commit", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +docs = ["cogapp", "furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier (<24.7)"] +tests = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +tests-mypy = ["mypy (>=1.11.1)", "pytest-mypy-plugins"] + [[package]] name = "certifi" version = "2024.8.30" @@ -209,13 +362,13 @@ test = ["pytest (>=6)"] [[package]] name = "fastapi" -version = "0.115.5" +version = "0.115.6" description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" optional = false python-versions = ">=3.8" files = [ - {file = "fastapi-0.115.5-py3-none-any.whl", hash = "sha256:596b95adbe1474da47049e802f9a65ab2ffa9c2b07e7efee70eb8a66c9f2f796"}, - {file = "fastapi-0.115.5.tar.gz", hash = "sha256:0e7a4d0dc0d01c68df21887cce0945e72d3c48b9f4f79dfe7a7d53aa08fbb289"}, + {file = "fastapi-0.115.6-py3-none-any.whl", hash = "sha256:e9240b29e36fa8f4bb7290316988e90c381e5092e0cbe84e7818cc3713bcf305"}, + {file = "fastapi-0.115.6.tar.gz", hash = "sha256:9ec46f7addc14ea472958a96aae5b5de65f39721a46aaf5705c480d9a8b76654"}, ] [package.dependencies] @@ -227,6 +380,107 @@ typing-extensions = ">=4.8.0" all = ["email-validator (>=2.0.0)", "fastapi-cli[standard] (>=0.0.5)", "httpx (>=0.23.0)", "itsdangerous (>=1.1.0)", "jinja2 (>=2.11.2)", "orjson (>=3.2.1)", "pydantic-extra-types (>=2.0.0)", "pydantic-settings (>=2.0.0)", "python-multipart (>=0.0.7)", "pyyaml (>=5.3.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0)", "uvicorn[standard] (>=0.12.0)"] standard = ["email-validator (>=2.0.0)", "fastapi-cli[standard] (>=0.0.5)", "httpx (>=0.23.0)", "jinja2 (>=2.11.2)", "python-multipart (>=0.0.7)", "uvicorn[standard] (>=0.12.0)"] +[[package]] +name = "frozenlist" +version = "1.5.0" +description = "A list-like structure which implements collections.abc.MutableSequence" +optional = false +python-versions = ">=3.8" +files = [ + {file = "frozenlist-1.5.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:5b6a66c18b5b9dd261ca98dffcb826a525334b2f29e7caa54e182255c5f6a65a"}, + {file = "frozenlist-1.5.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d1b3eb7b05ea246510b43a7e53ed1653e55c2121019a97e60cad7efb881a97bb"}, + {file = "frozenlist-1.5.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:15538c0cbf0e4fa11d1e3a71f823524b0c46299aed6e10ebb4c2089abd8c3bec"}, + {file = "frozenlist-1.5.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e79225373c317ff1e35f210dd5f1344ff31066ba8067c307ab60254cd3a78ad5"}, + {file = "frozenlist-1.5.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9272fa73ca71266702c4c3e2d4a28553ea03418e591e377a03b8e3659d94fa76"}, + {file = "frozenlist-1.5.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:498524025a5b8ba81695761d78c8dd7382ac0b052f34e66939c42df860b8ff17"}, + {file = "frozenlist-1.5.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:92b5278ed9d50fe610185ecd23c55d8b307d75ca18e94c0e7de328089ac5dcba"}, + {file = "frozenlist-1.5.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f3c8c1dacd037df16e85227bac13cca58c30da836c6f936ba1df0c05d046d8d"}, + {file = "frozenlist-1.5.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f2ac49a9bedb996086057b75bf93538240538c6d9b38e57c82d51f75a73409d2"}, + {file = "frozenlist-1.5.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e66cc454f97053b79c2ab09c17fbe3c825ea6b4de20baf1be28919460dd7877f"}, + {file = "frozenlist-1.5.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:5a3ba5f9a0dfed20337d3e966dc359784c9f96503674c2faf015f7fe8e96798c"}, + {file = "frozenlist-1.5.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:6321899477db90bdeb9299ac3627a6a53c7399c8cd58d25da094007402b039ab"}, + {file = "frozenlist-1.5.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:76e4753701248476e6286f2ef492af900ea67d9706a0155335a40ea21bf3b2f5"}, + {file = "frozenlist-1.5.0-cp310-cp310-win32.whl", hash = "sha256:977701c081c0241d0955c9586ffdd9ce44f7a7795df39b9151cd9a6fd0ce4cfb"}, + {file = "frozenlist-1.5.0-cp310-cp310-win_amd64.whl", hash = "sha256:189f03b53e64144f90990d29a27ec4f7997d91ed3d01b51fa39d2dbe77540fd4"}, + {file = "frozenlist-1.5.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:fd74520371c3c4175142d02a976aee0b4cb4a7cc912a60586ffd8d5929979b30"}, + {file = "frozenlist-1.5.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2f3f7a0fbc219fb4455264cae4d9f01ad41ae6ee8524500f381de64ffaa077d5"}, + {file = "frozenlist-1.5.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f47c9c9028f55a04ac254346e92977bf0f166c483c74b4232bee19a6697e4778"}, + {file = "frozenlist-1.5.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0996c66760924da6e88922756d99b47512a71cfd45215f3570bf1e0b694c206a"}, + {file = "frozenlist-1.5.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a2fe128eb4edeabe11896cb6af88fca5346059f6c8d807e3b910069f39157869"}, + {file = "frozenlist-1.5.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1a8ea951bbb6cacd492e3948b8da8c502a3f814f5d20935aae74b5df2b19cf3d"}, + {file = "frozenlist-1.5.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:de537c11e4aa01d37db0d403b57bd6f0546e71a82347a97c6a9f0dcc532b3a45"}, + {file = "frozenlist-1.5.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c2623347b933fcb9095841f1cc5d4ff0b278addd743e0e966cb3d460278840d"}, + {file = "frozenlist-1.5.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:cee6798eaf8b1416ef6909b06f7dc04b60755206bddc599f52232606e18179d3"}, + {file = "frozenlist-1.5.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:f5f9da7f5dbc00a604fe74aa02ae7c98bcede8a3b8b9666f9f86fc13993bc71a"}, + {file = "frozenlist-1.5.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:90646abbc7a5d5c7c19461d2e3eeb76eb0b204919e6ece342feb6032c9325ae9"}, + {file = "frozenlist-1.5.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:bdac3c7d9b705d253b2ce370fde941836a5f8b3c5c2b8fd70940a3ea3af7f4f2"}, + {file = "frozenlist-1.5.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:03d33c2ddbc1816237a67f66336616416e2bbb6beb306e5f890f2eb22b959cdf"}, + {file = "frozenlist-1.5.0-cp311-cp311-win32.whl", hash = "sha256:237f6b23ee0f44066219dae14c70ae38a63f0440ce6750f868ee08775073f942"}, + {file = "frozenlist-1.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:0cc974cc93d32c42e7b0f6cf242a6bd941c57c61b618e78b6c0a96cb72788c1d"}, + {file = "frozenlist-1.5.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:31115ba75889723431aa9a4e77d5f398f5cf976eea3bdf61749731f62d4a4a21"}, + {file = "frozenlist-1.5.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7437601c4d89d070eac8323f121fcf25f88674627505334654fd027b091db09d"}, + {file = "frozenlist-1.5.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7948140d9f8ece1745be806f2bfdf390127cf1a763b925c4a805c603df5e697e"}, + {file = "frozenlist-1.5.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:feeb64bc9bcc6b45c6311c9e9b99406660a9c05ca8a5b30d14a78555088b0b3a"}, + {file = "frozenlist-1.5.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:683173d371daad49cffb8309779e886e59c2f369430ad28fe715f66d08d4ab1a"}, + {file = "frozenlist-1.5.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7d57d8f702221405a9d9b40f9da8ac2e4a1a8b5285aac6100f3393675f0a85ee"}, + {file = "frozenlist-1.5.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:30c72000fbcc35b129cb09956836c7d7abf78ab5416595e4857d1cae8d6251a6"}, + {file = "frozenlist-1.5.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:000a77d6034fbad9b6bb880f7ec073027908f1b40254b5d6f26210d2dab1240e"}, + {file = "frozenlist-1.5.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5d7f5a50342475962eb18b740f3beecc685a15b52c91f7d975257e13e029eca9"}, + {file = "frozenlist-1.5.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:87f724d055eb4785d9be84e9ebf0f24e392ddfad00b3fe036e43f489fafc9039"}, + {file = "frozenlist-1.5.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:6e9080bb2fb195a046e5177f10d9d82b8a204c0736a97a153c2466127de87784"}, + {file = "frozenlist-1.5.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:9b93d7aaa36c966fa42efcaf716e6b3900438632a626fb09c049f6a2f09fc631"}, + {file = "frozenlist-1.5.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:52ef692a4bc60a6dd57f507429636c2af8b6046db8b31b18dac02cbc8f507f7f"}, + {file = "frozenlist-1.5.0-cp312-cp312-win32.whl", hash = "sha256:29d94c256679247b33a3dc96cce0f93cbc69c23bf75ff715919332fdbb6a32b8"}, + {file = "frozenlist-1.5.0-cp312-cp312-win_amd64.whl", hash = "sha256:8969190d709e7c48ea386db202d708eb94bdb29207a1f269bab1196ce0dcca1f"}, + {file = "frozenlist-1.5.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:7a1a048f9215c90973402e26c01d1cff8a209e1f1b53f72b95c13db61b00f953"}, + {file = "frozenlist-1.5.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:dd47a5181ce5fcb463b5d9e17ecfdb02b678cca31280639255ce9d0e5aa67af0"}, + {file = "frozenlist-1.5.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1431d60b36d15cda188ea222033eec8e0eab488f39a272461f2e6d9e1a8e63c2"}, + {file = "frozenlist-1.5.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6482a5851f5d72767fbd0e507e80737f9c8646ae7fd303def99bfe813f76cf7f"}, + {file = "frozenlist-1.5.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:44c49271a937625619e862baacbd037a7ef86dd1ee215afc298a417ff3270608"}, + {file = "frozenlist-1.5.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:12f78f98c2f1c2429d42e6a485f433722b0061d5c0b0139efa64f396efb5886b"}, + {file = "frozenlist-1.5.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ce3aa154c452d2467487765e3adc730a8c153af77ad84096bc19ce19a2400840"}, + {file = "frozenlist-1.5.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9b7dc0c4338e6b8b091e8faf0db3168a37101943e687f373dce00959583f7439"}, + {file = "frozenlist-1.5.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:45e0896250900b5aa25180f9aec243e84e92ac84bd4a74d9ad4138ef3f5c97de"}, + {file = "frozenlist-1.5.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:561eb1c9579d495fddb6da8959fd2a1fca2c6d060d4113f5844b433fc02f2641"}, + {file = "frozenlist-1.5.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:df6e2f325bfee1f49f81aaac97d2aa757c7646534a06f8f577ce184afe2f0a9e"}, + {file = "frozenlist-1.5.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:140228863501b44b809fb39ec56b5d4071f4d0aa6d216c19cbb08b8c5a7eadb9"}, + {file = "frozenlist-1.5.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7707a25d6a77f5d27ea7dc7d1fc608aa0a478193823f88511ef5e6b8a48f9d03"}, + {file = "frozenlist-1.5.0-cp313-cp313-win32.whl", hash = "sha256:31a9ac2b38ab9b5a8933b693db4939764ad3f299fcaa931a3e605bc3460e693c"}, + {file = "frozenlist-1.5.0-cp313-cp313-win_amd64.whl", hash = "sha256:11aabdd62b8b9c4b84081a3c246506d1cddd2dd93ff0ad53ede5defec7886b28"}, + {file = "frozenlist-1.5.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:dd94994fc91a6177bfaafd7d9fd951bc8689b0a98168aa26b5f543868548d3ca"}, + {file = "frozenlist-1.5.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2d0da8bbec082bf6bf18345b180958775363588678f64998c2b7609e34719b10"}, + {file = "frozenlist-1.5.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:73f2e31ea8dd7df61a359b731716018c2be196e5bb3b74ddba107f694fbd7604"}, + {file = "frozenlist-1.5.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:828afae9f17e6de596825cf4228ff28fbdf6065974e5ac1410cecc22f699d2b3"}, + {file = "frozenlist-1.5.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f1577515d35ed5649d52ab4319db757bb881ce3b2b796d7283e6634d99ace307"}, + {file = "frozenlist-1.5.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2150cc6305a2c2ab33299453e2968611dacb970d2283a14955923062c8d00b10"}, + {file = "frozenlist-1.5.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a72b7a6e3cd2725eff67cd64c8f13335ee18fc3c7befc05aed043d24c7b9ccb9"}, + {file = "frozenlist-1.5.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c16d2fa63e0800723139137d667e1056bee1a1cf7965153d2d104b62855e9b99"}, + {file = "frozenlist-1.5.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:17dcc32fc7bda7ce5875435003220a457bcfa34ab7924a49a1c19f55b6ee185c"}, + {file = "frozenlist-1.5.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:97160e245ea33d8609cd2b8fd997c850b56db147a304a262abc2b3be021a9171"}, + {file = "frozenlist-1.5.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:f1e6540b7fa044eee0bb5111ada694cf3dc15f2b0347ca125ee9ca984d5e9e6e"}, + {file = "frozenlist-1.5.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:91d6c171862df0a6c61479d9724f22efb6109111017c87567cfeb7b5d1449fdf"}, + {file = "frozenlist-1.5.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:c1fac3e2ace2eb1052e9f7c7db480818371134410e1f5c55d65e8f3ac6d1407e"}, + {file = "frozenlist-1.5.0-cp38-cp38-win32.whl", hash = "sha256:b97f7b575ab4a8af9b7bc1d2ef7f29d3afee2226bd03ca3875c16451ad5a7723"}, + {file = "frozenlist-1.5.0-cp38-cp38-win_amd64.whl", hash = "sha256:374ca2dabdccad8e2a76d40b1d037f5bd16824933bf7bcea3e59c891fd4a0923"}, + {file = "frozenlist-1.5.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:9bbcdfaf4af7ce002694a4e10a0159d5a8d20056a12b05b45cea944a4953f972"}, + {file = "frozenlist-1.5.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1893f948bf6681733aaccf36c5232c231e3b5166d607c5fa77773611df6dc336"}, + {file = "frozenlist-1.5.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2b5e23253bb709ef57a8e95e6ae48daa9ac5f265637529e4ce6b003a37b2621f"}, + {file = "frozenlist-1.5.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0f253985bb515ecd89629db13cb58d702035ecd8cfbca7d7a7e29a0e6d39af5f"}, + {file = "frozenlist-1.5.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:04a5c6babd5e8fb7d3c871dc8b321166b80e41b637c31a995ed844a6139942b6"}, + {file = "frozenlist-1.5.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a9fe0f1c29ba24ba6ff6abf688cb0b7cf1efab6b6aa6adc55441773c252f7411"}, + {file = "frozenlist-1.5.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:226d72559fa19babe2ccd920273e767c96a49b9d3d38badd7c91a0fdeda8ea08"}, + {file = "frozenlist-1.5.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15b731db116ab3aedec558573c1a5eec78822b32292fe4f2f0345b7f697745c2"}, + {file = "frozenlist-1.5.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:366d8f93e3edfe5a918c874702f78faac300209a4d5bf38352b2c1bdc07a766d"}, + {file = "frozenlist-1.5.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:1b96af8c582b94d381a1c1f51ffaedeb77c821c690ea5f01da3d70a487dd0a9b"}, + {file = "frozenlist-1.5.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:c03eff4a41bd4e38415cbed054bbaff4a075b093e2394b6915dca34a40d1e38b"}, + {file = "frozenlist-1.5.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:50cf5e7ee9b98f22bdecbabf3800ae78ddcc26e4a435515fc72d97903e8488e0"}, + {file = "frozenlist-1.5.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:1e76bfbc72353269c44e0bc2cfe171900fbf7f722ad74c9a7b638052afe6a00c"}, + {file = "frozenlist-1.5.0-cp39-cp39-win32.whl", hash = "sha256:666534d15ba8f0fda3f53969117383d5dc021266b3c1a42c9ec4855e4b58b9d3"}, + {file = "frozenlist-1.5.0-cp39-cp39-win_amd64.whl", hash = "sha256:5c28f4b5dbef8a0d8aad0d4de24d1e9e981728628afaf4ea0792f5d0939372f0"}, + {file = "frozenlist-1.5.0-py3-none-any.whl", hash = "sha256:d994863bba198a4a518b467bb971c56e1db3f180a25c6cf7bb1949c267f748c3"}, + {file = "frozenlist-1.5.0.tar.gz", hash = "sha256:81d5af29e61b9c8348e876d442253723928dce6433e0e76cd925cd83f1b4b817"}, +] + [[package]] name = "gitdb" version = "4.0.11" @@ -259,6 +513,92 @@ gitdb = ">=4.0.1,<5" doc = ["sphinx (==4.3.2)", "sphinx-autodoc-typehints", "sphinx-rtd-theme", "sphinxcontrib-applehelp (>=1.0.2,<=1.0.4)", "sphinxcontrib-devhelp (==1.0.2)", "sphinxcontrib-htmlhelp (>=2.0.0,<=2.0.1)", "sphinxcontrib-qthelp (==1.0.3)", "sphinxcontrib-serializinghtml (==1.1.5)"] test = ["coverage[toml]", "ddt (>=1.1.1,!=1.4.3)", "mock", "mypy", "pre-commit", "pytest (>=7.3.1)", "pytest-cov", "pytest-instafail", "pytest-mock", "pytest-sugar", "typing-extensions"] +[[package]] +name = "greenlet" +version = "3.1.1" +description = "Lightweight in-process concurrent programming" +optional = false +python-versions = ">=3.7" +files = [ + {file = "greenlet-3.1.1-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:0bbae94a29c9e5c7e4a2b7f0aae5c17e8e90acbfd3bf6270eeba60c39fce3563"}, + {file = "greenlet-3.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0fde093fb93f35ca72a556cf72c92ea3ebfda3d79fc35bb19fbe685853869a83"}, + {file = "greenlet-3.1.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:36b89d13c49216cadb828db8dfa6ce86bbbc476a82d3a6c397f0efae0525bdd0"}, + {file = "greenlet-3.1.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:94b6150a85e1b33b40b1464a3f9988dcc5251d6ed06842abff82e42632fac120"}, + {file = "greenlet-3.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:93147c513fac16385d1036b7e5b102c7fbbdb163d556b791f0f11eada7ba65dc"}, + {file = "greenlet-3.1.1-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:da7a9bff22ce038e19bf62c4dd1ec8391062878710ded0a845bcf47cc0200617"}, + {file = "greenlet-3.1.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:b2795058c23988728eec1f36a4e5e4ebad22f8320c85f3587b539b9ac84128d7"}, + {file = "greenlet-3.1.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:ed10eac5830befbdd0c32f83e8aa6288361597550ba669b04c48f0f9a2c843c6"}, + {file = "greenlet-3.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:77c386de38a60d1dfb8e55b8c1101d68c79dfdd25c7095d51fec2dd800892b80"}, + {file = "greenlet-3.1.1-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:e4d333e558953648ca09d64f13e6d8f0523fa705f51cae3f03b5983489958c70"}, + {file = "greenlet-3.1.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:09fc016b73c94e98e29af67ab7b9a879c307c6731a2c9da0db5a7d9b7edd1159"}, + {file = "greenlet-3.1.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d5e975ca70269d66d17dd995dafc06f1b06e8cb1ec1e9ed54c1d1e4a7c4cf26e"}, + {file = "greenlet-3.1.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3b2813dc3de8c1ee3f924e4d4227999285fd335d1bcc0d2be6dc3f1f6a318ec1"}, + {file = "greenlet-3.1.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e347b3bfcf985a05e8c0b7d462ba6f15b1ee1c909e2dcad795e49e91b152c383"}, + {file = "greenlet-3.1.1-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9e8f8c9cb53cdac7ba9793c276acd90168f416b9ce36799b9b885790f8ad6c0a"}, + {file = "greenlet-3.1.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:62ee94988d6b4722ce0028644418d93a52429e977d742ca2ccbe1c4f4a792511"}, + {file = "greenlet-3.1.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:1776fd7f989fc6b8d8c8cb8da1f6b82c5814957264d1f6cf818d475ec2bf6395"}, + {file = "greenlet-3.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:48ca08c771c268a768087b408658e216133aecd835c0ded47ce955381105ba39"}, + {file = "greenlet-3.1.1-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:4afe7ea89de619adc868e087b4d2359282058479d7cfb94970adf4b55284574d"}, + {file = "greenlet-3.1.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f406b22b7c9a9b4f8aa9d2ab13d6ae0ac3e85c9a809bd590ad53fed2bf70dc79"}, + {file = "greenlet-3.1.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c3a701fe5a9695b238503ce5bbe8218e03c3bcccf7e204e455e7462d770268aa"}, + {file = "greenlet-3.1.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2846930c65b47d70b9d178e89c7e1a69c95c1f68ea5aa0a58646b7a96df12441"}, + {file = "greenlet-3.1.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:99cfaa2110534e2cf3ba31a7abcac9d328d1d9f1b95beede58294a60348fba36"}, + {file = "greenlet-3.1.1-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1443279c19fca463fc33e65ef2a935a5b09bb90f978beab37729e1c3c6c25fe9"}, + {file = "greenlet-3.1.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:b7cede291382a78f7bb5f04a529cb18e068dd29e0fb27376074b6d0317bf4dd0"}, + {file = "greenlet-3.1.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:23f20bb60ae298d7d8656c6ec6db134bca379ecefadb0b19ce6f19d1f232a942"}, + {file = "greenlet-3.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:7124e16b4c55d417577c2077be379514321916d5790fa287c9ed6f23bd2ffd01"}, + {file = "greenlet-3.1.1-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:05175c27cb459dcfc05d026c4232f9de8913ed006d42713cb8a5137bd49375f1"}, + {file = "greenlet-3.1.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:935e943ec47c4afab8965954bf49bfa639c05d4ccf9ef6e924188f762145c0ff"}, + {file = "greenlet-3.1.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:667a9706c970cb552ede35aee17339a18e8f2a87a51fba2ed39ceeeb1004798a"}, + {file = "greenlet-3.1.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b8a678974d1f3aa55f6cc34dc480169d58f2e6d8958895d68845fa4ab566509e"}, + {file = "greenlet-3.1.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:efc0f674aa41b92da8c49e0346318c6075d734994c3c4e4430b1c3f853e498e4"}, + {file = "greenlet-3.1.1-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0153404a4bb921f0ff1abeb5ce8a5131da56b953eda6e14b88dc6bbc04d2049e"}, + {file = "greenlet-3.1.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:275f72decf9932639c1c6dd1013a1bc266438eb32710016a1c742df5da6e60a1"}, + {file = "greenlet-3.1.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:c4aab7f6381f38a4b42f269057aee279ab0fc7bf2e929e3d4abfae97b682a12c"}, + {file = "greenlet-3.1.1-cp313-cp313-win_amd64.whl", hash = "sha256:b42703b1cf69f2aa1df7d1030b9d77d3e584a70755674d60e710f0af570f3761"}, + {file = "greenlet-3.1.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f1695e76146579f8c06c1509c7ce4dfe0706f49c6831a817ac04eebb2fd02011"}, + {file = "greenlet-3.1.1-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7876452af029456b3f3549b696bb36a06db7c90747740c5302f74a9e9fa14b13"}, + {file = "greenlet-3.1.1-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4ead44c85f8ab905852d3de8d86f6f8baf77109f9da589cb4fa142bd3b57b475"}, + {file = "greenlet-3.1.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8320f64b777d00dd7ccdade271eaf0cad6636343293a25074cc5566160e4de7b"}, + {file = "greenlet-3.1.1-cp313-cp313t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6510bf84a6b643dabba74d3049ead221257603a253d0a9873f55f6a59a65f822"}, + {file = "greenlet-3.1.1-cp313-cp313t-musllinux_1_1_aarch64.whl", hash = "sha256:04b013dc07c96f83134b1e99888e7a79979f1a247e2a9f59697fa14b5862ed01"}, + {file = "greenlet-3.1.1-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:411f015496fec93c1c8cd4e5238da364e1da7a124bcb293f085bf2860c32c6f6"}, + {file = "greenlet-3.1.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:47da355d8687fd65240c364c90a31569a133b7b60de111c255ef5b606f2ae291"}, + {file = "greenlet-3.1.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:98884ecf2ffb7d7fe6bd517e8eb99d31ff7855a840fa6d0d63cd07c037f6a981"}, + {file = "greenlet-3.1.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f1d4aeb8891338e60d1ab6127af1fe45def5259def8094b9c7e34690c8858803"}, + {file = "greenlet-3.1.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db32b5348615a04b82240cc67983cb315309e88d444a288934ee6ceaebcad6cc"}, + {file = "greenlet-3.1.1-cp37-cp37m-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:dcc62f31eae24de7f8dce72134c8651c58000d3b1868e01392baea7c32c247de"}, + {file = "greenlet-3.1.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:1d3755bcb2e02de341c55b4fca7a745a24a9e7212ac953f6b3a48d117d7257aa"}, + {file = "greenlet-3.1.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:b8da394b34370874b4572676f36acabac172602abf054cbc4ac910219f3340af"}, + {file = "greenlet-3.1.1-cp37-cp37m-win32.whl", hash = "sha256:a0dfc6c143b519113354e780a50381508139b07d2177cb6ad6a08278ec655798"}, + {file = "greenlet-3.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:54558ea205654b50c438029505def3834e80f0869a70fb15b871c29b4575ddef"}, + {file = "greenlet-3.1.1-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:346bed03fe47414091be4ad44786d1bd8bef0c3fcad6ed3dee074a032ab408a9"}, + {file = "greenlet-3.1.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dfc59d69fc48664bc693842bd57acfdd490acafda1ab52c7836e3fc75c90a111"}, + {file = "greenlet-3.1.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d21e10da6ec19b457b82636209cbe2331ff4306b54d06fa04b7c138ba18c8a81"}, + {file = "greenlet-3.1.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:37b9de5a96111fc15418819ab4c4432e4f3c2ede61e660b1e33971eba26ef9ba"}, + {file = "greenlet-3.1.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6ef9ea3f137e5711f0dbe5f9263e8c009b7069d8a1acea822bd5e9dae0ae49c8"}, + {file = "greenlet-3.1.1-cp38-cp38-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:85f3ff71e2e60bd4b4932a043fbbe0f499e263c628390b285cb599154a3b03b1"}, + {file = "greenlet-3.1.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:95ffcf719966dd7c453f908e208e14cde192e09fde6c7186c8f1896ef778d8cd"}, + {file = "greenlet-3.1.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:03a088b9de532cbfe2ba2034b2b85e82df37874681e8c470d6fb2f8c04d7e4b7"}, + {file = "greenlet-3.1.1-cp38-cp38-win32.whl", hash = "sha256:8b8b36671f10ba80e159378df9c4f15c14098c4fd73a36b9ad715f057272fbef"}, + {file = "greenlet-3.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:7017b2be767b9d43cc31416aba48aab0d2309ee31b4dbf10a1d38fb7972bdf9d"}, + {file = "greenlet-3.1.1-cp39-cp39-macosx_11_0_universal2.whl", hash = "sha256:396979749bd95f018296af156201d6211240e7a23090f50a8d5d18c370084dc3"}, + {file = "greenlet-3.1.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca9d0ff5ad43e785350894d97e13633a66e2b50000e8a183a50a88d834752d42"}, + {file = "greenlet-3.1.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f6ff3b14f2df4c41660a7dec01045a045653998784bf8cfcb5a525bdffffbc8f"}, + {file = "greenlet-3.1.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:94ebba31df2aa506d7b14866fed00ac141a867e63143fe5bca82a8e503b36437"}, + {file = "greenlet-3.1.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:73aaad12ac0ff500f62cebed98d8789198ea0e6f233421059fa68a5aa7220145"}, + {file = "greenlet-3.1.1-cp39-cp39-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:63e4844797b975b9af3a3fb8f7866ff08775f5426925e1e0bbcfe7932059a12c"}, + {file = "greenlet-3.1.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:7939aa3ca7d2a1593596e7ac6d59391ff30281ef280d8632fa03d81f7c5f955e"}, + {file = "greenlet-3.1.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d0028e725ee18175c6e422797c407874da24381ce0690d6b9396c204c7f7276e"}, + {file = "greenlet-3.1.1-cp39-cp39-win32.whl", hash = "sha256:5e06afd14cbaf9e00899fae69b24a32f2196c19de08fcb9f4779dd4f004e5e7c"}, + {file = "greenlet-3.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:3319aa75e0e0639bc15ff54ca327e8dc7a6fe404003496e3c6925cd3142e0e22"}, + {file = "greenlet-3.1.1.tar.gz", hash = "sha256:4ce3ac6cdb6adf7946475d7ef31777c26d94bccc377e070a7986bd2d5c515467"}, +] + +[package.extras] +docs = ["Sphinx", "furo"] +test = ["objgraph", "psutil"] + [[package]] name = "gritql" version = "0.1.5" @@ -304,13 +644,13 @@ trio = ["trio (>=0.22.0,<1.0)"] [[package]] name = "httpx" -version = "0.27.2" +version = "0.28.0" description = "The next generation HTTP client." optional = false python-versions = ">=3.8" files = [ - {file = "httpx-0.27.2-py3-none-any.whl", hash = "sha256:7bb2708e112d8fdd7829cd4243970f0c223274051cb35ee80c03301ee29a3df0"}, - {file = "httpx-0.27.2.tar.gz", hash = "sha256:f7c2be1d2f3c3c3160d441802406b206c2b76f5947b11115e6df10c6c65e66c2"}, + {file = "httpx-0.28.0-py3-none-any.whl", hash = "sha256:dc0b419a0cfeb6e8b34e85167c0da2671206f5095f1baa9663d23bcfd6b535fc"}, + {file = "httpx-0.28.0.tar.gz", hash = "sha256:0858d3bab51ba7e386637f22a61d8ccddaeec5f3fe4209da3a6168dbb91573e0"}, ] [package.dependencies] @@ -318,7 +658,6 @@ anyio = "*" certifi = "*" httpcore = "==1.*" idna = "*" -sniffio = "*" [package.extras] brotli = ["brotli", "brotlicffi"] @@ -377,15 +716,44 @@ files = [ {file = "jsonpointer-3.0.0.tar.gz", hash = "sha256:2b2d729f2091522d61c3b31f82e11870f60b68f43fbc705cb76bf4b832af59ef"}, ] +[[package]] +name = "langchain" +version = "0.3.9" +description = "Building applications with LLMs through composability" +optional = false +python-versions = ">=3.9,<4.0" +files = [] +develop = true + +[package.dependencies] +aiohttp = "^3.8.3" +async-timeout = {version = "^4.0.0", markers = "python_version < \"3.11\""} +langchain-core = "^0.3.21" +langchain-text-splitters = "^0.3.0" +langsmith = "^0.1.17" +numpy = [ + {version = ">=1.22.4,<2", markers = "python_version < \"3.12\""}, + {version = ">=1.26.2,<3", markers = "python_version >= \"3.12\""}, +] +pydantic = "^2.7.4" +PyYAML = ">=5.3" +requests = "^2" +SQLAlchemy = ">=1.4,<3" +tenacity = ">=8.1.0,!=8.4.0,<10" + +[package.source] +type = "directory" +url = "../langchain" + [[package]] name = "langchain-core" -version = "0.3.19" +version = "0.3.21" description = "Building applications with LLMs through composability" optional = false python-versions = "<4.0,>=3.9" files = [ - {file = "langchain_core-0.3.19-py3-none-any.whl", hash = "sha256:562b7cc3c15dfaa9270cb1496990c1f3b3e0b660c4d6a3236d7f693346f2a96c"}, - {file = "langchain_core-0.3.19.tar.gz", hash = "sha256:126d9e8cadb2a5b8d1793a228c0783a3b608e36064d5a2ef1a4d38d07a344523"}, + {file = "langchain_core-0.3.21-py3-none-any.whl", hash = "sha256:7e723dff80946a1198976c6876fea8326dc82566ef9bcb5f8d9188f738733665"}, + {file = "langchain_core-0.3.21.tar.gz", hash = "sha256:561b52b258ffa50a9fb11d7a1940ebfd915654d1ec95b35e81dfd5ee84143411"}, ] [package.dependencies] @@ -400,6 +768,20 @@ PyYAML = ">=5.3" tenacity = ">=8.1.0,<8.4.0 || >8.4.0,<10.0.0" typing-extensions = ">=4.7" +[[package]] +name = "langchain-text-splitters" +version = "0.3.2" +description = "LangChain text splitting utilities" +optional = false +python-versions = "<4.0,>=3.9" +files = [ + {file = "langchain_text_splitters-0.3.2-py3-none-any.whl", hash = "sha256:0db28c53f41d1bc024cdb3b1646741f6d46d5371e90f31e7e7c9fbe75d01c726"}, + {file = "langchain_text_splitters-0.3.2.tar.gz", hash = "sha256:81e6515d9901d6dd8e35fb31ccd4f30f76d44b771890c789dc835ef9f16204df"}, +] + +[package.dependencies] +langchain-core = ">=0.3.15,<0.4.0" + [[package]] name = "langserve" version = "0.3.0" @@ -426,13 +808,13 @@ server = ["fastapi (>=0.90.1,<1)", "sse-starlette (>=1.3.0,<2.0.0)"] [[package]] name = "langsmith" -version = "0.1.144" +version = "0.1.147" description = "Client library to connect to the LangSmith LLM Tracing and Evaluation Platform." optional = false python-versions = "<4.0,>=3.8.1" files = [ - {file = "langsmith-0.1.144-py3-none-any.whl", hash = "sha256:08ffb975bff2e82fc6f5428837c64c074ea25102d08a25e256361a80812c6100"}, - {file = "langsmith-0.1.144.tar.gz", hash = "sha256:b621f358d5a33441d7b5e7264c376bf4ea82bfc62d7e41aafc0f8094e3bd6369"}, + {file = "langsmith-0.1.147-py3-none-any.whl", hash = "sha256:7166fc23b965ccf839d64945a78e9f1157757add228b086141eb03a60d699a15"}, + {file = "langsmith-0.1.147.tar.gz", hash = "sha256:2e933220318a4e73034657103b3b1a3a6109cc5db3566a7e8e03be8d6d7def7a"}, ] [package.dependencies] @@ -445,6 +827,9 @@ pydantic = [ requests = ">=2,<3" requests-toolbelt = ">=1.0.0,<2.0.0" +[package.extras] +langsmith-pyo3 = ["langsmith-pyo3 (>=0.1.0rc2,<0.2.0)"] + [[package]] name = "markdown-it-py" version = "3.0.0" @@ -480,71 +865,365 @@ files = [ {file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"}, ] +[[package]] +name = "multidict" +version = "6.1.0" +description = "multidict implementation" +optional = false +python-versions = ">=3.8" +files = [ + {file = "multidict-6.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3380252550e372e8511d49481bd836264c009adb826b23fefcc5dd3c69692f60"}, + {file = "multidict-6.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:99f826cbf970077383d7de805c0681799491cb939c25450b9b5b3ced03ca99f1"}, + {file = "multidict-6.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a114d03b938376557927ab23f1e950827c3b893ccb94b62fd95d430fd0e5cf53"}, + {file = "multidict-6.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b1c416351ee6271b2f49b56ad7f308072f6f44b37118d69c2cad94f3fa8a40d5"}, + {file = "multidict-6.1.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6b5d83030255983181005e6cfbac1617ce9746b219bc2aad52201ad121226581"}, + {file = "multidict-6.1.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3e97b5e938051226dc025ec80980c285b053ffb1e25a3db2a3aa3bc046bf7f56"}, + {file = "multidict-6.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d618649d4e70ac6efcbba75be98b26ef5078faad23592f9b51ca492953012429"}, + {file = "multidict-6.1.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:10524ebd769727ac77ef2278390fb0068d83f3acb7773792a5080f2b0abf7748"}, + {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ff3827aef427c89a25cc96ded1759271a93603aba9fb977a6d264648ebf989db"}, + {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:06809f4f0f7ab7ea2cabf9caca7d79c22c0758b58a71f9d32943ae13c7ace056"}, + {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:f179dee3b863ab1c59580ff60f9d99f632f34ccb38bf67a33ec6b3ecadd0fd76"}, + {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:aaed8b0562be4a0876ee3b6946f6869b7bcdb571a5d1496683505944e268b160"}, + {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3c8b88a2ccf5493b6c8da9076fb151ba106960a2df90c2633f342f120751a9e7"}, + {file = "multidict-6.1.0-cp310-cp310-win32.whl", hash = "sha256:4a9cb68166a34117d6646c0023c7b759bf197bee5ad4272f420a0141d7eb03a0"}, + {file = "multidict-6.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:20b9b5fbe0b88d0bdef2012ef7dee867f874b72528cf1d08f1d59b0e3850129d"}, + {file = "multidict-6.1.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:3efe2c2cb5763f2f1b275ad2bf7a287d3f7ebbef35648a9726e3b69284a4f3d6"}, + {file = "multidict-6.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c7053d3b0353a8b9de430a4f4b4268ac9a4fb3481af37dfe49825bf45ca24156"}, + {file = "multidict-6.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:27e5fc84ccef8dfaabb09d82b7d179c7cf1a3fbc8a966f8274fcb4ab2eb4cadb"}, + {file = "multidict-6.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e2b90b43e696f25c62656389d32236e049568b39320e2735d51f08fd362761b"}, + {file = "multidict-6.1.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d83a047959d38a7ff552ff94be767b7fd79b831ad1cd9920662db05fec24fe72"}, + {file = "multidict-6.1.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d1a9dd711d0877a1ece3d2e4fea11a8e75741ca21954c919406b44e7cf971304"}, + {file = "multidict-6.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec2abea24d98246b94913b76a125e855eb5c434f7c46546046372fe60f666351"}, + {file = "multidict-6.1.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4867cafcbc6585e4b678876c489b9273b13e9fff9f6d6d66add5e15d11d926cb"}, + {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:5b48204e8d955c47c55b72779802b219a39acc3ee3d0116d5080c388970b76e3"}, + {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:d8fff389528cad1618fb4b26b95550327495462cd745d879a8c7c2115248e399"}, + {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:a7a9541cd308eed5e30318430a9c74d2132e9a8cb46b901326272d780bf2d423"}, + {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:da1758c76f50c39a2efd5e9859ce7d776317eb1dd34317c8152ac9251fc574a3"}, + {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:c943a53e9186688b45b323602298ab727d8865d8c9ee0b17f8d62d14b56f0753"}, + {file = "multidict-6.1.0-cp311-cp311-win32.whl", hash = "sha256:90f8717cb649eea3504091e640a1b8568faad18bd4b9fcd692853a04475a4b80"}, + {file = "multidict-6.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:82176036e65644a6cc5bd619f65f6f19781e8ec2e5330f51aa9ada7504cc1926"}, + {file = "multidict-6.1.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:b04772ed465fa3cc947db808fa306d79b43e896beb677a56fb2347ca1a49c1fa"}, + {file = "multidict-6.1.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:6180c0ae073bddeb5a97a38c03f30c233e0a4d39cd86166251617d1bbd0af436"}, + {file = "multidict-6.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:071120490b47aa997cca00666923a83f02c7fbb44f71cf7f136df753f7fa8761"}, + {file = "multidict-6.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50b3a2710631848991d0bf7de077502e8994c804bb805aeb2925a981de58ec2e"}, + {file = "multidict-6.1.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b58c621844d55e71c1b7f7c498ce5aa6985d743a1a59034c57a905b3f153c1ef"}, + {file = "multidict-6.1.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:55b6d90641869892caa9ca42ff913f7ff1c5ece06474fbd32fb2cf6834726c95"}, + {file = "multidict-6.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b820514bfc0b98a30e3d85462084779900347e4d49267f747ff54060cc33925"}, + {file = "multidict-6.1.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:10a9b09aba0c5b48c53761b7c720aaaf7cf236d5fe394cd399c7ba662d5f9966"}, + {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1e16bf3e5fc9f44632affb159d30a437bfe286ce9e02754759be5536b169b305"}, + {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:76f364861c3bfc98cbbcbd402d83454ed9e01a5224bb3a28bf70002a230f73e2"}, + {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:820c661588bd01a0aa62a1283f20d2be4281b086f80dad9e955e690c75fb54a2"}, + {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:0e5f362e895bc5b9e67fe6e4ded2492d8124bdf817827f33c5b46c2fe3ffaca6"}, + {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3ec660d19bbc671e3a6443325f07263be452c453ac9e512f5eb935e7d4ac28b3"}, + {file = "multidict-6.1.0-cp312-cp312-win32.whl", hash = "sha256:58130ecf8f7b8112cdb841486404f1282b9c86ccb30d3519faf301b2e5659133"}, + {file = "multidict-6.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:188215fc0aafb8e03341995e7c4797860181562380f81ed0a87ff455b70bf1f1"}, + {file = "multidict-6.1.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:d569388c381b24671589335a3be6e1d45546c2988c2ebe30fdcada8457a31008"}, + {file = "multidict-6.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:052e10d2d37810b99cc170b785945421141bf7bb7d2f8799d431e7db229c385f"}, + {file = "multidict-6.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f90c822a402cb865e396a504f9fc8173ef34212a342d92e362ca498cad308e28"}, + {file = "multidict-6.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b225d95519a5bf73860323e633a664b0d85ad3d5bede6d30d95b35d4dfe8805b"}, + {file = "multidict-6.1.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:23bfd518810af7de1116313ebd9092cb9aa629beb12f6ed631ad53356ed6b86c"}, + {file = "multidict-6.1.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5c09fcfdccdd0b57867577b719c69e347a436b86cd83747f179dbf0cc0d4c1f3"}, + {file = "multidict-6.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf6bea52ec97e95560af5ae576bdac3aa3aae0b6758c6efa115236d9e07dae44"}, + {file = "multidict-6.1.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57feec87371dbb3520da6192213c7d6fc892d5589a93db548331954de8248fd2"}, + {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0c3f390dc53279cbc8ba976e5f8035eab997829066756d811616b652b00a23a3"}, + {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:59bfeae4b25ec05b34f1956eaa1cb38032282cd4dfabc5056d0a1ec4d696d3aa"}, + {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:b2f59caeaf7632cc633b5cf6fc449372b83bbdf0da4ae04d5be36118e46cc0aa"}, + {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:37bb93b2178e02b7b618893990941900fd25b6b9ac0fa49931a40aecdf083fe4"}, + {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4e9f48f58c2c523d5a06faea47866cd35b32655c46b443f163d08c6d0ddb17d6"}, + {file = "multidict-6.1.0-cp313-cp313-win32.whl", hash = "sha256:3a37ffb35399029b45c6cc33640a92bef403c9fd388acce75cdc88f58bd19a81"}, + {file = "multidict-6.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:e9aa71e15d9d9beaad2c6b9319edcdc0a49a43ef5c0a4c8265ca9ee7d6c67774"}, + {file = "multidict-6.1.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:db7457bac39421addd0c8449933ac32d8042aae84a14911a757ae6ca3eef1392"}, + {file = "multidict-6.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d094ddec350a2fb899fec68d8353c78233debde9b7d8b4beeafa70825f1c281a"}, + {file = "multidict-6.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:5845c1fd4866bb5dd3125d89b90e57ed3138241540897de748cdf19de8a2fca2"}, + {file = "multidict-6.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9079dfc6a70abe341f521f78405b8949f96db48da98aeb43f9907f342f627cdc"}, + {file = "multidict-6.1.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3914f5aaa0f36d5d60e8ece6a308ee1c9784cd75ec8151062614657a114c4478"}, + {file = "multidict-6.1.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c08be4f460903e5a9d0f76818db3250f12e9c344e79314d1d570fc69d7f4eae4"}, + {file = "multidict-6.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d093be959277cb7dee84b801eb1af388b6ad3ca6a6b6bf1ed7585895789d027d"}, + {file = "multidict-6.1.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3702ea6872c5a2a4eeefa6ffd36b042e9773f05b1f37ae3ef7264b1163c2dcf6"}, + {file = "multidict-6.1.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:2090f6a85cafc5b2db085124d752757c9d251548cedabe9bd31afe6363e0aff2"}, + {file = "multidict-6.1.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:f67f217af4b1ff66c68a87318012de788dd95fcfeb24cc889011f4e1c7454dfd"}, + {file = "multidict-6.1.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:189f652a87e876098bbc67b4da1049afb5f5dfbaa310dd67c594b01c10388db6"}, + {file = "multidict-6.1.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:6bb5992037f7a9eff7991ebe4273ea7f51f1c1c511e6a2ce511d0e7bdb754492"}, + {file = "multidict-6.1.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:ac10f4c2b9e770c4e393876e35a7046879d195cd123b4f116d299d442b335bcd"}, + {file = "multidict-6.1.0-cp38-cp38-win32.whl", hash = "sha256:e27bbb6d14416713a8bd7aaa1313c0fc8d44ee48d74497a0ff4c3a1b6ccb5167"}, + {file = "multidict-6.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:22f3105d4fb15c8f57ff3959a58fcab6ce36814486500cd7485651230ad4d4ef"}, + {file = "multidict-6.1.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:4e18b656c5e844539d506a0a06432274d7bd52a7487e6828c63a63d69185626c"}, + {file = "multidict-6.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a185f876e69897a6f3325c3f19f26a297fa058c5e456bfcff8015e9a27e83ae1"}, + {file = "multidict-6.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ab7c4ceb38d91570a650dba194e1ca87c2b543488fe9309b4212694174fd539c"}, + {file = "multidict-6.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e617fb6b0b6953fffd762669610c1c4ffd05632c138d61ac7e14ad187870669c"}, + {file = "multidict-6.1.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:16e5f4bf4e603eb1fdd5d8180f1a25f30056f22e55ce51fb3d6ad4ab29f7d96f"}, + {file = "multidict-6.1.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f4c035da3f544b1882bac24115f3e2e8760f10a0107614fc9839fd232200b875"}, + {file = "multidict-6.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:957cf8e4b6e123a9eea554fa7ebc85674674b713551de587eb318a2df3e00255"}, + {file = "multidict-6.1.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:483a6aea59cb89904e1ceabd2b47368b5600fb7de78a6e4a2c2987b2d256cf30"}, + {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:87701f25a2352e5bf7454caa64757642734da9f6b11384c1f9d1a8e699758057"}, + {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:682b987361e5fd7a139ed565e30d81fd81e9629acc7d925a205366877d8c8657"}, + {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:ce2186a7df133a9c895dea3331ddc5ddad42cdd0d1ea2f0a51e5d161e4762f28"}, + {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:9f636b730f7e8cb19feb87094949ba54ee5357440b9658b2a32a5ce4bce53972"}, + {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:73eae06aa53af2ea5270cc066dcaf02cc60d2994bbb2c4ef5764949257d10f43"}, + {file = "multidict-6.1.0-cp39-cp39-win32.whl", hash = "sha256:1ca0083e80e791cffc6efce7660ad24af66c8d4079d2a750b29001b53ff59ada"}, + {file = "multidict-6.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:aa466da5b15ccea564bdab9c89175c762bc12825f4659c11227f515cee76fa4a"}, + {file = "multidict-6.1.0-py3-none-any.whl", hash = "sha256:48e171e52d1c4d33888e529b999e5900356b9ae588c2f09a52dcefb158b27506"}, + {file = "multidict-6.1.0.tar.gz", hash = "sha256:22ae2ebf9b0c69d206c003e2f6a914ea33f0a932d4aa16f236afc049d9958f4a"}, +] + +[package.dependencies] +typing-extensions = {version = ">=4.1.0", markers = "python_version < \"3.11\""} + +[[package]] +name = "mypy" +version = "1.13.0" +description = "Optional static typing for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "mypy-1.13.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6607e0f1dd1fb7f0aca14d936d13fd19eba5e17e1cd2a14f808fa5f8f6d8f60a"}, + {file = "mypy-1.13.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8a21be69bd26fa81b1f80a61ee7ab05b076c674d9b18fb56239d72e21d9f4c80"}, + {file = "mypy-1.13.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7b2353a44d2179846a096e25691d54d59904559f4232519d420d64da6828a3a7"}, + {file = "mypy-1.13.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0730d1c6a2739d4511dc4253f8274cdd140c55c32dfb0a4cf8b7a43f40abfa6f"}, + {file = "mypy-1.13.0-cp310-cp310-win_amd64.whl", hash = "sha256:c5fc54dbb712ff5e5a0fca797e6e0aa25726c7e72c6a5850cfd2adbc1eb0a372"}, + {file = "mypy-1.13.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:581665e6f3a8a9078f28d5502f4c334c0c8d802ef55ea0e7276a6e409bc0d82d"}, + {file = "mypy-1.13.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3ddb5b9bf82e05cc9a627e84707b528e5c7caaa1c55c69e175abb15a761cec2d"}, + {file = "mypy-1.13.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:20c7ee0bc0d5a9595c46f38beb04201f2620065a93755704e141fcac9f59db2b"}, + {file = "mypy-1.13.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3790ded76f0b34bc9c8ba4def8f919dd6a46db0f5a6610fb994fe8efdd447f73"}, + {file = "mypy-1.13.0-cp311-cp311-win_amd64.whl", hash = "sha256:51f869f4b6b538229c1d1bcc1dd7d119817206e2bc54e8e374b3dfa202defcca"}, + {file = "mypy-1.13.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:5c7051a3461ae84dfb5dd15eff5094640c61c5f22257c8b766794e6dd85e72d5"}, + {file = "mypy-1.13.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:39bb21c69a5d6342f4ce526e4584bc5c197fd20a60d14a8624d8743fffb9472e"}, + {file = "mypy-1.13.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:164f28cb9d6367439031f4c81e84d3ccaa1e19232d9d05d37cb0bd880d3f93c2"}, + {file = "mypy-1.13.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a4c1bfcdbce96ff5d96fc9b08e3831acb30dc44ab02671eca5953eadad07d6d0"}, + {file = "mypy-1.13.0-cp312-cp312-win_amd64.whl", hash = "sha256:a0affb3a79a256b4183ba09811e3577c5163ed06685e4d4b46429a271ba174d2"}, + {file = "mypy-1.13.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a7b44178c9760ce1a43f544e595d35ed61ac2c3de306599fa59b38a6048e1aa7"}, + {file = "mypy-1.13.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5d5092efb8516d08440e36626f0153b5006d4088c1d663d88bf79625af3d1d62"}, + {file = "mypy-1.13.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:de2904956dac40ced10931ac967ae63c5089bd498542194b436eb097a9f77bc8"}, + {file = "mypy-1.13.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:7bfd8836970d33c2105562650656b6846149374dc8ed77d98424b40b09340ba7"}, + {file = "mypy-1.13.0-cp313-cp313-win_amd64.whl", hash = "sha256:9f73dba9ec77acb86457a8fc04b5239822df0c14a082564737833d2963677dbc"}, + {file = "mypy-1.13.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:100fac22ce82925f676a734af0db922ecfea991e1d7ec0ceb1e115ebe501301a"}, + {file = "mypy-1.13.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7bcb0bb7f42a978bb323a7c88f1081d1b5dee77ca86f4100735a6f541299d8fb"}, + {file = "mypy-1.13.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bde31fc887c213e223bbfc34328070996061b0833b0a4cfec53745ed61f3519b"}, + {file = "mypy-1.13.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:07de989f89786f62b937851295ed62e51774722e5444a27cecca993fc3f9cd74"}, + {file = "mypy-1.13.0-cp38-cp38-win_amd64.whl", hash = "sha256:4bde84334fbe19bad704b3f5b78c4abd35ff1026f8ba72b29de70dda0916beb6"}, + {file = "mypy-1.13.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:0246bcb1b5de7f08f2826451abd947bf656945209b140d16ed317f65a17dc7dc"}, + {file = "mypy-1.13.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:7f5b7deae912cf8b77e990b9280f170381fdfbddf61b4ef80927edd813163732"}, + {file = "mypy-1.13.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7029881ec6ffb8bc233a4fa364736789582c738217b133f1b55967115288a2bc"}, + {file = "mypy-1.13.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:3e38b980e5681f28f033f3be86b099a247b13c491f14bb8b1e1e134d23bb599d"}, + {file = "mypy-1.13.0-cp39-cp39-win_amd64.whl", hash = "sha256:a6789be98a2017c912ae6ccb77ea553bbaf13d27605d2ca20a76dfbced631b24"}, + {file = "mypy-1.13.0-py3-none-any.whl", hash = "sha256:9c250883f9fd81d212e0952c92dbfcc96fc237f4b7c92f56ac81fd48460b3e5a"}, + {file = "mypy-1.13.0.tar.gz", hash = "sha256:0291a61b6fbf3e6673e3405cfcc0e7650bebc7939659fdca2702958038bd835e"}, +] + +[package.dependencies] +mypy-extensions = ">=1.0.0" +tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} +typing-extensions = ">=4.6.0" + +[package.extras] +dmypy = ["psutil (>=4.0)"] +faster-cache = ["orjson"] +install-types = ["pip"] +mypyc = ["setuptools (>=50)"] +reports = ["lxml"] + +[[package]] +name = "mypy-extensions" +version = "1.0.0" +description = "Type system extensions for programs checked with the mypy type checker." +optional = false +python-versions = ">=3.5" +files = [ + {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, + {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, +] + +[[package]] +name = "numpy" +version = "1.26.4" +description = "Fundamental package for array computing in Python" +optional = false +python-versions = ">=3.9" +files = [ + {file = "numpy-1.26.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9ff0f4f29c51e2803569d7a51c2304de5554655a60c5d776e35b4a41413830d0"}, + {file = "numpy-1.26.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2e4ee3380d6de9c9ec04745830fd9e2eccb3e6cf790d39d7b98ffd19b0dd754a"}, + {file = "numpy-1.26.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d209d8969599b27ad20994c8e41936ee0964e6da07478d6c35016bc386b66ad4"}, + {file = "numpy-1.26.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ffa75af20b44f8dba823498024771d5ac50620e6915abac414251bd971b4529f"}, + {file = "numpy-1.26.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:62b8e4b1e28009ef2846b4c7852046736bab361f7aeadeb6a5b89ebec3c7055a"}, + {file = "numpy-1.26.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a4abb4f9001ad2858e7ac189089c42178fcce737e4169dc61321660f1a96c7d2"}, + {file = "numpy-1.26.4-cp310-cp310-win32.whl", hash = "sha256:bfe25acf8b437eb2a8b2d49d443800a5f18508cd811fea3181723922a8a82b07"}, + {file = "numpy-1.26.4-cp310-cp310-win_amd64.whl", hash = "sha256:b97fe8060236edf3662adfc2c633f56a08ae30560c56310562cb4f95500022d5"}, + {file = "numpy-1.26.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4c66707fabe114439db9068ee468c26bbdf909cac0fb58686a42a24de1760c71"}, + {file = "numpy-1.26.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:edd8b5fe47dab091176d21bb6de568acdd906d1887a4584a15a9a96a1dca06ef"}, + {file = "numpy-1.26.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ab55401287bfec946ced39700c053796e7cc0e3acbef09993a9ad2adba6ca6e"}, + {file = "numpy-1.26.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:666dbfb6ec68962c033a450943ded891bed2d54e6755e35e5835d63f4f6931d5"}, + {file = "numpy-1.26.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:96ff0b2ad353d8f990b63294c8986f1ec3cb19d749234014f4e7eb0112ceba5a"}, + {file = "numpy-1.26.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:60dedbb91afcbfdc9bc0b1f3f402804070deed7392c23eb7a7f07fa857868e8a"}, + {file = "numpy-1.26.4-cp311-cp311-win32.whl", hash = "sha256:1af303d6b2210eb850fcf03064d364652b7120803a0b872f5211f5234b399f20"}, + {file = "numpy-1.26.4-cp311-cp311-win_amd64.whl", hash = "sha256:cd25bcecc4974d09257ffcd1f098ee778f7834c3ad767fe5db785be9a4aa9cb2"}, + {file = "numpy-1.26.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b3ce300f3644fb06443ee2222c2201dd3a89ea6040541412b8fa189341847218"}, + {file = "numpy-1.26.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:03a8c78d01d9781b28a6989f6fa1bb2c4f2d51201cf99d3dd875df6fbd96b23b"}, + {file = "numpy-1.26.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9fad7dcb1aac3c7f0584a5a8133e3a43eeb2fe127f47e3632d43d677c66c102b"}, + {file = "numpy-1.26.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:675d61ffbfa78604709862923189bad94014bef562cc35cf61d3a07bba02a7ed"}, + {file = "numpy-1.26.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ab47dbe5cc8210f55aa58e4805fe224dac469cde56b9f731a4c098b91917159a"}, + {file = "numpy-1.26.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:1dda2e7b4ec9dd512f84935c5f126c8bd8b9f2fc001e9f54af255e8c5f16b0e0"}, + {file = "numpy-1.26.4-cp312-cp312-win32.whl", hash = "sha256:50193e430acfc1346175fcbdaa28ffec49947a06918b7b92130744e81e640110"}, + {file = "numpy-1.26.4-cp312-cp312-win_amd64.whl", hash = "sha256:08beddf13648eb95f8d867350f6a018a4be2e5ad54c8d8caed89ebca558b2818"}, + {file = "numpy-1.26.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7349ab0fa0c429c82442a27a9673fc802ffdb7c7775fad780226cb234965e53c"}, + {file = "numpy-1.26.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:52b8b60467cd7dd1e9ed082188b4e6bb35aa5cdd01777621a1658910745b90be"}, + {file = "numpy-1.26.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d5241e0a80d808d70546c697135da2c613f30e28251ff8307eb72ba696945764"}, + {file = "numpy-1.26.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f870204a840a60da0b12273ef34f7051e98c3b5961b61b0c2c1be6dfd64fbcd3"}, + {file = "numpy-1.26.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:679b0076f67ecc0138fd2ede3a8fd196dddc2ad3254069bcb9faf9a79b1cebcd"}, + {file = "numpy-1.26.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:47711010ad8555514b434df65f7d7b076bb8261df1ca9bb78f53d3b2db02e95c"}, + {file = "numpy-1.26.4-cp39-cp39-win32.whl", hash = "sha256:a354325ee03388678242a4d7ebcd08b5c727033fcff3b2f536aea978e15ee9e6"}, + {file = "numpy-1.26.4-cp39-cp39-win_amd64.whl", hash = "sha256:3373d5d70a5fe74a2c1bb6d2cfd9609ecf686d47a2d7b1d37a8f3b6bf6003aea"}, + {file = "numpy-1.26.4-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:afedb719a9dcfc7eaf2287b839d8198e06dcd4cb5d276a3df279231138e83d30"}, + {file = "numpy-1.26.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95a7476c59002f2f6c590b9b7b998306fba6a5aa646b1e22ddfeaf8f78c3a29c"}, + {file = "numpy-1.26.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7e50d0a0cc3189f9cb0aeb3a6a6af18c16f59f004b866cd2be1c14b36134a4a0"}, + {file = "numpy-1.26.4.tar.gz", hash = "sha256:2a02aba9ed12e4ac4eb3ea9421c420301a0c6460d9830d74a9df87efa4912010"}, +] + +[[package]] +name = "numpy" +version = "2.1.3" +description = "Fundamental package for array computing in Python" +optional = false +python-versions = ">=3.10" +files = [ + {file = "numpy-2.1.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c894b4305373b9c5576d7a12b473702afdf48ce5369c074ba304cc5ad8730dff"}, + {file = "numpy-2.1.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b47fbb433d3260adcd51eb54f92a2ffbc90a4595f8970ee00e064c644ac788f5"}, + {file = "numpy-2.1.3-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:825656d0743699c529c5943554d223c021ff0494ff1442152ce887ef4f7561a1"}, + {file = "numpy-2.1.3-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:6a4825252fcc430a182ac4dee5a505053d262c807f8a924603d411f6718b88fd"}, + {file = "numpy-2.1.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e711e02f49e176a01d0349d82cb5f05ba4db7d5e7e0defd026328e5cfb3226d3"}, + {file = "numpy-2.1.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78574ac2d1a4a02421f25da9559850d59457bac82f2b8d7a44fe83a64f770098"}, + {file = "numpy-2.1.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c7662f0e3673fe4e832fe07b65c50342ea27d989f92c80355658c7f888fcc83c"}, + {file = "numpy-2.1.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:fa2d1337dc61c8dc417fbccf20f6d1e139896a30721b7f1e832b2bb6ef4eb6c4"}, + {file = "numpy-2.1.3-cp310-cp310-win32.whl", hash = "sha256:72dcc4a35a8515d83e76b58fdf8113a5c969ccd505c8a946759b24e3182d1f23"}, + {file = "numpy-2.1.3-cp310-cp310-win_amd64.whl", hash = "sha256:ecc76a9ba2911d8d37ac01de72834d8849e55473457558e12995f4cd53e778e0"}, + {file = "numpy-2.1.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4d1167c53b93f1f5d8a139a742b3c6f4d429b54e74e6b57d0eff40045187b15d"}, + {file = "numpy-2.1.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c80e4a09b3d95b4e1cac08643f1152fa71a0a821a2d4277334c88d54b2219a41"}, + {file = "numpy-2.1.3-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:576a1c1d25e9e02ed7fa5477f30a127fe56debd53b8d2c89d5578f9857d03ca9"}, + {file = "numpy-2.1.3-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:973faafebaae4c0aaa1a1ca1ce02434554d67e628b8d805e61f874b84e136b09"}, + {file = "numpy-2.1.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:762479be47a4863e261a840e8e01608d124ee1361e48b96916f38b119cfda04a"}, + {file = "numpy-2.1.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc6f24b3d1ecc1eebfbf5d6051faa49af40b03be1aaa781ebdadcbc090b4539b"}, + {file = "numpy-2.1.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:17ee83a1f4fef3c94d16dc1802b998668b5419362c8a4f4e8a491de1b41cc3ee"}, + {file = "numpy-2.1.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:15cb89f39fa6d0bdfb600ea24b250e5f1a3df23f901f51c8debaa6a5d122b2f0"}, + {file = "numpy-2.1.3-cp311-cp311-win32.whl", hash = "sha256:d9beb777a78c331580705326d2367488d5bc473b49a9bc3036c154832520aca9"}, + {file = "numpy-2.1.3-cp311-cp311-win_amd64.whl", hash = "sha256:d89dd2b6da69c4fff5e39c28a382199ddedc3a5be5390115608345dec660b9e2"}, + {file = "numpy-2.1.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f55ba01150f52b1027829b50d70ef1dafd9821ea82905b63936668403c3b471e"}, + {file = "numpy-2.1.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:13138eadd4f4da03074851a698ffa7e405f41a0845a6b1ad135b81596e4e9958"}, + {file = "numpy-2.1.3-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:a6b46587b14b888e95e4a24d7b13ae91fa22386c199ee7b418f449032b2fa3b8"}, + {file = "numpy-2.1.3-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:0fa14563cc46422e99daef53d725d0c326e99e468a9320a240affffe87852564"}, + {file = "numpy-2.1.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8637dcd2caa676e475503d1f8fdb327bc495554e10838019651b76d17b98e512"}, + {file = "numpy-2.1.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2312b2aa89e1f43ecea6da6ea9a810d06aae08321609d8dc0d0eda6d946a541b"}, + {file = "numpy-2.1.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a38c19106902bb19351b83802531fea19dee18e5b37b36454f27f11ff956f7fc"}, + {file = "numpy-2.1.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:02135ade8b8a84011cbb67dc44e07c58f28575cf9ecf8ab304e51c05528c19f0"}, + {file = "numpy-2.1.3-cp312-cp312-win32.whl", hash = "sha256:e6988e90fcf617da2b5c78902fe8e668361b43b4fe26dbf2d7b0f8034d4cafb9"}, + {file = "numpy-2.1.3-cp312-cp312-win_amd64.whl", hash = "sha256:0d30c543f02e84e92c4b1f415b7c6b5326cbe45ee7882b6b77db7195fb971e3a"}, + {file = "numpy-2.1.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:96fe52fcdb9345b7cd82ecd34547fca4321f7656d500eca497eb7ea5a926692f"}, + {file = "numpy-2.1.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f653490b33e9c3a4c1c01d41bc2aef08f9475af51146e4a7710c450cf9761598"}, + {file = "numpy-2.1.3-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:dc258a761a16daa791081d026f0ed4399b582712e6fc887a95af09df10c5ca57"}, + {file = "numpy-2.1.3-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:016d0f6f5e77b0f0d45d77387ffa4bb89816b57c835580c3ce8e099ef830befe"}, + {file = "numpy-2.1.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c181ba05ce8299c7aa3125c27b9c2167bca4a4445b7ce73d5febc411ca692e43"}, + {file = "numpy-2.1.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5641516794ca9e5f8a4d17bb45446998c6554704d888f86df9b200e66bdcce56"}, + {file = "numpy-2.1.3-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ea4dedd6e394a9c180b33c2c872b92f7ce0f8e7ad93e9585312b0c5a04777a4a"}, + {file = "numpy-2.1.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b0df3635b9c8ef48bd3be5f862cf71b0a4716fa0e702155c45067c6b711ddcef"}, + {file = "numpy-2.1.3-cp313-cp313-win32.whl", hash = "sha256:50ca6aba6e163363f132b5c101ba078b8cbd3fa92c7865fd7d4d62d9779ac29f"}, + {file = "numpy-2.1.3-cp313-cp313-win_amd64.whl", hash = "sha256:747641635d3d44bcb380d950679462fae44f54b131be347d5ec2bce47d3df9ed"}, + {file = "numpy-2.1.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:996bb9399059c5b82f76b53ff8bb686069c05acc94656bb259b1d63d04a9506f"}, + {file = "numpy-2.1.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:45966d859916ad02b779706bb43b954281db43e185015df6eb3323120188f9e4"}, + {file = "numpy-2.1.3-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:baed7e8d7481bfe0874b566850cb0b85243e982388b7b23348c6db2ee2b2ae8e"}, + {file = "numpy-2.1.3-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:a9f7f672a3388133335589cfca93ed468509cb7b93ba3105fce780d04a6576a0"}, + {file = "numpy-2.1.3-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7aac50327da5d208db2eec22eb11e491e3fe13d22653dce51b0f4109101b408"}, + {file = "numpy-2.1.3-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4394bc0dbd074b7f9b52024832d16e019decebf86caf909d94f6b3f77a8ee3b6"}, + {file = "numpy-2.1.3-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:50d18c4358a0a8a53f12a8ba9d772ab2d460321e6a93d6064fc22443d189853f"}, + {file = "numpy-2.1.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:14e253bd43fc6b37af4921b10f6add6925878a42a0c5fe83daee390bca80bc17"}, + {file = "numpy-2.1.3-cp313-cp313t-win32.whl", hash = "sha256:08788d27a5fd867a663f6fc753fd7c3ad7e92747efc73c53bca2f19f8bc06f48"}, + {file = "numpy-2.1.3-cp313-cp313t-win_amd64.whl", hash = "sha256:2564fbdf2b99b3f815f2107c1bbc93e2de8ee655a69c261363a1172a79a257d4"}, + {file = "numpy-2.1.3-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:4f2015dfe437dfebbfce7c85c7b53d81ba49e71ba7eadbf1df40c915af75979f"}, + {file = "numpy-2.1.3-pp310-pypy310_pp73-macosx_14_0_x86_64.whl", hash = "sha256:3522b0dfe983a575e6a9ab3a4a4dfe156c3e428468ff08ce582b9bb6bd1d71d4"}, + {file = "numpy-2.1.3-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c006b607a865b07cd981ccb218a04fc86b600411d83d6fc261357f1c0966755d"}, + {file = "numpy-2.1.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:e14e26956e6f1696070788252dcdff11b4aca4c3e8bd166e0df1bb8f315a67cb"}, + {file = "numpy-2.1.3.tar.gz", hash = "sha256:aa08e04e08aaf974d4458def539dece0d28146d866a39da5639596f4921fd761"}, +] + [[package]] name = "orjson" -version = "3.10.11" +version = "3.10.12" description = "Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy" optional = false python-versions = ">=3.8" files = [ - {file = "orjson-3.10.11-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:6dade64687f2bd7c090281652fe18f1151292d567a9302b34c2dbb92a3872f1f"}, - {file = "orjson-3.10.11-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:82f07c550a6ccd2b9290849b22316a609023ed851a87ea888c0456485a7d196a"}, - {file = "orjson-3.10.11-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bd9a187742d3ead9df2e49240234d728c67c356516cf4db018833a86f20ec18c"}, - {file = "orjson-3.10.11-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:77b0fed6f209d76c1c39f032a70df2d7acf24b1812ca3e6078fd04e8972685a3"}, - {file = "orjson-3.10.11-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:63fc9d5fe1d4e8868f6aae547a7b8ba0a2e592929245fff61d633f4caccdcdd6"}, - {file = "orjson-3.10.11-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:65cd3e3bb4fbb4eddc3c1e8dce10dc0b73e808fcb875f9fab40c81903dd9323e"}, - {file = "orjson-3.10.11-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:6f67c570602300c4befbda12d153113b8974a3340fdcf3d6de095ede86c06d92"}, - {file = "orjson-3.10.11-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:1f39728c7f7d766f1f5a769ce4d54b5aaa4c3f92d5b84817053cc9995b977acc"}, - {file = "orjson-3.10.11-cp310-none-win32.whl", hash = "sha256:1789d9db7968d805f3d94aae2c25d04014aae3a2fa65b1443117cd462c6da647"}, - {file = "orjson-3.10.11-cp310-none-win_amd64.whl", hash = "sha256:5576b1e5a53a5ba8f8df81872bb0878a112b3ebb1d392155f00f54dd86c83ff6"}, - {file = "orjson-3.10.11-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:1444f9cb7c14055d595de1036f74ecd6ce15f04a715e73f33bb6326c9cef01b6"}, - {file = "orjson-3.10.11-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cdec57fe3b4bdebcc08a946db3365630332dbe575125ff3d80a3272ebd0ddafe"}, - {file = "orjson-3.10.11-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4eed32f33a0ea6ef36ccc1d37f8d17f28a1d6e8eefae5928f76aff8f1df85e67"}, - {file = "orjson-3.10.11-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:80df27dd8697242b904f4ea54820e2d98d3f51f91e97e358fc13359721233e4b"}, - {file = "orjson-3.10.11-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:705f03cee0cb797256d54de6695ef219e5bc8c8120b6654dd460848d57a9af3d"}, - {file = "orjson-3.10.11-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:03246774131701de8e7059b2e382597da43144a9a7400f178b2a32feafc54bd5"}, - {file = "orjson-3.10.11-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8b5759063a6c940a69c728ea70d7c33583991c6982915a839c8da5f957e0103a"}, - {file = "orjson-3.10.11-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:677f23e32491520eebb19c99bb34675daf5410c449c13416f7f0d93e2cf5f981"}, - {file = "orjson-3.10.11-cp311-none-win32.whl", hash = "sha256:a11225d7b30468dcb099498296ffac36b4673a8398ca30fdaec1e6c20df6aa55"}, - {file = "orjson-3.10.11-cp311-none-win_amd64.whl", hash = "sha256:df8c677df2f9f385fcc85ab859704045fa88d4668bc9991a527c86e710392bec"}, - {file = "orjson-3.10.11-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:360a4e2c0943da7c21505e47cf6bd725588962ff1d739b99b14e2f7f3545ba51"}, - {file = "orjson-3.10.11-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:496e2cb45de21c369079ef2d662670a4892c81573bcc143c4205cae98282ba97"}, - {file = "orjson-3.10.11-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7dfa8db55c9792d53c5952900c6a919cfa377b4f4534c7a786484a6a4a350c19"}, - {file = "orjson-3.10.11-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:51f3382415747e0dbda9dade6f1e1a01a9d37f630d8c9049a8ed0e385b7a90c0"}, - {file = "orjson-3.10.11-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f35a1b9f50a219f470e0e497ca30b285c9f34948d3c8160d5ad3a755d9299433"}, - {file = "orjson-3.10.11-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e2f3b7c5803138e67028dde33450e054c87e0703afbe730c105f1fcd873496d5"}, - {file = "orjson-3.10.11-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f91d9eb554310472bd09f5347950b24442600594c2edc1421403d7610a0998fd"}, - {file = "orjson-3.10.11-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:dfbb2d460a855c9744bbc8e36f9c3a997c4b27d842f3d5559ed54326e6911f9b"}, - {file = "orjson-3.10.11-cp312-none-win32.whl", hash = "sha256:d4a62c49c506d4d73f59514986cadebb7e8d186ad510c518f439176cf8d5359d"}, - {file = "orjson-3.10.11-cp312-none-win_amd64.whl", hash = "sha256:f1eec3421a558ff7a9b010a6c7effcfa0ade65327a71bb9b02a1c3b77a247284"}, - {file = "orjson-3.10.11-cp313-cp313-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:c46294faa4e4d0eb73ab68f1a794d2cbf7bab33b1dda2ac2959ffb7c61591899"}, - {file = "orjson-3.10.11-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:52e5834d7d6e58a36846e059d00559cb9ed20410664f3ad156cd2cc239a11230"}, - {file = "orjson-3.10.11-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a2fc947e5350fdce548bfc94f434e8760d5cafa97fb9c495d2fef6757aa02ec0"}, - {file = "orjson-3.10.11-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0efabbf839388a1dab5b72b5d3baedbd6039ac83f3b55736eb9934ea5494d258"}, - {file = "orjson-3.10.11-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a3f29634260708c200c4fe148e42b4aae97d7b9fee417fbdd74f8cfc265f15b0"}, - {file = "orjson-3.10.11-cp313-none-win32.whl", hash = "sha256:1a1222ffcee8a09476bbdd5d4f6f33d06d0d6642df2a3d78b7a195ca880d669b"}, - {file = "orjson-3.10.11-cp313-none-win_amd64.whl", hash = "sha256:bc274ac261cc69260913b2d1610760e55d3c0801bb3457ba7b9004420b6b4270"}, - {file = "orjson-3.10.11-cp38-cp38-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:19b3763e8bbf8ad797df6b6b5e0fc7c843ec2e2fc0621398534e0c6400098f87"}, - {file = "orjson-3.10.11-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1be83a13312e5e58d633580c5eb8d0495ae61f180da2722f20562974188af205"}, - {file = "orjson-3.10.11-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:afacfd1ab81f46dedd7f6001b6d4e8de23396e4884cd3c3436bd05defb1a6446"}, - {file = "orjson-3.10.11-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cb4d0bea56bba596723d73f074c420aec3b2e5d7d30698bc56e6048066bd560c"}, - {file = "orjson-3.10.11-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:96ed1de70fcb15d5fed529a656df29f768187628727ee2788344e8a51e1c1350"}, - {file = "orjson-3.10.11-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4bfb30c891b530f3f80e801e3ad82ef150b964e5c38e1fb8482441c69c35c61c"}, - {file = "orjson-3.10.11-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:d496c74fc2b61341e3cefda7eec21b7854c5f672ee350bc55d9a4997a8a95204"}, - {file = "orjson-3.10.11-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:655a493bac606655db9a47fe94d3d84fc7f3ad766d894197c94ccf0c5408e7d3"}, - {file = "orjson-3.10.11-cp38-none-win32.whl", hash = "sha256:b9546b278c9fb5d45380f4809e11b4dd9844ca7aaf1134024503e134ed226161"}, - {file = "orjson-3.10.11-cp38-none-win_amd64.whl", hash = "sha256:b592597fe551d518f42c5a2eb07422eb475aa8cfdc8c51e6da7054b836b26782"}, - {file = "orjson-3.10.11-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:c95f2ecafe709b4e5c733b5e2768ac569bed308623c85806c395d9cca00e08af"}, - {file = "orjson-3.10.11-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:80c00d4acded0c51c98754fe8218cb49cb854f0f7eb39ea4641b7f71732d2cb7"}, - {file = "orjson-3.10.11-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:461311b693d3d0a060439aa669c74f3603264d4e7a08faa68c47ae5a863f352d"}, - {file = "orjson-3.10.11-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:52ca832f17d86a78cbab86cdc25f8c13756ebe182b6fc1a97d534051c18a08de"}, - {file = "orjson-3.10.11-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f4c57ea78a753812f528178aa2f1c57da633754c91d2124cb28991dab4c79a54"}, - {file = "orjson-3.10.11-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b7fcfc6f7ca046383fb954ba528587e0f9336828b568282b27579c49f8e16aad"}, - {file = "orjson-3.10.11-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:86b9dd983857970c29e4c71bb3e95ff085c07d3e83e7c46ebe959bac07ebd80b"}, - {file = "orjson-3.10.11-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:4d83f87582d223e54efb2242a79547611ba4ebae3af8bae1e80fa9a0af83bb7f"}, - {file = "orjson-3.10.11-cp39-none-win32.whl", hash = "sha256:9fd0ad1c129bc9beb1154c2655f177620b5beaf9a11e0d10bac63ef3fce96950"}, - {file = "orjson-3.10.11-cp39-none-win_amd64.whl", hash = "sha256:10f416b2a017c8bd17f325fb9dee1fb5cdd7a54e814284896b7c3f2763faa017"}, - {file = "orjson-3.10.11.tar.gz", hash = "sha256:e35b6d730de6384d5b2dab5fd23f0d76fae8bbc8c353c2f78210aa5fa4beb3ef"}, + {file = "orjson-3.10.12-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:ece01a7ec71d9940cc654c482907a6b65df27251255097629d0dea781f255c6d"}, + {file = "orjson-3.10.12-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c34ec9aebc04f11f4b978dd6caf697a2df2dd9b47d35aa4cc606cabcb9df69d7"}, + {file = "orjson-3.10.12-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fd6ec8658da3480939c79b9e9e27e0db31dffcd4ba69c334e98c9976ac29140e"}, + {file = "orjson-3.10.12-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f17e6baf4cf01534c9de8a16c0c611f3d94925d1701bf5f4aff17003677d8ced"}, + {file = "orjson-3.10.12-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6402ebb74a14ef96f94a868569f5dccf70d791de49feb73180eb3c6fda2ade56"}, + {file = "orjson-3.10.12-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0000758ae7c7853e0a4a6063f534c61656ebff644391e1f81698c1b2d2fc8cd2"}, + {file = "orjson-3.10.12-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:888442dcee99fd1e5bd37a4abb94930915ca6af4db50e23e746cdf4d1e63db13"}, + {file = "orjson-3.10.12-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:c1f7a3ce79246aa0e92f5458d86c54f257fb5dfdc14a192651ba7ec2c00f8a05"}, + {file = "orjson-3.10.12-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:802a3935f45605c66fb4a586488a38af63cb37aaad1c1d94c982c40dcc452e85"}, + {file = "orjson-3.10.12-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:1da1ef0113a2be19bb6c557fb0ec2d79c92ebd2fed4cfb1b26bab93f021fb885"}, + {file = "orjson-3.10.12-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7a3273e99f367f137d5b3fecb5e9f45bcdbfac2a8b2f32fbc72129bbd48789c2"}, + {file = "orjson-3.10.12-cp310-none-win32.whl", hash = "sha256:475661bf249fd7907d9b0a2a2421b4e684355a77ceef85b8352439a9163418c3"}, + {file = "orjson-3.10.12-cp310-none-win_amd64.whl", hash = "sha256:87251dc1fb2b9e5ab91ce65d8f4caf21910d99ba8fb24b49fd0c118b2362d509"}, + {file = "orjson-3.10.12-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:a734c62efa42e7df94926d70fe7d37621c783dea9f707a98cdea796964d4cf74"}, + {file = "orjson-3.10.12-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:750f8b27259d3409eda8350c2919a58b0cfcd2054ddc1bd317a643afc646ef23"}, + {file = "orjson-3.10.12-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bb52c22bfffe2857e7aa13b4622afd0dd9d16ea7cc65fd2bf318d3223b1b6252"}, + {file = "orjson-3.10.12-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:440d9a337ac8c199ff8251e100c62e9488924c92852362cd27af0e67308c16ef"}, + {file = "orjson-3.10.12-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a9e15c06491c69997dfa067369baab3bf094ecb74be9912bdc4339972323f252"}, + {file = "orjson-3.10.12-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:362d204ad4b0b8724cf370d0cd917bb2dc913c394030da748a3bb632445ce7c4"}, + {file = "orjson-3.10.12-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2b57cbb4031153db37b41622eac67329c7810e5f480fda4cfd30542186f006ae"}, + {file = "orjson-3.10.12-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:165c89b53ef03ce0d7c59ca5c82fa65fe13ddf52eeb22e859e58c237d4e33b9b"}, + {file = "orjson-3.10.12-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:5dee91b8dfd54557c1a1596eb90bcd47dbcd26b0baaed919e6861f076583e9da"}, + {file = "orjson-3.10.12-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:77a4e1cfb72de6f905bdff061172adfb3caf7a4578ebf481d8f0530879476c07"}, + {file = "orjson-3.10.12-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:038d42c7bc0606443459b8fe2d1f121db474c49067d8d14c6a075bbea8bf14dd"}, + {file = "orjson-3.10.12-cp311-none-win32.whl", hash = "sha256:03b553c02ab39bed249bedd4abe37b2118324d1674e639b33fab3d1dafdf4d79"}, + {file = "orjson-3.10.12-cp311-none-win_amd64.whl", hash = "sha256:8b8713b9e46a45b2af6b96f559bfb13b1e02006f4242c156cbadef27800a55a8"}, + {file = "orjson-3.10.12-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:53206d72eb656ca5ac7d3a7141e83c5bbd3ac30d5eccfe019409177a57634b0d"}, + {file = "orjson-3.10.12-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac8010afc2150d417ebda810e8df08dd3f544e0dd2acab5370cfa6bcc0662f8f"}, + {file = "orjson-3.10.12-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ed459b46012ae950dd2e17150e838ab08215421487371fa79d0eced8d1461d70"}, + {file = "orjson-3.10.12-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8dcb9673f108a93c1b52bfc51b0af422c2d08d4fc710ce9c839faad25020bb69"}, + {file = "orjson-3.10.12-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:22a51ae77680c5c4652ebc63a83d5255ac7d65582891d9424b566fb3b5375ee9"}, + {file = "orjson-3.10.12-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:910fdf2ac0637b9a77d1aad65f803bac414f0b06f720073438a7bd8906298192"}, + {file = "orjson-3.10.12-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:24ce85f7100160936bc2116c09d1a8492639418633119a2224114f67f63a4559"}, + {file = "orjson-3.10.12-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8a76ba5fc8dd9c913640292df27bff80a685bed3a3c990d59aa6ce24c352f8fc"}, + {file = "orjson-3.10.12-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:ff70ef093895fd53f4055ca75f93f047e088d1430888ca1229393a7c0521100f"}, + {file = "orjson-3.10.12-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:f4244b7018b5753ecd10a6d324ec1f347da130c953a9c88432c7fbc8875d13be"}, + {file = "orjson-3.10.12-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:16135ccca03445f37921fa4b585cff9a58aa8d81ebcb27622e69bfadd220b32c"}, + {file = "orjson-3.10.12-cp312-none-win32.whl", hash = "sha256:2d879c81172d583e34153d524fcba5d4adafbab8349a7b9f16ae511c2cee8708"}, + {file = "orjson-3.10.12-cp312-none-win_amd64.whl", hash = "sha256:fc23f691fa0f5c140576b8c365bc942d577d861a9ee1142e4db468e4e17094fb"}, + {file = "orjson-3.10.12-cp313-cp313-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:47962841b2a8aa9a258b377f5188db31ba49af47d4003a32f55d6f8b19006543"}, + {file = "orjson-3.10.12-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6334730e2532e77b6054e87ca84f3072bee308a45a452ea0bffbbbc40a67e296"}, + {file = "orjson-3.10.12-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:accfe93f42713c899fdac2747e8d0d5c659592df2792888c6c5f829472e4f85e"}, + {file = "orjson-3.10.12-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a7974c490c014c48810d1dede6c754c3cc46598da758c25ca3b4001ac45b703f"}, + {file = "orjson-3.10.12-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:3f250ce7727b0b2682f834a3facff88e310f52f07a5dcfd852d99637d386e79e"}, + {file = "orjson-3.10.12-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:f31422ff9486ae484f10ffc51b5ab2a60359e92d0716fcce1b3593d7bb8a9af6"}, + {file = "orjson-3.10.12-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5f29c5d282bb2d577c2a6bbde88d8fdcc4919c593f806aac50133f01b733846e"}, + {file = "orjson-3.10.12-cp313-none-win32.whl", hash = "sha256:f45653775f38f63dc0e6cd4f14323984c3149c05d6007b58cb154dd080ddc0dc"}, + {file = "orjson-3.10.12-cp313-none-win_amd64.whl", hash = "sha256:229994d0c376d5bdc91d92b3c9e6be2f1fbabd4cc1b59daae1443a46ee5e9825"}, + {file = "orjson-3.10.12-cp38-cp38-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:7d69af5b54617a5fac5c8e5ed0859eb798e2ce8913262eb522590239db6c6763"}, + {file = "orjson-3.10.12-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ed119ea7d2953365724a7059231a44830eb6bbb0cfead33fcbc562f5fd8f935"}, + {file = "orjson-3.10.12-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9c5fc1238ef197e7cad5c91415f524aaa51e004be5a9b35a1b8a84ade196f73f"}, + {file = "orjson-3.10.12-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:43509843990439b05f848539d6f6198d4ac86ff01dd024b2f9a795c0daeeab60"}, + {file = "orjson-3.10.12-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f72e27a62041cfb37a3de512247ece9f240a561e6c8662276beaf4d53d406db4"}, + {file = "orjson-3.10.12-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9a904f9572092bb6742ab7c16c623f0cdccbad9eeb2d14d4aa06284867bddd31"}, + {file = "orjson-3.10.12-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:855c0833999ed5dc62f64552db26f9be767434917d8348d77bacaab84f787d7b"}, + {file = "orjson-3.10.12-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:897830244e2320f6184699f598df7fb9db9f5087d6f3f03666ae89d607e4f8ed"}, + {file = "orjson-3.10.12-cp38-cp38-musllinux_1_2_armv7l.whl", hash = "sha256:0b32652eaa4a7539f6f04abc6243619c56f8530c53bf9b023e1269df5f7816dd"}, + {file = "orjson-3.10.12-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:36b4aa31e0f6a1aeeb6f8377769ca5d125db000f05c20e54163aef1d3fe8e833"}, + {file = "orjson-3.10.12-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:5535163054d6cbf2796f93e4f0dbc800f61914c0e3c4ed8499cf6ece22b4a3da"}, + {file = "orjson-3.10.12-cp38-none-win32.whl", hash = "sha256:90a5551f6f5a5fa07010bf3d0b4ca2de21adafbbc0af6cb700b63cd767266cb9"}, + {file = "orjson-3.10.12-cp38-none-win_amd64.whl", hash = "sha256:703a2fb35a06cdd45adf5d733cf613cbc0cb3ae57643472b16bc22d325b5fb6c"}, + {file = "orjson-3.10.12-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:f29de3ef71a42a5822765def1febfb36e0859d33abf5c2ad240acad5c6a1b78d"}, + {file = "orjson-3.10.12-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:de365a42acc65d74953f05e4772c974dad6c51cfc13c3240899f534d611be967"}, + {file = "orjson-3.10.12-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:91a5a0158648a67ff0004cb0df5df7dcc55bfc9ca154d9c01597a23ad54c8d0c"}, + {file = "orjson-3.10.12-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c47ce6b8d90fe9646a25b6fb52284a14ff215c9595914af63a5933a49972ce36"}, + {file = "orjson-3.10.12-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0eee4c2c5bfb5c1b47a5db80d2ac7aaa7e938956ae88089f098aff2c0f35d5d8"}, + {file = "orjson-3.10.12-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:35d3081bbe8b86587eb5c98a73b97f13d8f9fea685cf91a579beddacc0d10566"}, + {file = "orjson-3.10.12-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:73c23a6e90383884068bc2dba83d5222c9fcc3b99a0ed2411d38150734236755"}, + {file = "orjson-3.10.12-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:5472be7dc3269b4b52acba1433dac239215366f89dc1d8d0e64029abac4e714e"}, + {file = "orjson-3.10.12-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:7319cda750fca96ae5973efb31b17d97a5c5225ae0bc79bf5bf84df9e1ec2ab6"}, + {file = "orjson-3.10.12-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:74d5ca5a255bf20b8def6a2b96b1e18ad37b4a122d59b154c458ee9494377f80"}, + {file = "orjson-3.10.12-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:ff31d22ecc5fb85ef62c7d4afe8301d10c558d00dd24274d4bbe464380d3cd69"}, + {file = "orjson-3.10.12-cp39-none-win32.whl", hash = "sha256:c22c3ea6fba91d84fcb4cda30e64aff548fcf0c44c876e681f47d61d24b12e6b"}, + {file = "orjson-3.10.12-cp39-none-win_amd64.whl", hash = "sha256:be604f60d45ace6b0b33dd990a66b4526f1a7a186ac411c942674625456ca548"}, + {file = "orjson-3.10.12.tar.gz", hash = "sha256:0a78bbda3aea0f9f079057ee1ee8a1ecf790d4f1af88dd67493c6b8ee52506ff"}, ] [[package]] @@ -558,17 +1237,6 @@ files = [ {file = "packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f"}, ] -[[package]] -name = "pastel" -version = "0.2.1" -description = "Bring colors to your terminal." -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -files = [ - {file = "pastel-0.2.1-py2.py3-none-any.whl", hash = "sha256:4349225fcdf6c2bb34d483e523475de5bb04a5c10ef711263452cb37d7dd4364"}, - {file = "pastel-0.2.1.tar.gz", hash = "sha256:e6581ac04e973cac858828c6202c1e1e81fee1dc7de7683f3e1ffe0bfd8a573d"}, -] - [[package]] name = "pluggy" version = "1.5.0" @@ -585,32 +1253,105 @@ dev = ["pre-commit", "tox"] testing = ["pytest", "pytest-benchmark"] [[package]] -name = "poethepoet" -version = "0.24.4" -description = "A task runner that works well with poetry." +name = "propcache" +version = "0.2.1" +description = "Accelerated property cache" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "poethepoet-0.24.4-py3-none-any.whl", hash = "sha256:fb4ea35d7f40fe2081ea917d2e4102e2310fda2cde78974050ca83896e229075"}, - {file = "poethepoet-0.24.4.tar.gz", hash = "sha256:ff4220843a87c888cbcb5312c8905214701d0af60ac7271795baa8369b428fef"}, + {file = "propcache-0.2.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:6b3f39a85d671436ee3d12c017f8fdea38509e4f25b28eb25877293c98c243f6"}, + {file = "propcache-0.2.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:39d51fbe4285d5db5d92a929e3e21536ea3dd43732c5b177c7ef03f918dff9f2"}, + {file = "propcache-0.2.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6445804cf4ec763dc70de65a3b0d9954e868609e83850a47ca4f0cb64bd79fea"}, + {file = "propcache-0.2.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f9479aa06a793c5aeba49ce5c5692ffb51fcd9a7016e017d555d5e2b0045d212"}, + {file = "propcache-0.2.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d9631c5e8b5b3a0fda99cb0d29c18133bca1e18aea9effe55adb3da1adef80d3"}, + {file = "propcache-0.2.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3156628250f46a0895f1f36e1d4fbe062a1af8718ec3ebeb746f1d23f0c5dc4d"}, + {file = "propcache-0.2.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b6fb63ae352e13748289f04f37868099e69dba4c2b3e271c46061e82c745634"}, + {file = "propcache-0.2.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:887d9b0a65404929641a9fabb6452b07fe4572b269d901d622d8a34a4e9043b2"}, + {file = "propcache-0.2.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a96dc1fa45bd8c407a0af03b2d5218392729e1822b0c32e62c5bf7eeb5fb3958"}, + {file = "propcache-0.2.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:a7e65eb5c003a303b94aa2c3852ef130230ec79e349632d030e9571b87c4698c"}, + {file = "propcache-0.2.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:999779addc413181912e984b942fbcc951be1f5b3663cd80b2687758f434c583"}, + {file = "propcache-0.2.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:19a0f89a7bb9d8048d9c4370c9c543c396e894c76be5525f5e1ad287f1750ddf"}, + {file = "propcache-0.2.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:1ac2f5fe02fa75f56e1ad473f1175e11f475606ec9bd0be2e78e4734ad575034"}, + {file = "propcache-0.2.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:574faa3b79e8ebac7cb1d7930f51184ba1ccf69adfdec53a12f319a06030a68b"}, + {file = "propcache-0.2.1-cp310-cp310-win32.whl", hash = "sha256:03ff9d3f665769b2a85e6157ac8b439644f2d7fd17615a82fa55739bc97863f4"}, + {file = "propcache-0.2.1-cp310-cp310-win_amd64.whl", hash = "sha256:2d3af2e79991102678f53e0dbf4c35de99b6b8b58f29a27ca0325816364caaba"}, + {file = "propcache-0.2.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:1ffc3cca89bb438fb9c95c13fc874012f7b9466b89328c3c8b1aa93cdcfadd16"}, + {file = "propcache-0.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f174bbd484294ed9fdf09437f889f95807e5f229d5d93588d34e92106fbf6717"}, + {file = "propcache-0.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:70693319e0b8fd35dd863e3e29513875eb15c51945bf32519ef52927ca883bc3"}, + {file = "propcache-0.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b480c6a4e1138e1aa137c0079b9b6305ec6dcc1098a8ca5196283e8a49df95a9"}, + {file = "propcache-0.2.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d27b84d5880f6d8aa9ae3edb253c59d9f6642ffbb2c889b78b60361eed449787"}, + {file = "propcache-0.2.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:857112b22acd417c40fa4595db2fe28ab900c8c5fe4670c7989b1c0230955465"}, + {file = "propcache-0.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cf6c4150f8c0e32d241436526f3c3f9cbd34429492abddbada2ffcff506c51af"}, + {file = "propcache-0.2.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:66d4cfda1d8ed687daa4bc0274fcfd5267873db9a5bc0418c2da19273040eeb7"}, + {file = "propcache-0.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c2f992c07c0fca81655066705beae35fc95a2fa7366467366db627d9f2ee097f"}, + {file = "propcache-0.2.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:4a571d97dbe66ef38e472703067021b1467025ec85707d57e78711c085984e54"}, + {file = "propcache-0.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:bb6178c241278d5fe853b3de743087be7f5f4c6f7d6d22a3b524d323eecec505"}, + {file = "propcache-0.2.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:ad1af54a62ffe39cf34db1aa6ed1a1873bd548f6401db39d8e7cd060b9211f82"}, + {file = "propcache-0.2.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:e7048abd75fe40712005bcfc06bb44b9dfcd8e101dda2ecf2f5aa46115ad07ca"}, + {file = "propcache-0.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:160291c60081f23ee43d44b08a7e5fb76681221a8e10b3139618c5a9a291b84e"}, + {file = "propcache-0.2.1-cp311-cp311-win32.whl", hash = "sha256:819ce3b883b7576ca28da3861c7e1a88afd08cc8c96908e08a3f4dd64a228034"}, + {file = "propcache-0.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:edc9fc7051e3350643ad929df55c451899bb9ae6d24998a949d2e4c87fb596d3"}, + {file = "propcache-0.2.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:081a430aa8d5e8876c6909b67bd2d937bfd531b0382d3fdedb82612c618bc41a"}, + {file = "propcache-0.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d2ccec9ac47cf4e04897619c0e0c1a48c54a71bdf045117d3a26f80d38ab1fb0"}, + {file = "propcache-0.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:14d86fe14b7e04fa306e0c43cdbeebe6b2c2156a0c9ce56b815faacc193e320d"}, + {file = "propcache-0.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:049324ee97bb67285b49632132db351b41e77833678432be52bdd0289c0e05e4"}, + {file = "propcache-0.2.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1cd9a1d071158de1cc1c71a26014dcdfa7dd3d5f4f88c298c7f90ad6f27bb46d"}, + {file = "propcache-0.2.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98110aa363f1bb4c073e8dcfaefd3a5cea0f0834c2aab23dda657e4dab2f53b5"}, + {file = "propcache-0.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:647894f5ae99c4cf6bb82a1bb3a796f6e06af3caa3d32e26d2350d0e3e3faf24"}, + {file = "propcache-0.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bfd3223c15bebe26518d58ccf9a39b93948d3dcb3e57a20480dfdd315356baff"}, + {file = "propcache-0.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d71264a80f3fcf512eb4f18f59423fe82d6e346ee97b90625f283df56aee103f"}, + {file = "propcache-0.2.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:e73091191e4280403bde6c9a52a6999d69cdfde498f1fdf629105247599b57ec"}, + {file = "propcache-0.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:3935bfa5fede35fb202c4b569bb9c042f337ca4ff7bd540a0aa5e37131659348"}, + {file = "propcache-0.2.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:f508b0491767bb1f2b87fdfacaba5f7eddc2f867740ec69ece6d1946d29029a6"}, + {file = "propcache-0.2.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:1672137af7c46662a1c2be1e8dc78cb6d224319aaa40271c9257d886be4363a6"}, + {file = "propcache-0.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b74c261802d3d2b85c9df2dfb2fa81b6f90deeef63c2db9f0e029a3cac50b518"}, + {file = "propcache-0.2.1-cp312-cp312-win32.whl", hash = "sha256:d09c333d36c1409d56a9d29b3a1b800a42c76a57a5a8907eacdbce3f18768246"}, + {file = "propcache-0.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:c214999039d4f2a5b2073ac506bba279945233da8c786e490d411dfc30f855c1"}, + {file = "propcache-0.2.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:aca405706e0b0a44cc6bfd41fbe89919a6a56999157f6de7e182a990c36e37bc"}, + {file = "propcache-0.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:12d1083f001ace206fe34b6bdc2cb94be66d57a850866f0b908972f90996b3e9"}, + {file = "propcache-0.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d93f3307ad32a27bda2e88ec81134b823c240aa3abb55821a8da553eed8d9439"}, + {file = "propcache-0.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ba278acf14471d36316159c94a802933d10b6a1e117b8554fe0d0d9b75c9d536"}, + {file = "propcache-0.2.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4e6281aedfca15301c41f74d7005e6e3f4ca143584ba696ac69df4f02f40d629"}, + {file = "propcache-0.2.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5b750a8e5a1262434fb1517ddf64b5de58327f1adc3524a5e44c2ca43305eb0b"}, + {file = "propcache-0.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf72af5e0fb40e9babf594308911436c8efde3cb5e75b6f206c34ad18be5c052"}, + {file = "propcache-0.2.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b2d0a12018b04f4cb820781ec0dffb5f7c7c1d2a5cd22bff7fb055a2cb19ebce"}, + {file = "propcache-0.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e800776a79a5aabdb17dcc2346a7d66d0777e942e4cd251defeb084762ecd17d"}, + {file = "propcache-0.2.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:4160d9283bd382fa6c0c2b5e017acc95bc183570cd70968b9202ad6d8fc48dce"}, + {file = "propcache-0.2.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:30b43e74f1359353341a7adb783c8f1b1c676367b011709f466f42fda2045e95"}, + {file = "propcache-0.2.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:58791550b27d5488b1bb52bc96328456095d96206a250d28d874fafe11b3dfaf"}, + {file = "propcache-0.2.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:0f022d381747f0dfe27e99d928e31bc51a18b65bb9e481ae0af1380a6725dd1f"}, + {file = "propcache-0.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:297878dc9d0a334358f9b608b56d02e72899f3b8499fc6044133f0d319e2ec30"}, + {file = "propcache-0.2.1-cp313-cp313-win32.whl", hash = "sha256:ddfab44e4489bd79bda09d84c430677fc7f0a4939a73d2bba3073036f487a0a6"}, + {file = "propcache-0.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:556fc6c10989f19a179e4321e5d678db8eb2924131e64652a51fe83e4c3db0e1"}, + {file = "propcache-0.2.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:6a9a8c34fb7bb609419a211e59da8887eeca40d300b5ea8e56af98f6fbbb1541"}, + {file = "propcache-0.2.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ae1aa1cd222c6d205853b3013c69cd04515f9d6ab6de4b0603e2e1c33221303e"}, + {file = "propcache-0.2.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:accb6150ce61c9c4b7738d45550806aa2b71c7668c6942f17b0ac182b6142fd4"}, + {file = "propcache-0.2.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5eee736daafa7af6d0a2dc15cc75e05c64f37fc37bafef2e00d77c14171c2097"}, + {file = "propcache-0.2.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f7a31fc1e1bd362874863fdeed71aed92d348f5336fd84f2197ba40c59f061bd"}, + {file = "propcache-0.2.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cba4cfa1052819d16699e1d55d18c92b6e094d4517c41dd231a8b9f87b6fa681"}, + {file = "propcache-0.2.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f089118d584e859c62b3da0892b88a83d611c2033ac410e929cb6754eec0ed16"}, + {file = "propcache-0.2.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:781e65134efaf88feb447e8c97a51772aa75e48b794352f94cb7ea717dedda0d"}, + {file = "propcache-0.2.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:31f5af773530fd3c658b32b6bdc2d0838543de70eb9a2156c03e410f7b0d3aae"}, + {file = "propcache-0.2.1-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:a7a078f5d37bee6690959c813977da5291b24286e7b962e62a94cec31aa5188b"}, + {file = "propcache-0.2.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:cea7daf9fc7ae6687cf1e2c049752f19f146fdc37c2cc376e7d0032cf4f25347"}, + {file = "propcache-0.2.1-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:8b3489ff1ed1e8315674d0775dc7d2195fb13ca17b3808721b54dbe9fd020faf"}, + {file = "propcache-0.2.1-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:9403db39be1393618dd80c746cb22ccda168efce239c73af13c3763ef56ffc04"}, + {file = "propcache-0.2.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:5d97151bc92d2b2578ff7ce779cdb9174337390a535953cbb9452fb65164c587"}, + {file = "propcache-0.2.1-cp39-cp39-win32.whl", hash = "sha256:9caac6b54914bdf41bcc91e7eb9147d331d29235a7c967c150ef5df6464fd1bb"}, + {file = "propcache-0.2.1-cp39-cp39-win_amd64.whl", hash = "sha256:92fc4500fcb33899b05ba73276dfb684a20d31caa567b7cb5252d48f896a91b1"}, + {file = "propcache-0.2.1-py3-none-any.whl", hash = "sha256:52277518d6aae65536e9cea52d4e7fd2f7a66f4aa2d30ed3f2fcea620ace3c54"}, + {file = "propcache-0.2.1.tar.gz", hash = "sha256:3f77ce728b19cb537714499928fe800c3dda29e8d9428778fc7c186da4c09a64"}, ] -[package.dependencies] -pastel = ">=0.2.1,<0.3.0" -tomli = ">=1.2.2" - -[package.extras] -poetry-plugin = ["poetry (>=1.0,<2.0)"] - [[package]] name = "pydantic" -version = "2.10.1" +version = "2.10.3" description = "Data validation using Python type hints" optional = false python-versions = ">=3.8" files = [ - {file = "pydantic-2.10.1-py3-none-any.whl", hash = "sha256:a8d20db84de64cf4a7d59e899c2caf0fe9d660c7cfc482528e7020d7dd189a7e"}, - {file = "pydantic-2.10.1.tar.gz", hash = "sha256:a4daca2dc0aa429555e0656d6bf94873a7dc5f54ee42b1f5873d666fb3f35560"}, + {file = "pydantic-2.10.3-py3-none-any.whl", hash = "sha256:be04d85bbc7b65651c5f8e6b9976ed9c6f41782a55524cef079a34a0bb82144d"}, + {file = "pydantic-2.10.3.tar.gz", hash = "sha256:cb5ac360ce894ceacd69c403187900a02c4b20b693a9dd1d643e1effab9eadf9"}, ] [package.dependencies] @@ -962,6 +1703,54 @@ files = [ {file = "sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc"}, ] +[[package]] +name = "sqlalchemy" +version = "2.0.36" +description = "Database Abstraction Library" +optional = false +python-versions = ">=3.7" +files = [ + {file = "SQLAlchemy-2.0.36-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c245b1fbade9c35e5bd3b64270ab49ce990369018289ecfde3f9c318411aaa07"}, + {file = "SQLAlchemy-2.0.36-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f9511d8dd4a6e9271d07d150fb2f81874a3c8c95e11ff9af3a2dfc35fe42ee44"}, + {file = "SQLAlchemy-2.0.36-cp310-cp310-win32.whl", hash = "sha256:c3f3631693003d8e585d4200730616b78fafd5a01ef8b698f6967da5c605b3fa"}, + {file = "SQLAlchemy-2.0.36-cp310-cp310-win_amd64.whl", hash = "sha256:a86bfab2ef46d63300c0f06936bd6e6c0105faa11d509083ba8f2f9d237fb5b5"}, + {file = "SQLAlchemy-2.0.36-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2519f3a5d0517fc159afab1015e54bb81b4406c278749779be57a569d8d1bb0d"}, + {file = "SQLAlchemy-2.0.36-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:39769a115f730d683b0eb7b694db9789267bcd027326cccc3125e862eb03bfd8"}, + {file = "SQLAlchemy-2.0.36-cp311-cp311-win32.whl", hash = "sha256:66bffbad8d6271bb1cc2f9a4ea4f86f80fe5e2e3e501a5ae2a3dc6a76e604e6f"}, + {file = "SQLAlchemy-2.0.36-cp311-cp311-win_amd64.whl", hash = "sha256:23623166bfefe1487d81b698c423f8678e80df8b54614c2bf4b4cfcd7c711959"}, + {file = "SQLAlchemy-2.0.36-py3-none-any.whl", hash = "sha256:fddbe92b4760c6f5d48162aef14824add991aeda8ddadb3c31d56eb15ca69f8e"}, + {file = "sqlalchemy-2.0.36.tar.gz", hash = "sha256:7f2767680b6d2398aea7082e45a774b2b0767b5c8d8ffb9c8b683088ea9b29c5"}, +] + +[package.dependencies] +greenlet = {version = "!=0.4.17", markers = "python_version < \"3.13\" and (platform_machine == \"aarch64\" or platform_machine == \"ppc64le\" or platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"AMD64\" or platform_machine == \"win32\" or platform_machine == \"WIN32\")"} +typing-extensions = ">=4.6.0" + +[package.extras] +aiomysql = ["aiomysql (>=0.2.0)", "greenlet (!=0.4.17)"] +aioodbc = ["aioodbc", "greenlet (!=0.4.17)"] +aiosqlite = ["aiosqlite", "greenlet (!=0.4.17)", "typing_extensions (!=3.10.0.1)"] +asyncio = ["greenlet (!=0.4.17)"] +asyncmy = ["asyncmy (>=0.2.3,!=0.2.4,!=0.2.6)", "greenlet (!=0.4.17)"] +mariadb-connector = ["mariadb (>=1.0.1,!=1.1.2,!=1.1.5,!=1.1.10)"] +mssql = ["pyodbc"] +mssql-pymssql = ["pymssql"] +mssql-pyodbc = ["pyodbc"] +mypy = ["mypy (>=0.910)"] +mysql = ["mysqlclient (>=1.4.0)"] +mysql-connector = ["mysql-connector-python"] +oracle = ["cx_oracle (>=8)"] +oracle-oracledb = ["oracledb (>=1.0.1)"] +postgresql = ["psycopg2 (>=2.7)"] +postgresql-asyncpg = ["asyncpg", "greenlet (!=0.4.17)"] +postgresql-pg8000 = ["pg8000 (>=1.29.1)"] +postgresql-psycopg = ["psycopg (>=3.0.7)"] +postgresql-psycopg2binary = ["psycopg2-binary"] +postgresql-psycopg2cffi = ["psycopg2cffi"] +postgresql-psycopgbinary = ["psycopg[binary] (>=3.0.7)"] +pymysql = ["pymysql"] +sqlcipher = ["sqlcipher3_binary"] + [[package]] name = "sse-starlette" version = "1.8.2" @@ -1014,13 +1803,43 @@ test = ["pytest", "tornado (>=4.5)", "typeguard"] [[package]] name = "tomli" -version = "2.1.0" +version = "2.2.1" description = "A lil' TOML parser" optional = false python-versions = ">=3.8" files = [ - {file = "tomli-2.1.0-py3-none-any.whl", hash = "sha256:a5c57c3d1c56f5ccdf89f6523458f60ef716e210fc47c4cfb188c5ba473e0391"}, - {file = "tomli-2.1.0.tar.gz", hash = "sha256:3f646cae2aec94e17d04973e4249548320197cfabdf130015d023de4b74d8ab8"}, + {file = "tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249"}, + {file = "tomli-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6"}, + {file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a"}, + {file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee"}, + {file = "tomli-2.2.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e"}, + {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4"}, + {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106"}, + {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8"}, + {file = "tomli-2.2.1-cp311-cp311-win32.whl", hash = "sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff"}, + {file = "tomli-2.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b"}, + {file = "tomli-2.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea"}, + {file = "tomli-2.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8"}, + {file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192"}, + {file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222"}, + {file = "tomli-2.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77"}, + {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6"}, + {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd"}, + {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e"}, + {file = "tomli-2.2.1-cp312-cp312-win32.whl", hash = "sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98"}, + {file = "tomli-2.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4"}, + {file = "tomli-2.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7"}, + {file = "tomli-2.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c"}, + {file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13"}, + {file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281"}, + {file = "tomli-2.2.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272"}, + {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140"}, + {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2"}, + {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744"}, + {file = "tomli-2.2.1-cp313-cp313-win32.whl", hash = "sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec"}, + {file = "tomli-2.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69"}, + {file = "tomli-2.2.1-py3-none-any.whl", hash = "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc"}, + {file = "tomli-2.2.1.tar.gz", hash = "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff"}, ] [[package]] @@ -1147,10 +1966,106 @@ files = [ [package.extras] watchmedo = ["PyYAML (>=3.10)"] +[[package]] +name = "yarl" +version = "1.18.3" +description = "Yet another URL library" +optional = false +python-versions = ">=3.9" +files = [ + {file = "yarl-1.18.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7df647e8edd71f000a5208fe6ff8c382a1de8edfbccdbbfe649d263de07d8c34"}, + {file = "yarl-1.18.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c69697d3adff5aa4f874b19c0e4ed65180ceed6318ec856ebc423aa5850d84f7"}, + {file = "yarl-1.18.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:602d98f2c2d929f8e697ed274fbadc09902c4025c5a9963bf4e9edfc3ab6f7ed"}, + {file = "yarl-1.18.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c654d5207c78e0bd6d749f6dae1dcbbfde3403ad3a4b11f3c5544d9906969dde"}, + {file = "yarl-1.18.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5094d9206c64181d0f6e76ebd8fb2f8fe274950a63890ee9e0ebfd58bf9d787b"}, + {file = "yarl-1.18.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:35098b24e0327fc4ebdc8ffe336cee0a87a700c24ffed13161af80124b7dc8e5"}, + {file = "yarl-1.18.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3236da9272872443f81fedc389bace88408f64f89f75d1bdb2256069a8730ccc"}, + {file = "yarl-1.18.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e2c08cc9b16f4f4bc522771d96734c7901e7ebef70c6c5c35dd0f10845270bcd"}, + {file = "yarl-1.18.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:80316a8bd5109320d38eef8833ccf5f89608c9107d02d2a7f985f98ed6876990"}, + {file = "yarl-1.18.3-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:c1e1cc06da1491e6734f0ea1e6294ce00792193c463350626571c287c9a704db"}, + {file = "yarl-1.18.3-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:fea09ca13323376a2fdfb353a5fa2e59f90cd18d7ca4eaa1fd31f0a8b4f91e62"}, + {file = "yarl-1.18.3-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:e3b9fd71836999aad54084906f8663dffcd2a7fb5cdafd6c37713b2e72be1760"}, + {file = "yarl-1.18.3-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:757e81cae69244257d125ff31663249b3013b5dc0a8520d73694aed497fb195b"}, + {file = "yarl-1.18.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b1771de9944d875f1b98a745bc547e684b863abf8f8287da8466cf470ef52690"}, + {file = "yarl-1.18.3-cp310-cp310-win32.whl", hash = "sha256:8874027a53e3aea659a6d62751800cf6e63314c160fd607489ba5c2edd753cf6"}, + {file = "yarl-1.18.3-cp310-cp310-win_amd64.whl", hash = "sha256:93b2e109287f93db79210f86deb6b9bbb81ac32fc97236b16f7433db7fc437d8"}, + {file = "yarl-1.18.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8503ad47387b8ebd39cbbbdf0bf113e17330ffd339ba1144074da24c545f0069"}, + {file = "yarl-1.18.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:02ddb6756f8f4517a2d5e99d8b2f272488e18dd0bfbc802f31c16c6c20f22193"}, + {file = "yarl-1.18.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:67a283dd2882ac98cc6318384f565bffc751ab564605959df4752d42483ad889"}, + {file = "yarl-1.18.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d980e0325b6eddc81331d3f4551e2a333999fb176fd153e075c6d1c2530aa8a8"}, + {file = "yarl-1.18.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b643562c12680b01e17239be267bc306bbc6aac1f34f6444d1bded0c5ce438ca"}, + {file = "yarl-1.18.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c017a3b6df3a1bd45b9fa49a0f54005e53fbcad16633870104b66fa1a30a29d8"}, + {file = "yarl-1.18.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75674776d96d7b851b6498f17824ba17849d790a44d282929c42dbb77d4f17ae"}, + {file = "yarl-1.18.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ccaa3a4b521b780a7e771cc336a2dba389a0861592bbce09a476190bb0c8b4b3"}, + {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2d06d3005e668744e11ed80812e61efd77d70bb7f03e33c1598c301eea20efbb"}, + {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:9d41beda9dc97ca9ab0b9888cb71f7539124bc05df02c0cff6e5acc5a19dcc6e"}, + {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ba23302c0c61a9999784e73809427c9dbedd79f66a13d84ad1b1943802eaaf59"}, + {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:6748dbf9bfa5ba1afcc7556b71cda0d7ce5f24768043a02a58846e4a443d808d"}, + {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:0b0cad37311123211dc91eadcb322ef4d4a66008d3e1bdc404808992260e1a0e"}, + {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0fb2171a4486bb075316ee754c6d8382ea6eb8b399d4ec62fde2b591f879778a"}, + {file = "yarl-1.18.3-cp311-cp311-win32.whl", hash = "sha256:61b1a825a13bef4a5f10b1885245377d3cd0bf87cba068e1d9a88c2ae36880e1"}, + {file = "yarl-1.18.3-cp311-cp311-win_amd64.whl", hash = "sha256:b9d60031cf568c627d028239693fd718025719c02c9f55df0a53e587aab951b5"}, + {file = "yarl-1.18.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:1dd4bdd05407ced96fed3d7f25dbbf88d2ffb045a0db60dbc247f5b3c5c25d50"}, + {file = "yarl-1.18.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7c33dd1931a95e5d9a772d0ac5e44cac8957eaf58e3c8da8c1414de7dd27c576"}, + {file = "yarl-1.18.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:25b411eddcfd56a2f0cd6a384e9f4f7aa3efee14b188de13048c25b5e91f1640"}, + {file = "yarl-1.18.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:436c4fc0a4d66b2badc6c5fc5ef4e47bb10e4fd9bf0c79524ac719a01f3607c2"}, + {file = "yarl-1.18.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e35ef8683211db69ffe129a25d5634319a677570ab6b2eba4afa860f54eeaf75"}, + {file = "yarl-1.18.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:84b2deecba4a3f1a398df819151eb72d29bfeb3b69abb145a00ddc8d30094512"}, + {file = "yarl-1.18.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:00e5a1fea0fd4f5bfa7440a47eff01d9822a65b4488f7cff83155a0f31a2ecba"}, + {file = "yarl-1.18.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d0e883008013c0e4aef84dcfe2a0b172c4d23c2669412cf5b3371003941f72bb"}, + {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5a3f356548e34a70b0172d8890006c37be92995f62d95a07b4a42e90fba54272"}, + {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:ccd17349166b1bee6e529b4add61727d3f55edb7babbe4069b5764c9587a8cc6"}, + {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b958ddd075ddba5b09bb0be8a6d9906d2ce933aee81100db289badbeb966f54e"}, + {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c7d79f7d9aabd6011004e33b22bc13056a3e3fb54794d138af57f5ee9d9032cb"}, + {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:4891ed92157e5430874dad17b15eb1fda57627710756c27422200c52d8a4e393"}, + {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ce1af883b94304f493698b00d0f006d56aea98aeb49d75ec7d98cd4a777e9285"}, + {file = "yarl-1.18.3-cp312-cp312-win32.whl", hash = "sha256:f91c4803173928a25e1a55b943c81f55b8872f0018be83e3ad4938adffb77dd2"}, + {file = "yarl-1.18.3-cp312-cp312-win_amd64.whl", hash = "sha256:7e2ee16578af3b52ac2f334c3b1f92262f47e02cc6193c598502bd46f5cd1477"}, + {file = "yarl-1.18.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:90adb47ad432332d4f0bc28f83a5963f426ce9a1a8809f5e584e704b82685dcb"}, + {file = "yarl-1.18.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:913829534200eb0f789d45349e55203a091f45c37a2674678744ae52fae23efa"}, + {file = "yarl-1.18.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ef9f7768395923c3039055c14334ba4d926f3baf7b776c923c93d80195624782"}, + {file = "yarl-1.18.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88a19f62ff30117e706ebc9090b8ecc79aeb77d0b1f5ec10d2d27a12bc9f66d0"}, + {file = "yarl-1.18.3-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e17c9361d46a4d5addf777c6dd5eab0715a7684c2f11b88c67ac37edfba6c482"}, + {file = "yarl-1.18.3-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1a74a13a4c857a84a845505fd2d68e54826a2cd01935a96efb1e9d86c728e186"}, + {file = "yarl-1.18.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:41f7ce59d6ee7741af71d82020346af364949314ed3d87553763a2df1829cc58"}, + {file = "yarl-1.18.3-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f52a265001d830bc425f82ca9eabda94a64a4d753b07d623a9f2863fde532b53"}, + {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:82123d0c954dc58db301f5021a01854a85bf1f3bb7d12ae0c01afc414a882ca2"}, + {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:2ec9bbba33b2d00999af4631a3397d1fd78290c48e2a3e52d8dd72db3a067ac8"}, + {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:fbd6748e8ab9b41171bb95c6142faf068f5ef1511935a0aa07025438dd9a9bc1"}, + {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:877d209b6aebeb5b16c42cbb377f5f94d9e556626b1bfff66d7b0d115be88d0a"}, + {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:b464c4ab4bfcb41e3bfd3f1c26600d038376c2de3297760dfe064d2cb7ea8e10"}, + {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8d39d351e7faf01483cc7ff7c0213c412e38e5a340238826be7e0e4da450fdc8"}, + {file = "yarl-1.18.3-cp313-cp313-win32.whl", hash = "sha256:61ee62ead9b68b9123ec24bc866cbef297dd266175d53296e2db5e7f797f902d"}, + {file = "yarl-1.18.3-cp313-cp313-win_amd64.whl", hash = "sha256:578e281c393af575879990861823ef19d66e2b1d0098414855dd367e234f5b3c"}, + {file = "yarl-1.18.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:61e5e68cb65ac8f547f6b5ef933f510134a6bf31bb178be428994b0cb46c2a04"}, + {file = "yarl-1.18.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:fe57328fbc1bfd0bd0514470ac692630f3901c0ee39052ae47acd1d90a436719"}, + {file = "yarl-1.18.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a440a2a624683108a1b454705ecd7afc1c3438a08e890a1513d468671d90a04e"}, + {file = "yarl-1.18.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:09c7907c8548bcd6ab860e5f513e727c53b4a714f459b084f6580b49fa1b9cee"}, + {file = "yarl-1.18.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b4f6450109834af88cb4cc5ecddfc5380ebb9c228695afc11915a0bf82116789"}, + {file = "yarl-1.18.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a9ca04806f3be0ac6d558fffc2fdf8fcef767e0489d2684a21912cc4ed0cd1b8"}, + {file = "yarl-1.18.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:77a6e85b90a7641d2e07184df5557132a337f136250caafc9ccaa4a2a998ca2c"}, + {file = "yarl-1.18.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6333c5a377c8e2f5fae35e7b8f145c617b02c939d04110c76f29ee3676b5f9a5"}, + {file = "yarl-1.18.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:0b3c92fa08759dbf12b3a59579a4096ba9af8dd344d9a813fc7f5070d86bbab1"}, + {file = "yarl-1.18.3-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:4ac515b860c36becb81bb84b667466885096b5fc85596948548b667da3bf9f24"}, + {file = "yarl-1.18.3-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:045b8482ce9483ada4f3f23b3774f4e1bf4f23a2d5c912ed5170f68efb053318"}, + {file = "yarl-1.18.3-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:a4bb030cf46a434ec0225bddbebd4b89e6471814ca851abb8696170adb163985"}, + {file = "yarl-1.18.3-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:54d6921f07555713b9300bee9c50fb46e57e2e639027089b1d795ecd9f7fa910"}, + {file = "yarl-1.18.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:1d407181cfa6e70077df3377938c08012d18893f9f20e92f7d2f314a437c30b1"}, + {file = "yarl-1.18.3-cp39-cp39-win32.whl", hash = "sha256:ac36703a585e0929b032fbaab0707b75dc12703766d0b53486eabd5139ebadd5"}, + {file = "yarl-1.18.3-cp39-cp39-win_amd64.whl", hash = "sha256:ba87babd629f8af77f557b61e49e7c7cac36f22f871156b91e10a6e9d4f829e9"}, + {file = "yarl-1.18.3-py3-none-any.whl", hash = "sha256:b57f4f58099328dfb26c6a771d09fb20dbbae81d20cfb66141251ea063bd101b"}, + {file = "yarl-1.18.3.tar.gz", hash = "sha256:ac1801c45cbf77b6c99242eeff4fffb5e4e73a800b5c4ad4fc0be5def634d2e1"}, +] + +[package.dependencies] +idna = ">=2.0" +multidict = ">=4.0" +propcache = ">=0.2.0" + [extras] serve = [] [metadata] lock-version = "2.0" python-versions = ">=3.9,<4.0" -content-hash = "ed6ba14db90499ff27fefaab277bb8b879a48e024f4dabf944d76d8f7375002b" +content-hash = "c666eaa9945394483db2cf56ec2c147869b2fcefb767184c83c4f0e2f211ea2b" diff --git a/libs/cli/pyproject.toml b/libs/cli/pyproject.toml index 004d48b3bb3..3e434fc8e6a 100644 --- a/libs/cli/pyproject.toml +++ b/libs/cli/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "langchain-cli" -version = "0.0.33" +version = "0.0.34" description = "CLI for interacting with LangChain" authors = ["Erick Friis "] readme = "README.md" @@ -25,16 +25,18 @@ langchain = "langchain_cli.cli:app" langchain-cli = "langchain_cli.cli:app" [tool.poetry.group.dev.dependencies] -poethepoet = "^0.24.1" pytest = "^7.4.2" pytest-watch = "^4.2.0" [tool.poetry.group.lint.dependencies] ruff = "^0.5" +mypy = "^1.13.0" [tool.poetry.group.test.dependencies] +langchain = {path = "../langchain", develop = true} [tool.poetry.group.typing.dependencies] +langchain = {path = "../langchain", develop = true} [tool.poetry.group.test_integration.dependencies] @@ -50,22 +52,11 @@ select = [ "T201", # print ] -[tool.poe.tasks] -test = "poetry run pytest tests" -watch = "poetry run ptw" -version = "poetry version --short" -bump = ["_bump_1", "_bump_2"] -lint = ["_lint", "_check_formatting"] -format = ["_format", "_lint_fix"] - -_bump_2.shell = """sed -i "" "/^__version__ =/c\\ \n__version__ = \\"$version\\"\n" langchain_cli/cli.py""" -_bump_2.uses = { version = "version" } - -_bump_1 = "poetry version patch" -_check_formatting = "poetry run ruff format . --diff" -_lint = "poetry run ruff check ." -_format = "poetry run ruff format ." -_lint_fix = "poetry run ruff check . --fix" +[tool.mypy] +exclude = [ + "langchain_cli/integration_template", + "langchain_cli/package_template", +] [build-system] requires = ["poetry-core"] diff --git a/libs/cli/scripts/generate_migrations.py b/libs/cli/scripts/generate_migrations.py index 38c830443c7..11b5a8a6b0e 100644 --- a/libs/cli/scripts/generate_migrations.py +++ b/libs/cli/scripts/generate_migrations.py @@ -1,3 +1,4 @@ +# type: ignore """Script to generate migrations for the migration script.""" import json diff --git a/libs/cli/tests/integration_tests/test_compile.py b/libs/cli/tests/integration_tests/test_compile.py new file mode 100644 index 00000000000..33ecccdfa0f --- /dev/null +++ b/libs/cli/tests/integration_tests/test_compile.py @@ -0,0 +1,7 @@ +import pytest + + +@pytest.mark.compile +def test_placeholder() -> None: + """Used for compiling integration tests without running any real tests.""" + pass diff --git a/libs/cli/tests/unit_tests/migrate/cli_runner/test_cli.py b/libs/cli/tests/unit_tests/migrate/cli_runner/test_cli.py index 4fbeae295ba..3cc57112ead 100644 --- a/libs/cli/tests/unit_tests/migrate/cli_runner/test_cli.py +++ b/libs/cli/tests/unit_tests/migrate/cli_runner/test_cli.py @@ -41,6 +41,7 @@ def find_issue(current: Folder, expected: Folder) -> str: return "Unknown" +@pytest.mark.xfail(reason="grit may not be installed in env") def test_command_line(tmp_path: Path) -> None: runner = CliRunner() diff --git a/libs/community/README.md b/libs/community/README.md index 38240d2c948..02b1e754764 100644 --- a/libs/community/README.md +++ b/libs/community/README.md @@ -13,7 +13,7 @@ pip install langchain-community LangChain Community contains third-party integrations that implement the base interfaces defined in LangChain Core, making them ready-to-use in any LangChain application. -For full documentation see the [API reference](https://api.python.langchain.com/en/stable/community_api_reference.html). +For full documentation see the [API reference](https://python.langchain.com/api_reference/community/index.html). ![Diagram outlining the hierarchical organization of the LangChain framework, displaying the interconnected parts across multiple layers.](https://raw.githubusercontent.com/langchain-ai/langchain/e1d113ea84a2edcf4a7709fc5be0e972ea74a5d9/docs/static/svg/langchain_stack_112024.svg "LangChain Framework Overview") diff --git a/libs/community/extended_testing_deps.txt b/libs/community/extended_testing_deps.txt index d331fb66e85..fc208a71ef2 100644 --- a/libs/community/extended_testing_deps.txt +++ b/libs/community/extended_testing_deps.txt @@ -46,6 +46,7 @@ motor>=3.3.1,<4 msal>=1.25.0,<2 mwparserfromhell>=0.6.4,<0.7 mwxml>=0.3.3,<0.4 +needle-python>=0.4 networkx>=3.2.1,<4 newspaper3k>=0.2.8,<0.3 numexpr>=2.8.6,<3 diff --git a/libs/community/langchain_community/document_loaders/__init__.py b/libs/community/langchain_community/document_loaders/__init__.py index 2576093d3d4..8a56f918ab6 100644 --- a/libs/community/langchain_community/document_loaders/__init__.py +++ b/libs/community/langchain_community/document_loaders/__init__.py @@ -299,6 +299,9 @@ if TYPE_CHECKING: from langchain_community.document_loaders.mongodb import ( MongodbLoader, ) + from langchain_community.document_loaders.needle import ( + NeedleLoader, + ) from langchain_community.document_loaders.news import ( NewsURLLoader, ) @@ -631,6 +634,7 @@ _module_lookup = { "MergedDataLoader": "langchain_community.document_loaders.merge", "ModernTreasuryLoader": "langchain_community.document_loaders.modern_treasury", "MongodbLoader": "langchain_community.document_loaders.mongodb", + "NeedleLoader": "langchain_community.document_loaders.needle", "NewsURLLoader": "langchain_community.document_loaders.news", "NotebookLoader": "langchain_community.document_loaders.notebook", "NotionDBLoader": "langchain_community.document_loaders.notiondb", @@ -837,6 +841,7 @@ __all__ = [ "MergedDataLoader", "ModernTreasuryLoader", "MongodbLoader", + "NeedleLoader", "NewsURLLoader", "NotebookLoader", "NotionDBLoader", diff --git a/libs/community/langchain_community/document_loaders/needle.py b/libs/community/langchain_community/document_loaders/needle.py new file mode 100644 index 00000000000..03b9ee0c0e0 --- /dev/null +++ b/libs/community/langchain_community/document_loaders/needle.py @@ -0,0 +1,164 @@ +from typing import Dict, Iterator, List, Optional + +from langchain_core.document_loaders.base import BaseLoader +from langchain_core.documents import Document + + +class NeedleLoader(BaseLoader): + """ + NeedleLoader is a document loader for managing documents stored in a collection. + + Setup: + Install the `needle-python` library and set your Needle API key. + + .. code-block:: bash + + pip install needle-python + export NEEDLE_API_KEY="your-api-key" + + Key init args: + - `needle_api_key` (Optional[str]): API key for authenticating with Needle. + - `collection_id` (str): Needle collection to load documents from. + + Usage: + .. code-block:: python + + from langchain_community.document_loaders.needle import NeedleLoader + + loader = NeedleLoader( + needle_api_key="your-api-key", + collection_id="your-collection-id" + ) + + # Load documents + documents = loader.load() + for doc in documents: + print(doc.metadata) + + # Lazy load documents + for doc in loader.lazy_load(): + print(doc.metadata) + """ + + def __init__( + self, + needle_api_key: Optional[str] = None, + collection_id: Optional[str] = None, + ) -> None: + """ + Initializes the NeedleLoader with API key and collection ID. + + Args: + needle_api_key (Optional[str]): API key for authenticating with Needle. + collection_id (Optional[str]): Identifier for the Needle collection. + + Raises: + ImportError: If the `needle-python` library is not installed. + ValueError: If the collection ID is not provided. + """ + try: + from needle.v1 import NeedleClient + except ImportError: + raise ImportError( + "Please install with `pip install needle-python` to use NeedleLoader." + ) + + super().__init__() + self.needle_api_key = needle_api_key + self.collection_id = collection_id + self.client: Optional[NeedleClient] = None + + if self.needle_api_key: + self.client = NeedleClient(api_key=self.needle_api_key) + + if not self.collection_id: + raise ValueError("Collection ID must be provided.") + + def _get_collection(self) -> None: + """ + Ensures the Needle collection is set and the client is initialized. + + Raises: + ValueError: If the Needle client is not initialized or + if the collection ID is missing. + """ + if self.client is None: + raise ValueError( + "NeedleClient is not initialized. Provide a valid API key." + ) + if not self.collection_id: + raise ValueError("Collection ID must be provided.") + + def add_files(self, files: Dict[str, str]) -> None: + """ + Adds files to the Needle collection. + + Args: + files (Dict[str, str]): Dictionary where keys are file names and values + are file URLs. + + Raises: + ImportError: If the `needle-python` library is not installed. + ValueError: If the collection is not properly initialized. + """ + try: + from needle.v1.models import FileToAdd + except ImportError: + raise ImportError( + "Please install with `pip install needle-python` to add files." + ) + + self._get_collection() + assert self.client is not None, "NeedleClient must be initialized." + + files_to_add = [FileToAdd(name=name, url=url) for name, url in files.items()] + + self.client.collections.files.add( + collection_id=self.collection_id, files=files_to_add + ) + + def _fetch_documents(self) -> List[Document]: + """ + Fetches metadata for documents from the Needle collection. + + Returns: + List[Document]: A list of documents with metadata. Content is excluded. + + Raises: + ValueError: If the collection is not properly initialized. + """ + self._get_collection() + assert self.client is not None, "NeedleClient must be initialized." + + files = self.client.collections.files.list(self.collection_id) + docs = [ + Document( + page_content="", # Needle doesn't provide file content fetching + metadata={ + "source": file.url, + "title": file.name, + "size": getattr(file, "size", None), + }, + ) + for file in files + if file.status == "indexed" + ] + return docs + + def load(self) -> List[Document]: + """ + Loads all documents from the Needle collection. + + Returns: + List[Document]: A list of documents from the collection. + """ + return self._fetch_documents() + + def lazy_load(self) -> Iterator[Document]: + """ + Lazily loads documents from the Needle collection. + + Yields: + Iterator[Document]: An iterator over the documents. + """ + yield from self._fetch_documents() diff --git a/libs/community/langchain_community/query_constructors/databricks_vector_search.py b/libs/community/langchain_community/query_constructors/databricks_vector_search.py index 03e7de8efa7..f79a690c9ba 100644 --- a/libs/community/langchain_community/query_constructors/databricks_vector_search.py +++ b/libs/community/langchain_community/query_constructors/databricks_vector_search.py @@ -90,5 +90,5 @@ class DatabricksVectorSearchTranslator(Visitor): if structured_query.filter is None: kwargs = {} else: - kwargs = {"filters": structured_query.filter.accept(self)} + kwargs = {"filter": structured_query.filter.accept(self)} return structured_query.query, kwargs diff --git a/libs/community/langchain_community/retrievers/__init__.py b/libs/community/langchain_community/retrievers/__init__.py index 75600eab6d5..ce4ac731bde 100644 --- a/libs/community/langchain_community/retrievers/__init__.py +++ b/libs/community/langchain_community/retrievers/__init__.py @@ -93,6 +93,7 @@ if TYPE_CHECKING: MilvusRetriever, ) from langchain_community.retrievers.nanopq import NanoPQRetriever + from langchain_community.retrievers.needle import NeedleRetriever from langchain_community.retrievers.outline import ( OutlineRetriever, ) @@ -173,6 +174,7 @@ _module_lookup = { "MetalRetriever": "langchain_community.retrievers.metal", "MilvusRetriever": "langchain_community.retrievers.milvus", "NanoPQRetriever": "langchain_community.retrievers.nanopq", + "NeedleRetriever": "langchain_community.retrievers.needle", "OutlineRetriever": "langchain_community.retrievers.outline", "PineconeHybridSearchRetriever": "langchain_community.retrievers.pinecone_hybrid_search", # noqa: E501 "PubMedRetriever": "langchain_community.retrievers.pubmed", @@ -229,6 +231,7 @@ __all__ = [ "MetalRetriever", "MilvusRetriever", "NanoPQRetriever", + "NeedleRetriever", "NeuralDBRetriever", "OutlineRetriever", "PineconeHybridSearchRetriever", diff --git a/libs/community/langchain_community/retrievers/bm25.py b/libs/community/langchain_community/retrievers/bm25.py index 543058c131a..70910ce170f 100644 --- a/libs/community/langchain_community/retrievers/bm25.py +++ b/libs/community/langchain_community/retrievers/bm25.py @@ -33,6 +33,7 @@ class BM25Retriever(BaseRetriever): cls, texts: Iterable[str], metadatas: Optional[Iterable[dict]] = None, + ids: Optional[Iterable[str]] = None, bm25_params: Optional[Dict[str, Any]] = None, preprocess_func: Callable[[str], List[str]] = default_preprocessing_func, **kwargs: Any, @@ -42,6 +43,7 @@ class BM25Retriever(BaseRetriever): Args: texts: A list of texts to vectorize. metadatas: A list of metadata dicts to associate with each text. + ids: A list of ids to associate with each text. bm25_params: Parameters to pass to the BM25 vectorizer. preprocess_func: A function to preprocess each text before vectorization. **kwargs: Any other arguments to pass to the retriever. @@ -61,7 +63,15 @@ class BM25Retriever(BaseRetriever): bm25_params = bm25_params or {} vectorizer = BM25Okapi(texts_processed, **bm25_params) metadatas = metadatas or ({} for _ in texts) - docs = [Document(page_content=t, metadata=m) for t, m in zip(texts, metadatas)] + if ids: + docs = [ + Document(page_content=t, metadata=m, id=i) + for t, m, i in zip(texts, metadatas, ids) + ] + else: + docs = [ + Document(page_content=t, metadata=m) for t, m in zip(texts, metadatas) + ] return cls( vectorizer=vectorizer, docs=docs, preprocess_func=preprocess_func, **kwargs ) @@ -86,11 +96,14 @@ class BM25Retriever(BaseRetriever): Returns: A BM25Retriever instance. """ - texts, metadatas = zip(*((d.page_content, d.metadata) for d in documents)) + texts, metadatas, ids = zip( + *((d.page_content, d.metadata, d.id) for d in documents) + ) return cls.from_texts( texts=texts, bm25_params=bm25_params, metadatas=metadatas, + ids=ids, preprocess_func=preprocess_func, **kwargs, ) diff --git a/libs/community/langchain_community/retrievers/needle.py b/libs/community/langchain_community/retrievers/needle.py new file mode 100644 index 00000000000..201d617fda4 --- /dev/null +++ b/libs/community/langchain_community/retrievers/needle.py @@ -0,0 +1,96 @@ +from typing import Any, List, Optional # noqa: I001 + +from langchain_core.callbacks import CallbackManagerForRetrieverRun +from langchain_core.documents import Document +from langchain_core.retrievers import BaseRetriever +from pydantic import BaseModel, Field + + +class NeedleRetriever(BaseRetriever, BaseModel): + """ + NeedleRetriever retrieves relevant documents or context from a Needle collection + based on a search query. + + Setup: + Install the `needle-python` library and set your Needle API key. + + .. code-block:: bash + + pip install needle-python + export NEEDLE_API_KEY="your-api-key" + + Key init args: + - `needle_api_key` (Optional[str]): The API key for authenticating with Needle. + - `collection_id` (str): The ID of the Needle collection to search in. + - `client` (Optional[NeedleClient]): An optional instance of the NeedleClient. + + Usage: + .. code-block:: python + + from langchain_community.retrievers.needle import NeedleRetriever + + retriever = NeedleRetriever( + needle_api_key="your-api-key", + collection_id="your-collection-id" + ) + + results = retriever.retrieve("example query") + for doc in results: + print(doc.page_content) + """ + + client: Optional[Any] = None + """Optional instance of NeedleClient.""" + needle_api_key: Optional[str] = Field(None, description="Needle API Key") + collection_id: Optional[str] = Field( + ..., description="The ID of the Needle collection to search in" + ) + + def _initialize_client(self) -> None: + """ + Initialize the NeedleClient with the provided API key. + + If a client instance is already provided, this method does nothing. + """ + try: + from needle.v1 import NeedleClient + except ImportError: + raise ImportError("Please install with `pip install needle-python`.") + + if not self.client: + self.client = NeedleClient(api_key=self.needle_api_key) + + def _search_collection(self, query: str) -> List[Document]: + """ + Search the Needle collection for relevant documents. + + Args: + query (str): The search query used to find relevant documents. + + Returns: + List[Document]: A list of documents matching the search query. + """ + self._initialize_client() + if self.client is None: + raise ValueError("NeedleClient is not initialized. Provide an API key.") + + results = self.client.collections.search( + collection_id=self.collection_id, text=query + ) + docs = [Document(page_content=result.content) for result in results] + return docs + + def _get_relevant_documents( + self, query: str, *, run_manager: CallbackManagerForRetrieverRun + ) -> List[Document]: + """ + Retrieve relevant documents based on the query. + + Args: + query (str): The query string used to search the collection. + Returns: + List[Document]: A list of documents relevant to the query. + """ + # The `run_manager` parameter is included to match the superclass signature, + # but it is not used in this implementation. + return self._search_collection(query) diff --git a/libs/community/langchain_community/utilities/pubmed.py b/libs/community/langchain_community/utilities/pubmed.py index e3b23cfa0ad..20185d0c285 100644 --- a/libs/community/langchain_community/utilities/pubmed.py +++ b/libs/community/langchain_community/utilities/pubmed.py @@ -31,6 +31,7 @@ class PubMedAPIWrapper(BaseModel): sleep_time: time to wait between retries. Default is 0.2 seconds. email: email address to be used for the PubMed API. + api_key: API key to be used for the PubMed API. """ parse: Any #: :meta private: @@ -47,6 +48,7 @@ class PubMedAPIWrapper(BaseModel): MAX_QUERY_LENGTH: int = 300 doc_content_chars_max: int = 2000 email: str = "your_email@example.com" + api_key: str = "" @model_validator(mode="before") @classmethod @@ -101,6 +103,8 @@ class PubMedAPIWrapper(BaseModel): + str({urllib.parse.quote(query)}) + f"&retmode=json&retmax={self.top_k_results}&usehistory=y" ) + if self.api_key != "": + url += f"&api_key={self.api_key}" result = urllib.request.urlopen(url) text = result.read().decode("utf-8") json_text = json.loads(text) @@ -135,6 +139,8 @@ class PubMedAPIWrapper(BaseModel): + "&webenv=" + webenv ) + if self.api_key != "": + url += f"&api_key={self.api_key}" retry = 0 while True: diff --git a/libs/community/langchain_community/vectorstores/tencentvectordb.py b/libs/community/langchain_community/vectorstores/tencentvectordb.py index c3bda890fe2..7d408c21132 100644 --- a/libs/community/langchain_community/vectorstores/tencentvectordb.py +++ b/libs/community/langchain_community/vectorstores/tencentvectordb.py @@ -6,7 +6,18 @@ import json import logging import time from enum import Enum -from typing import Any, Dict, Iterable, List, Optional, Sequence, Tuple, Union, cast +from typing import ( + Any, + Callable, + Dict, + Iterable, + List, + Optional, + Sequence, + Tuple, + Union, + cast, +) import numpy as np from langchain_core.documents import Document @@ -168,8 +179,8 @@ class TencentVectorDB(VectorStore): tcvectordb = guard_import("tcvectordb") tcollection = guard_import("tcvectordb.model.collection") enum = guard_import("tcvectordb.model.enum") - - if t_vdb_embedding: + self.embedding_model = None + if embedding is None and t_vdb_embedding: embedding_model = [ model for model in enum.EmbeddingModel @@ -566,3 +577,17 @@ class TencentVectorDB(VectorStore): ) # Reorder the values and return. return [documents[x] for x in new_ordering if x != -1] + + def _select_relevance_score_fn(self) -> Callable[[float], float]: + metric_type = self.index_params.metric_type + if metric_type == "COSINE": + return self._cosine_relevance_score_fn + elif metric_type == "L2": + return self._euclidean_relevance_score_fn + elif metric_type == "IP": + return self._max_inner_product_relevance_score_fn + else: + raise ValueError( + "No supported normalization function" + f" for distance metric of type: {metric_type}." + ) diff --git a/libs/community/tests/unit_tests/document_loaders/test_imports.py b/libs/community/tests/unit_tests/document_loaders/test_imports.py index b49a1b7cc4a..ddeaf734b0f 100644 --- a/libs/community/tests/unit_tests/document_loaders/test_imports.py +++ b/libs/community/tests/unit_tests/document_loaders/test_imports.py @@ -105,6 +105,7 @@ EXPECTED_ALL = [ "MergedDataLoader", "ModernTreasuryLoader", "MongodbLoader", + "NeedleLoader", "NewsURLLoader", "NotebookLoader", "NotionDBLoader", diff --git a/libs/community/tests/unit_tests/document_loaders/test_needle.py b/libs/community/tests/unit_tests/document_loaders/test_needle.py new file mode 100644 index 00000000000..d8f7a22fb0f --- /dev/null +++ b/libs/community/tests/unit_tests/document_loaders/test_needle.py @@ -0,0 +1,75 @@ +import pytest +from pytest_mock import MockerFixture + + +@pytest.mark.requires("needle") +def test_add_and_fetch_files(mocker: MockerFixture) -> None: + """ + Test adding and fetching files using the NeedleLoader with a mock. + """ + from langchain_community.document_loaders.needle import NeedleLoader # noqa: I001 + from needle.v1.models import CollectionFile # noqa: I001 + + # Create mock instances using mocker + # Create mock instances using mocker + mock_files = mocker.Mock() + mock_files.add.return_value = [ + CollectionFile( + id="mock_id", + name="tech-radar-30.pdf", + url="https://example.com/", + status="indexed", + type="mock_type", + user_id="mock_user_id", + connector_id="mock_connector_id", + size=1234, + md5_hash="mock_md5_hash", + created_at="2024-01-01T00:00:00Z", + updated_at="2024-01-01T00:00:00Z", + ) + ] + mock_files.list.return_value = [ + CollectionFile( + id="mock_id", + name="tech-radar-30.pdf", + url="https://example.com/", + status="indexed", + type="mock_type", + user_id="mock_user_id", + connector_id="mock_connector_id", + size=1234, + md5_hash="mock_md5_hash", + created_at="2024-01-01T00:00:00Z", + updated_at="2024-01-01T00:00:00Z", + ) + ] + + mock_collections = mocker.Mock() + mock_collections.files = mock_files + + mock_needle_client = mocker.Mock() + mock_needle_client.collections = mock_collections + + # Patch the NeedleClient to return the mock client + mocker.patch("needle.v1.NeedleClient", return_value=mock_needle_client) + + # Initialize NeedleLoader with mock API key and collection ID + document_store = NeedleLoader( + needle_api_key="fake_api_key", + collection_id="fake_collection_id", + ) + + # Define files to add + files = { + "tech-radar-30.pdf": "https://www.thoughtworks.com/content/dam/thoughtworks/documents/radar/2024/04/tr_technology_radar_vol_30_en.pdf" + } + + # Add files to the collection using the mock client + document_store.add_files(files=files) + + # Fetch the added files using the mock client + added_files = document_store._fetch_documents() + + # Assertions to verify that the file was added and fetched correctly + assert isinstance(added_files[0].metadata["title"], str) + assert isinstance(added_files[0].metadata["source"], str) diff --git a/libs/community/tests/unit_tests/query_constructors/test_databricks_vector_search.py b/libs/community/tests/unit_tests/query_constructors/test_databricks_vector_search.py index 1f38f3b1b60..e71e32c34eb 100644 --- a/libs/community/tests/unit_tests/query_constructors/test_databricks_vector_search.py +++ b/libs/community/tests/unit_tests/query_constructors/test_databricks_vector_search.py @@ -109,7 +109,7 @@ def test_visit_structured_query_with_one_arg_filter() -> None: filter=comp, ) - expected = (query, {"filters": {"country": "France"}}) + expected = (query, {"filter": {"country": "France"}}) actual = DEFAULT_TRANSLATOR.visit_structured_query(structured_query) assert expected == actual @@ -134,7 +134,7 @@ def test_visit_structured_query_with_multiple_arg_filter_and_operator() -> None: expected = ( query, - {"filters": {"country": "France", "year >=": 1888, "year <=": 1900}}, + {"filter": {"country": "France", "year >=": 1888, "year <=": 1900}}, ) actual = DEFAULT_TRANSLATOR.visit_structured_query(structured_query) diff --git a/libs/community/tests/unit_tests/retrievers/test_bm25.py b/libs/community/tests/unit_tests/retrievers/test_bm25.py index ef40b25ba7d..81afae84c72 100644 --- a/libs/community/tests/unit_tests/retrievers/test_bm25.py +++ b/libs/community/tests/unit_tests/retrievers/test_bm25.py @@ -43,3 +43,42 @@ def test_repr() -> None: ] bm25_retriever = BM25Retriever.from_documents(documents=input_docs) assert "I have a pen" not in repr(bm25_retriever) + + +@pytest.mark.requires("rank_bm25") +def test_doc_id() -> None: + docs_with_ids = [ + Document(page_content="I have a pen.", id="1"), + Document(page_content="Do you have a pen?", id="2"), + Document(page_content="I have a bag.", id="3"), + ] + docs_without_ids = [ + Document(page_content="I have a pen."), + Document(page_content="Do you have a pen?"), + Document(page_content="I have a bag."), + ] + docs_with_some_ids = [ + Document(page_content="I have a pen.", id="1"), + Document(page_content="Do you have a pen?"), + Document(page_content="I have a bag.", id="3"), + ] + bm25_retriever_with_ids = BM25Retriever.from_documents(documents=docs_with_ids) + bm25_retriever_without_ids = BM25Retriever.from_documents( + documents=docs_without_ids + ) + bm25_retriever_with_some_ids = BM25Retriever.from_documents( + documents=docs_with_some_ids + ) + for doc in bm25_retriever_with_ids.docs: + assert doc.id is not None + for doc in bm25_retriever_without_ids.docs: + assert doc.id is None + for doc in bm25_retriever_with_some_ids.docs: + if doc.page_content == "I have a pen.": + assert doc.id == "1" + elif doc.page_content == "Do you have a pen?": + assert doc.id is None + elif doc.page_content == "I have a bag.": + assert doc.id == "3" + else: + raise ValueError("Unexpected document") diff --git a/libs/community/tests/unit_tests/retrievers/test_imports.py b/libs/community/tests/unit_tests/retrievers/test_imports.py index f5b791139a8..dde08e2f817 100644 --- a/libs/community/tests/unit_tests/retrievers/test_imports.py +++ b/libs/community/tests/unit_tests/retrievers/test_imports.py @@ -26,6 +26,7 @@ EXPECTED_ALL = [ "MetalRetriever", "MilvusRetriever", "NanoPQRetriever", + "NeedleRetriever", "OutlineRetriever", "PineconeHybridSearchRetriever", "PubMedRetriever", diff --git a/libs/community/tests/unit_tests/retrievers/test_needle.py b/libs/community/tests/unit_tests/retrievers/test_needle.py new file mode 100644 index 00000000000..853250d409f --- /dev/null +++ b/libs/community/tests/unit_tests/retrievers/test_needle.py @@ -0,0 +1,72 @@ +from typing import Any + +import pytest +from pytest_mock import MockerFixture + + +# Mock class to simulate search results from Needle API +class MockSearchResult: + def __init__(self, content: str) -> None: + self.content = content + + +# Mock class to simulate NeedleClient and its collections behavior +class MockNeedleClient: + def __init__(self, api_key: str) -> None: + self.api_key = api_key + self.collections = self.MockCollections() + + class MockCollections: + def search(self, collection_id: str, text: str) -> list[MockSearchResult]: + return [ + MockSearchResult(content=f"Result for query: {text}"), + MockSearchResult(content=f"Another result for query: {text}"), + ] + + +@pytest.mark.requires("needle") +def test_needle_retriever_initialization() -> None: + """ + Test that the NeedleRetriever is initialized correctly. + """ + from langchain_community.retrievers.needle import NeedleRetriever # noqa: I001 + + retriever = NeedleRetriever( + needle_api_key="mock_api_key", + collection_id="mock_collection_id", + ) + + assert retriever.needle_api_key == "mock_api_key" + assert retriever.collection_id == "mock_collection_id" + + +@pytest.mark.requires("needle") +def test_get_relevant_documents(mocker: MockerFixture) -> None: + """ + Test that the retriever correctly fetches documents. + """ + from langchain_community.retrievers.needle import NeedleRetriever # noqa: I001 + + # Patch the actual NeedleClient import path used in the NeedleRetriever + mocker.patch("needle.v1.NeedleClient", new=MockNeedleClient) + + # Initialize the retriever with mocked API key and collection ID + retriever = NeedleRetriever( + needle_api_key="mock_api_key", + collection_id="mock_collection_id", + ) + + mock_run_manager: Any = None + + # Perform the search + query = "What is RAG?" + retrieved_documents = retriever._get_relevant_documents( + query, run_manager=mock_run_manager + ) + + # Validate the results + assert len(retrieved_documents) == 2 + assert retrieved_documents[0].page_content == "Result for query: What is RAG?" + assert ( + retrieved_documents[1].page_content == "Another result for query: What is RAG?" + ) diff --git a/libs/core/README.md b/libs/core/README.md index c833c203946..fb09de946ec 100644 --- a/libs/core/README.md +++ b/libs/core/README.md @@ -17,7 +17,7 @@ These abstractions are designed to be as modular and simple as possible. Example The benefit of having these abstractions is that any provider can implement the required interface and then easily be used in the rest of the LangChain ecosystem. -For full documentation see the [API reference](https://api.python.langchain.com/en/stable/core_api_reference.html). +For full documentation see the [API reference](https://python.langchain.com/api_reference/core/index.html). ## 1️⃣ Core Interface: Runnables diff --git a/libs/langchain/langchain/chains/router/multi_prompt.py b/libs/langchain/langchain/chains/router/multi_prompt.py index 214b9a2b372..0531cdb834d 100644 --- a/libs/langchain/langchain/chains/router/multi_prompt.py +++ b/libs/langchain/langchain/chains/router/multi_prompt.py @@ -20,9 +20,8 @@ from langchain.chains.router.multi_prompt_prompt import MULTI_PROMPT_ROUTER_TEMP since="0.2.12", removal="1.0", message=( - "Use RunnableLambda to select from multiple prompt templates. See example " - "in API reference: " - "https://api.python.langchain.com/en/latest/chains/langchain.chains.router.multi_prompt.MultiPromptChain.html" # noqa: E501 + "Please see migration guide here for recommended implementation: " + "https://python.langchain.com/docs/versions/migrating_chains/multi_prompt_chain/" # noqa: E501 ), ) class MultiPromptChain(MultiRouteChain): @@ -37,60 +36,109 @@ class MultiPromptChain(MultiRouteChain): from operator import itemgetter from typing import Literal - from typing_extensions import TypedDict from langchain_core.output_parsers import StrOutputParser from langchain_core.prompts import ChatPromptTemplate - from langchain_core.runnables import RunnableLambda, RunnablePassthrough + from langchain_core.runnables import RunnableConfig from langchain_openai import ChatOpenAI + from langgraph.graph import END, START, StateGraph + from typing_extensions import TypedDict llm = ChatOpenAI(model="gpt-4o-mini") + # Define the prompts we will route to prompt_1 = ChatPromptTemplate.from_messages( [ ("system", "You are an expert on animals."), - ("human", "{query}"), + ("human", "{input}"), ] ) prompt_2 = ChatPromptTemplate.from_messages( [ ("system", "You are an expert on vegetables."), - ("human", "{query}"), + ("human", "{input}"), ] ) + # Construct the chains we will route to. These format the input query + # into the respective prompt, run it through a chat model, and cast + # the result to a string. chain_1 = prompt_1 | llm | StrOutputParser() chain_2 = prompt_2 | llm | StrOutputParser() + + # Next: define the chain that selects which branch to route to. + # Here we will take advantage of tool-calling features to force + # the output to select one of two desired branches. route_system = "Route the user's query to either the animal or vegetable expert." route_prompt = ChatPromptTemplate.from_messages( [ ("system", route_system), - ("human", "{query}"), + ("human", "{input}"), ] ) + # Define schema for output: class RouteQuery(TypedDict): - \"\"\"Route query to destination.\"\"\" + \"\"\"Route query to destination expert.\"\"\" + destination: Literal["animal", "vegetable"] - route_chain = ( - route_prompt - | llm.with_structured_output(RouteQuery) - | itemgetter("destination") - ) + route_chain = route_prompt | llm.with_structured_output(RouteQuery) - chain = { - "destination": route_chain, # "animal" or "vegetable" - "query": lambda x: x["query"], # pass through input query - } | RunnableLambda( - # if animal, chain_1. otherwise, chain_2. - lambda x: chain_1 if x["destination"] == "animal" else chain_2, - ) - chain.invoke({"query": "what color are carrots"}) + # For LangGraph, we will define the state of the graph to hold the query, + # destination, and final answer. + class State(TypedDict): + query: str + destination: RouteQuery + answer: str + + + # We define functions for each node, including routing the query: + async def route_query(state: State, config: RunnableConfig): + destination = await route_chain.ainvoke(state["query"], config) + return {"destination": destination} + + + # And one node for each prompt + async def prompt_1(state: State, config: RunnableConfig): + return {"answer": await chain_1.ainvoke(state["query"], config)} + + + async def prompt_2(state: State, config: RunnableConfig): + return {"answer": await chain_2.ainvoke(state["query"], config)} + + + # We then define logic that selects the prompt based on the classification + def select_node(state: State) -> Literal["prompt_1", "prompt_2"]: + if state["destination"] == "animal": + return "prompt_1" + else: + return "prompt_2" + + + # Finally, assemble the multi-prompt chain. This is a sequence of two steps: + # 1) Select "animal" or "vegetable" via the route_chain, and collect the answer + # alongside the input query. + # 2) Route the input query to chain_1 or chain_2, based on the + # selection. + graph = StateGraph(State) + graph.add_node("route_query", route_query) + graph.add_node("prompt_1", prompt_1) + graph.add_node("prompt_2", prompt_2) + + graph.add_edge(START, "route_query") + graph.add_conditional_edges("route_query", select_node) + graph.add_edge("prompt_1", END) + graph.add_edge("prompt_2", END) + app = graph.compile() + + result = await app.ainvoke({"query": "what color are carrots"}) + print(result["destination"]) + print(result["answer"]) """ # noqa: E501 @property diff --git a/libs/partners/anthropic/Makefile b/libs/partners/anthropic/Makefile index 7a32f31997a..256ab677b83 100644 --- a/libs/partners/anthropic/Makefile +++ b/libs/partners/anthropic/Makefile @@ -8,7 +8,7 @@ TEST_FILE ?= tests/unit_tests/ integration_test integration_tests: TEST_FILE=tests/integration_tests/ test tests integration_test integration_tests: - poetry run pytest $(TEST_FILE) + poetry run pytest -vvv --timeout 10 $(TEST_FILE) test_watch: poetry run ptw --snapshot-update --now . -- -vv $(TEST_FILE) diff --git a/libs/partners/anthropic/poetry.lock b/libs/partners/anthropic/poetry.lock index 24666fc6657..0770706b185 100644 --- a/libs/partners/anthropic/poetry.lock +++ b/libs/partners/anthropic/poetry.lock @@ -852,6 +852,20 @@ pytest = ">=6.2.5" [package.extras] dev = ["pre-commit", "pytest-asyncio", "tox"] +[[package]] +name = "pytest-timeout" +version = "2.3.1" +description = "pytest plugin to abort hanging tests" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pytest-timeout-2.3.1.tar.gz", hash = "sha256:12397729125c6ecbdaca01035b9e5239d4db97352320af155b3f5de1ba5165d9"}, + {file = "pytest_timeout-2.3.1-py3-none-any.whl", hash = "sha256:68188cb703edfc6a18fad98dc25a3c61e9f24d644b0b70f33af545219fc7813e"}, +] + +[package.dependencies] +pytest = ">=7.0.0" + [[package]] name = "pytest-watcher" version = "0.3.5" @@ -1140,4 +1154,4 @@ watchmedo = ["PyYAML (>=3.10)"] [metadata] lock-version = "2.0" python-versions = ">=3.9,<4.0" -content-hash = "ee4aaa06307b4dc7f7913147bf58f3f36245193c9d4a79c43aba07641f7b6ab9" +content-hash = "7d24a5eb5b867fa9ad80cbc9fb80d630e7cb00a490b62502cdb57c2fe95cd125" diff --git a/libs/partners/anthropic/pyproject.toml b/libs/partners/anthropic/pyproject.toml index cda31223035..b6ff159efcc 100644 --- a/libs/partners/anthropic/pyproject.toml +++ b/libs/partners/anthropic/pyproject.toml @@ -65,6 +65,7 @@ syrupy = "^4.0.2" pytest-watcher = "^0.3.4" pytest-asyncio = "^0.21.1" defusedxml = "^0.7.1" +pytest-timeout = "^2.3.1" [tool.poetry.group.codespell.dependencies] codespell = "^2.2.0" diff --git a/libs/partners/anthropic/tests/integration_tests/test_chat_models.py b/libs/partners/anthropic/tests/integration_tests/test_chat_models.py index 5c229549263..8ff2396c9d1 100644 --- a/libs/partners/anthropic/tests/integration_tests/test_chat_models.py +++ b/libs/partners/anthropic/tests/integration_tests/test_chat_models.py @@ -22,7 +22,7 @@ from pydantic import BaseModel, Field from langchain_anthropic import ChatAnthropic, ChatAnthropicMessages from tests.unit_tests._utils import FakeCallbackHandler -MODEL_NAME = "claude-3-sonnet-20240229" +MODEL_NAME = "claude-3-5-sonnet-20240620" def test_stream() -> None: diff --git a/libs/partners/chroma/langchain_chroma/vectorstores.py b/libs/partners/chroma/langchain_chroma/vectorstores.py index 30bc3fd8764..afb9191c60a 100644 --- a/libs/partners/chroma/langchain_chroma/vectorstores.py +++ b/libs/partners/chroma/langchain_chroma/vectorstores.py @@ -16,6 +16,7 @@ from typing import ( Iterable, List, Optional, + Sequence, Tuple, Type, Union, @@ -44,10 +45,14 @@ def _results_to_docs_and_scores(results: Any) -> List[Tuple[Document, float]]: return [ # TODO: Chroma can do batch querying, # we shouldn't hard code to the 1st result - (Document(page_content=result[0], metadata=result[1] or {}), result[2]) + ( + Document(page_content=result[0], metadata=result[1] or {}, id=result[2]), + result[3], + ) for result in zip( results["documents"][0], results["metadatas"][0], + results["ids"][0], results["distances"][0], ) ] @@ -513,6 +518,11 @@ class Chroma(VectorStore): """ if ids is None: ids = [str(uuid.uuid4()) for _ in texts] + else: + # Assign strings to any null IDs + for idx, _id in enumerate(ids): + if _id is None: + ids[idx] = str(uuid.uuid4()) embeddings = None texts = list(texts) if self._embedding_function is not None: @@ -748,7 +758,7 @@ class Chroma(VectorStore): The most similar documents will have the lowest relevance score. Default relevance score function is euclidean distance. Distance metric must be - provided in `collection_metadata` during initizalition of Chroma object. + provided in `collection_metadata` during initialization of Chroma object. Example: collection_metadata={"hnsw:space": "cosine"}. Available distance metrics are: 'cosine', 'l2' and 'ip'. @@ -1024,6 +1034,38 @@ class Chroma(VectorStore): return self._collection.get(**kwargs) # type: ignore + def get_by_ids(self, ids: Sequence[str], /) -> list[Document]: + """Get documents by their IDs. + + The returned documents are expected to have the ID field set to the ID of the + document in the vector store. + + Fewer documents may be returned than requested if some IDs are not found or + if there are duplicated IDs. + + Users should not assume that the order of the returned documents matches + the order of the input IDs. Instead, users should rely on the ID field of the + returned documents. + + This method should **NOT** raise exceptions if no documents are found for + some IDs. + + Args: + ids: List of ids to retrieve. + + Returns: + List of Documents. + + .. versionadded:: 0.2.1 + """ + results = self.get(ids=list(ids)) + return [ + Document(page_content=doc, metadata=meta, id=doc_id) + for doc, meta, doc_id in zip( + results["documents"], results["metadatas"], results["ids"] + ) + ] + def update_document(self, document_id: str, document: Document) -> None: """Update a document in the collection. @@ -1185,6 +1227,8 @@ class Chroma(VectorStore): """ texts = [doc.page_content for doc in documents] metadatas = [doc.metadata for doc in documents] + if ids is None: + ids = [doc.id if doc.id else str(uuid.uuid4()) for doc in documents] return cls.from_texts( texts=texts, embedding=embedding, diff --git a/libs/partners/chroma/poetry.lock b/libs/partners/chroma/poetry.lock index 812eefb494a..f4b4192f448 100644 --- a/libs/partners/chroma/poetry.lock +++ b/libs/partners/chroma/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.8.4 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. [[package]] name = "annotated-types" @@ -955,6 +955,25 @@ typing-extensions = ">=4.7" type = "directory" url = "../../core" +[[package]] +name = "langchain-tests" +version = "0.3.4" +description = "Standard tests for LangChain implementations" +optional = false +python-versions = ">=3.9,<4.0" +files = [] +develop = true + +[package.dependencies] +httpx = "^0.27.0" +langchain-core = "^0.3.19" +pytest = ">=7,<9" +syrupy = "^4" + +[package.source] +type = "directory" +url = "../../standard-tests" + [[package]] name = "langsmith" version = "0.1.139" @@ -2805,4 +2824,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.0" python-versions = ">=3.9,<4" -content-hash = "4e3e3152fdc954723a33ffc5cc5c42b763e5aee74f39df8b54f16cdb753b2d13" +content-hash = "2d6bc4b9a18a322c326c3f7d5786c4b196a997458e6d2ca4043cb6b7a4a123b3" diff --git a/libs/partners/chroma/pyproject.toml b/libs/partners/chroma/pyproject.toml index ede3a9fad5a..8a7e18bdf1b 100644 --- a/libs/partners/chroma/pyproject.toml +++ b/libs/partners/chroma/pyproject.toml @@ -90,6 +90,10 @@ python = ">=3.9" version = ">=0.1.40,<0.3" python = "<3.9" +[[tool.poetry.group.test.dependencies.langchain-tests]] +path = "../../standard-tests" +develop = true + [tool.poetry.group.codespell.dependencies] codespell = "^2.2.0" diff --git a/libs/partners/chroma/tests/integration_tests/test_standard.py b/libs/partners/chroma/tests/integration_tests/test_standard.py new file mode 100644 index 00000000000..4396cf8df5e --- /dev/null +++ b/libs/partners/chroma/tests/integration_tests/test_standard.py @@ -0,0 +1,34 @@ +from typing import AsyncGenerator, Generator + +import pytest +from langchain_core.vectorstores import VectorStore +from langchain_tests.integration_tests.vectorstores import ( + AsyncReadWriteTestSuite, + ReadWriteTestSuite, +) + +from langchain_chroma import Chroma + + +class TestSync(ReadWriteTestSuite): + @pytest.fixture() + def vectorstore(self) -> Generator[VectorStore, None, None]: # type: ignore + """Get an empty vectorstore for unit tests.""" + store = Chroma(embedding_function=self.get_embeddings()) + try: + yield store + finally: + store.delete_collection() + pass + + +class TestAsync(AsyncReadWriteTestSuite): + @pytest.fixture() + async def vectorstore(self) -> AsyncGenerator[VectorStore, None]: # type: ignore + """Get an empty vectorstore for unit tests.""" + store = Chroma(embedding_function=self.get_embeddings()) + try: + yield store + finally: + store.delete_collection() + pass diff --git a/libs/partners/chroma/tests/integration_tests/test_vectorstores.py b/libs/partners/chroma/tests/integration_tests/test_vectorstores.py index d20d8f3d7c9..f7bed4cfa55 100644 --- a/libs/partners/chroma/tests/integration_tests/test_vectorstores.py +++ b/libs/partners/chroma/tests/integration_tests/test_vectorstores.py @@ -46,8 +46,43 @@ def test_chroma() -> None: output = docsearch.similarity_search("foo", k=1) docsearch.delete_collection() + assert len(output) == 1 + assert output[0].page_content == "foo" + assert output[0].id is not None - assert output == [Document(page_content="foo")] + +def test_from_documents() -> None: + """Test init using .from_documents.""" + documents = [ + Document(page_content="foo"), + Document(page_content="bar"), + Document(page_content="baz"), + ] + docsearch = Chroma.from_documents(documents=documents, embedding=FakeEmbeddings()) + output = docsearch.similarity_search("foo", k=1) + + docsearch.delete_collection() + assert len(output) == 1 + assert output[0].page_content == "foo" + assert output[0].id is not None + + +def test_chroma_with_ids() -> None: + """Test end to end construction and search.""" + texts = ["foo", "bar", "baz"] + ids = [f"id_{i}" for i in range(len(texts))] + docsearch = Chroma.from_texts( + collection_name="test_collection", + texts=texts, + embedding=FakeEmbeddings(), + ids=ids, + ) + output = docsearch.similarity_search("foo", k=1) + + docsearch.delete_collection() + assert len(output) == 1 + assert output[0].page_content == "foo" + assert output[0].id == "id_0" async def test_chroma_async() -> None: @@ -59,7 +94,27 @@ async def test_chroma_async() -> None: output = await docsearch.asimilarity_search("foo", k=1) docsearch.delete_collection() - assert output == [Document(page_content="foo")] + assert len(output) == 1 + assert output[0].page_content == "foo" + assert output[0].id is not None + + +async def test_chroma_async_with_ids() -> None: + """Test end to end construction and search.""" + texts = ["foo", "bar", "baz"] + ids = [f"id_{i}" for i in range(len(texts))] + docsearch = Chroma.from_texts( + collection_name="test_collection", + texts=texts, + embedding=FakeEmbeddings(), + ids=ids, + ) + output = await docsearch.asimilarity_search("foo", k=1) + + docsearch.delete_collection() + assert len(output) == 1 + assert output[0].page_content == "foo" + assert output[0].id == "id_0" def test_chroma_with_metadatas() -> None: @@ -74,22 +129,49 @@ def test_chroma_with_metadatas() -> None: ) output = docsearch.similarity_search("foo", k=1) docsearch.delete_collection() - assert output == [Document(page_content="foo", metadata={"page": "0"})] + assert len(output) == 1 + assert output[0].page_content == "foo" + assert output[0].metadata == {"page": "0"} + assert output[0].id is not None -def test_chroma_with_metadatas_with_scores() -> None: - """Test end to end construction and scored search.""" +def test_chroma_with_metadatas_and_ids() -> None: + """Test end to end construction and search.""" texts = ["foo", "bar", "baz"] metadatas = [{"page": str(i)} for i in range(len(texts))] + ids = [f"id_{i}" for i in range(len(texts))] docsearch = Chroma.from_texts( collection_name="test_collection", texts=texts, embedding=FakeEmbeddings(), metadatas=metadatas, + ids=ids, + ) + output = docsearch.similarity_search("foo", k=1) + docsearch.delete_collection() + assert len(output) == 1 + assert output[0].page_content == "foo" + assert output[0].metadata == {"page": "0"} + assert output[0].id == "id_0" + + +def test_chroma_with_metadatas_with_scores_and_ids() -> None: + """Test end to end construction and scored search.""" + texts = ["foo", "bar", "baz"] + metadatas = [{"page": str(i)} for i in range(len(texts))] + ids = [f"id_{i}" for i in range(len(texts))] + docsearch = Chroma.from_texts( + collection_name="test_collection", + texts=texts, + embedding=FakeEmbeddings(), + metadatas=metadatas, + ids=ids, ) output = docsearch.similarity_search_with_score("foo", k=1) docsearch.delete_collection() - assert output == [(Document(page_content="foo", metadata={"page": "0"}), 0.0)] + assert output == [ + (Document(page_content="foo", metadata={"page": "0"}, id="id_0"), 0.0) + ] def test_chroma_with_metadatas_with_vectors() -> None: @@ -114,6 +196,7 @@ def test_chroma_with_metadatas_with_scores_using_vector() -> None: """Test end to end construction and scored search, using embedding vector.""" texts = ["foo", "bar", "baz"] metadatas = [{"page": str(i)} for i in range(len(texts))] + ids = [f"id_{i}" for i in range(len(texts))] embeddings = FakeEmbeddings() docsearch = Chroma.from_texts( @@ -121,41 +204,52 @@ def test_chroma_with_metadatas_with_scores_using_vector() -> None: texts=texts, embedding=embeddings, metadatas=metadatas, + ids=ids, ) embedded_query = embeddings.embed_query("foo") output = docsearch.similarity_search_by_vector_with_relevance_scores( embedding=embedded_query, k=1 ) docsearch.delete_collection() - assert output == [(Document(page_content="foo", metadata={"page": "0"}), 0.0)] + assert output == [ + (Document(page_content="foo", metadata={"page": "0"}, id="id_0"), 0.0) + ] def test_chroma_search_filter() -> None: """Test end to end construction and search with metadata filtering.""" texts = ["far", "bar", "baz"] metadatas = [{"first_letter": "{}".format(text[0])} for text in texts] + ids = [f"id_{i}" for i in range(len(texts))] docsearch = Chroma.from_texts( collection_name="test_collection", texts=texts, embedding=FakeEmbeddings(), metadatas=metadatas, + ids=ids, ) output1 = docsearch.similarity_search("far", k=1, filter={"first_letter": "f"}) output2 = docsearch.similarity_search("far", k=1, filter={"first_letter": "b"}) docsearch.delete_collection() - assert output1 == [Document(page_content="far", metadata={"first_letter": "f"})] - assert output2 == [Document(page_content="bar", metadata={"first_letter": "b"})] + assert output1 == [ + Document(page_content="far", metadata={"first_letter": "f"}, id="id_0") + ] + assert output2 == [ + Document(page_content="bar", metadata={"first_letter": "b"}, id="id_1") + ] def test_chroma_search_filter_with_scores() -> None: """Test end to end construction and scored search with metadata filtering.""" texts = ["far", "bar", "baz"] metadatas = [{"first_letter": "{}".format(text[0])} for text in texts] + ids = [f"id_{i}" for i in range(len(texts))] docsearch = Chroma.from_texts( collection_name="test_collection", texts=texts, embedding=FakeEmbeddings(), metadatas=metadatas, + ids=ids, ) output1 = docsearch.similarity_search_with_score( "far", k=1, filter={"first_letter": "f"} @@ -165,10 +259,10 @@ def test_chroma_search_filter_with_scores() -> None: ) docsearch.delete_collection() assert output1 == [ - (Document(page_content="far", metadata={"first_letter": "f"}), 0.0) + (Document(page_content="far", metadata={"first_letter": "f"}, id="id_0"), 0.0) ] assert output2 == [ - (Document(page_content="bar", metadata={"first_letter": "b"}), 1.0) + (Document(page_content="bar", metadata={"first_letter": "b"}, id="id_1"), 1.0) ] @@ -177,15 +271,18 @@ def test_chroma_with_persistence() -> None: chroma_persist_dir = "./tests/persist_dir" collection_name = "test_collection" texts = ["foo", "bar", "baz"] + ids = [f"id_{i}" for i in range(len(texts))] + docsearch = Chroma.from_texts( collection_name=collection_name, texts=texts, embedding=FakeEmbeddings(), persist_directory=chroma_persist_dir, + ids=ids, ) output = docsearch.similarity_search("foo", k=1) - assert output == [Document(page_content="foo")] + assert output == [Document(page_content="foo", id="id_0")] # Get a new VectorStore from the persisted directory docsearch = Chroma( @@ -194,6 +291,7 @@ def test_chroma_with_persistence() -> None: persist_directory=chroma_persist_dir, ) output = docsearch.similarity_search("foo", k=1) + assert output == [Document(page_content="foo", id="id_0")] # Clean up docsearch.delete_collection() @@ -211,7 +309,9 @@ def test_chroma_mmr() -> None: ) output = docsearch.max_marginal_relevance_search("foo", k=1) docsearch.delete_collection() - assert output == [Document(page_content="foo")] + assert len(output) == 1 + assert output[0].page_content == "foo" + assert output[0].id is not None def test_chroma_mmr_by_vector() -> None: @@ -224,7 +324,9 @@ def test_chroma_mmr_by_vector() -> None: embedded_query = embeddings.embed_query("foo") output = docsearch.max_marginal_relevance_search_by_vector(embedded_query, k=1) docsearch.delete_collection() - assert output == [Document(page_content="foo")] + assert len(output) == 1 + assert output[0].page_content == "foo" + assert output[0].id is not None def test_chroma_with_include_parameter() -> None: @@ -241,7 +343,10 @@ def test_chroma_with_include_parameter() -> None: def test_chroma_update_document() -> None: - """Test the update_document function in the Chroma class.""" + """Test the update_document function in the Chroma class. + + Uses an external document id. + """ # Make a consistent embedding embedding = ConsistentFakeEmbeddings() @@ -283,7 +388,66 @@ def test_chroma_update_document() -> None: docsearch.delete_collection() # Assert that the updated document is returned by the search - assert output == [Document(page_content=updated_content, metadata={"page": "0"})] + assert output == [ + Document(page_content=updated_content, metadata={"page": "0"}, id=document_id) + ] + + assert list(new_embedding) == list(embedding.embed_documents([updated_content])[0]) + assert list(new_embedding) != list(old_embedding) + + +def test_chroma_update_document_with_id() -> None: + """Test the update_document function in the Chroma class. + + Uses an internal document id. + """ + # Make a consistent embedding + embedding = ConsistentFakeEmbeddings() + + # Initial document content and id + initial_content = "foo" + document_id = "doc1" + + # Create an instance of Document with initial content and metadata + original_doc = Document( + page_content=initial_content, metadata={"page": "0"}, id=document_id + ) + + # Initialize a Chroma instance with the original document + docsearch = Chroma.from_documents( + collection_name="test_collection", + documents=[original_doc], + embedding=embedding, + ) + old_embedding = docsearch._collection.peek()["embeddings"][ # type: ignore + docsearch._collection.peek()["ids"].index(document_id) + ] + + # Define updated content for the document + updated_content = "updated foo" + + # Create a new Document instance with the updated content and the same id + updated_doc = Document( + page_content=updated_content, metadata={"page": "0"}, id=document_id + ) + + # Update the document in the Chroma instance + docsearch.update_document(document_id=document_id, document=updated_doc) + + # Perform a similarity search with the updated content + output = docsearch.similarity_search(updated_content, k=1) + + # Assert that the new embedding is correct + new_embedding = docsearch._collection.peek()["embeddings"][ # type: ignore + docsearch._collection.peek()["ids"].index(document_id) + ] + + docsearch.delete_collection() + + # Assert that the updated document is returned by the search + assert output == [ + Document(page_content=updated_content, metadata={"page": "0"}, id=document_id) + ] assert list(new_embedding) == list(embedding.embed_documents([updated_content])[0]) assert list(new_embedding) != list(old_embedding) @@ -294,20 +458,22 @@ def test_chroma_with_relevance_score_custom_normalization_fn() -> None: """Test searching with relevance score and custom normalization function.""" texts = ["foo", "bar", "baz"] metadatas = [{"page": str(i)} for i in range(len(texts))] + ids = [f"id_{i}" for i in range(len(texts))] docsearch = Chroma.from_texts( collection_name="test1_collection", texts=texts, embedding=FakeEmbeddings(), metadatas=metadatas, + ids=ids, relevance_score_fn=lambda d: d * 0, collection_metadata={"hnsw:space": "l2"}, ) output = docsearch.similarity_search_with_relevance_scores("foo", k=3) docsearch.delete_collection() assert output == [ - (Document(page_content="foo", metadata={"page": "0"}), 0.0), - (Document(page_content="bar", metadata={"page": "1"}), 0.0), - (Document(page_content="baz", metadata={"page": "2"}), 0.0), + (Document(page_content="foo", metadata={"page": "0"}, id="id_0"), 0.0), + (Document(page_content="bar", metadata={"page": "1"}, id="id_1"), 0.0), + (Document(page_content="baz", metadata={"page": "2"}, id="id_2"), 0.0), ] @@ -332,11 +498,11 @@ def test_chroma_add_documents_no_metadata() -> None: def test_chroma_add_documents_mixed_metadata() -> None: db = Chroma(embedding_function=FakeEmbeddings()) docs = [ - Document(page_content="foo"), - Document(page_content="bar", metadata={"baz": 1}), + Document(page_content="foo", id="0"), + Document(page_content="bar", metadata={"baz": 1}, id="1"), ] ids = ["0", "1"] - actual_ids = db.add_documents(docs, ids=ids) + actual_ids = db.add_documents(docs) search = db.similarity_search("foo bar") db.delete_collection() diff --git a/libs/partners/chroma/tests/unit_tests/test_vectorstores.py b/libs/partners/chroma/tests/unit_tests/test_vectorstores.py index 84d8637879e..66ac3b06224 100644 --- a/libs/partners/chroma/tests/unit_tests/test_vectorstores.py +++ b/libs/partners/chroma/tests/unit_tests/test_vectorstores.py @@ -13,3 +13,18 @@ def test_initialization() -> None: texts=texts, embedding=FakeEmbeddings(size=10), ) + + +def test_similarity_search() -> None: + """Test similarity search by Chroma.""" + texts = ["foo", "bar", "baz"] + metadatas = [{"page": str(i)} for i in range(len(texts))] + docsearch = Chroma.from_texts( + collection_name="test_collection", + texts=texts, + embedding=FakeEmbeddings(size=10), + metadatas=metadatas, + ) + output = docsearch.similarity_search("foo", k=1) + docsearch.delete_collection() + assert len(output) == 1 diff --git a/libs/partners/openai/tests/integration_tests/embeddings/test_base_standard.py b/libs/partners/openai/tests/integration_tests/embeddings/test_base_standard.py new file mode 100644 index 00000000000..66f74f1687f --- /dev/null +++ b/libs/partners/openai/tests/integration_tests/embeddings/test_base_standard.py @@ -0,0 +1,18 @@ +"""Standard LangChain interface tests""" + +from typing import Type + +from langchain_core.embeddings import Embeddings +from langchain_tests.integration_tests.embeddings import EmbeddingsIntegrationTests + +from langchain_openai import OpenAIEmbeddings + + +class TestOpenAIStandard(EmbeddingsIntegrationTests): + @property + def embeddings_class(self) -> Type[Embeddings]: + return OpenAIEmbeddings + + @property + def embedding_model_params(self) -> dict: + return {"model": "text-embedding-3-small", "dimensions": 128} diff --git a/libs/standard-tests/langchain_tests/integration_tests/__init__.py b/libs/standard-tests/langchain_tests/integration_tests/__init__.py index ed7e5f111c9..734af1608c6 100644 --- a/libs/standard-tests/langchain_tests/integration_tests/__init__.py +++ b/libs/standard-tests/langchain_tests/integration_tests/__init__.py @@ -11,6 +11,7 @@ modules = [ "vectorstores", "embeddings", "tools", + "retrievers", ] for module in modules: diff --git a/libs/standard-tests/langchain_tests/integration_tests/chat_models.py b/libs/standard-tests/langchain_tests/integration_tests/chat_models.py index 1cbec02ad0d..4e6a811c451 100644 --- a/libs/standard-tests/langchain_tests/integration_tests/chat_models.py +++ b/libs/standard-tests/langchain_tests/integration_tests/chat_models.py @@ -75,29 +75,30 @@ def _validate_tool_call_message_no_args(message: BaseMessage) -> None: class ChatModelIntegrationTests(ChatModelTests): """Base class for chat model integration tests. - Test subclasses must implement the following two properties: + Test subclasses must implement the ``chat_model_class`` and + ``chat_model_params`` properties to specify what model to test and its + initialization parameters. - chat_model_class - The chat model class to test, e.g., ``ChatParrotLink``. + Example: - Example: + .. code-block:: python - .. code-block:: python + from typing import Type + from langchain_tests.integration_tests import ChatModelIntegrationTests + from my_package.chat_models import MyChatModel + + + class TestMyChatModelIntegration(ChatModelIntegrationTests): @property - def chat_model_class(self) -> Type[ChatParrotLink]: - return ChatParrotLink - - chat_model_params - Initialization parameters for the chat model. - - Example: - - .. code-block:: python + def chat_model_class(self) -> Type[MyChatModel]: + # Return the chat model class to test here + return MyChatModel @property def chat_model_params(self) -> dict: - return {"model": "bird-brain-001", "temperature": 0} + # Return initialization parameters for the model. + return {"model": "model-001", "temperature": 0} .. note:: API references for individual test methods include troubleshooting tips. diff --git a/libs/standard-tests/langchain_tests/integration_tests/embeddings.py b/libs/standard-tests/langchain_tests/integration_tests/embeddings.py index 7e3689d0f54..8b4f20bb4a5 100644 --- a/libs/standard-tests/langchain_tests/integration_tests/embeddings.py +++ b/libs/standard-tests/langchain_tests/integration_tests/embeddings.py @@ -6,7 +6,47 @@ from langchain_tests.unit_tests.embeddings import EmbeddingsTests class EmbeddingsIntegrationTests(EmbeddingsTests): + """Base class for embeddings integration tests. + + Test subclasses must implement the ``embeddings_class`` property to specify the + embeddings model to be tested. You can also override the + ``embedding_model_params`` property to specify initialization parameters. + + Example: + + .. code-block:: python + + from typing import Type + + from langchain_tests.integration_tests import EmbeddingsIntegrationTests + from my_package.embeddings import MyEmbeddingsModel + + + class TestMyEmbeddingsModelIntegration(EmbeddingsIntegrationTests): + @property + def embeddings_class(self) -> Type[MyEmbeddingsModel]: + # Return the embeddings model class to test here + return MyEmbeddingsModel + + @property + def embedding_model_params(self) -> dict: + # Return initialization parameters for the model. + return {"model": "model-001"} + + .. note:: + API references for individual test methods include troubleshooting tips. + """ + def test_embed_query(self, model: Embeddings) -> None: + """Test embedding a string query. + + .. dropdown:: Troubleshooting + + If this test fails, check that: + + 1. The model will generate a list of floats when calling ``.embed_query`` on a string. + 2. The length of the list is consistent across different inputs. + """ # noqa: E501 embedding_1 = model.embed_query("foo") assert isinstance(embedding_1, List) @@ -18,6 +58,15 @@ class EmbeddingsIntegrationTests(EmbeddingsTests): assert len(embedding_1) == len(embedding_2) def test_embed_documents(self, model: Embeddings) -> None: + """Test embedding a list of strings. + + .. dropdown:: Troubleshooting + + If this test fails, check that: + + 1. The model will generate a list of lists of floats when calling ``.embed_documents`` on a list of strings. + 2. The length of each list is the same. + """ # noqa: E501 documents = ["foo", "bar", "baz"] embeddings = model.embed_documents(documents) @@ -28,6 +77,15 @@ class EmbeddingsIntegrationTests(EmbeddingsTests): assert all(len(embedding) == len(embeddings[0]) for embedding in embeddings) async def test_aembed_query(self, model: Embeddings) -> None: + """Test embedding a string query async. + + .. dropdown:: Troubleshooting + + If this test fails, check that: + + 1. The model will generate a list of floats when calling ``.aembed_query`` on a string. + 2. The length of the list is consistent across different inputs. + """ # noqa: E501 embedding_1 = await model.aembed_query("foo") assert isinstance(embedding_1, List) @@ -39,6 +97,15 @@ class EmbeddingsIntegrationTests(EmbeddingsTests): assert len(embedding_1) == len(embedding_2) async def test_aembed_documents(self, model: Embeddings) -> None: + """Test embedding a list of strings async. + + .. dropdown:: Troubleshooting + + If this test fails, check that: + + 1. The model will generate a list of lists of floats when calling ``.aembed_documents`` on a list of strings. + 2. The length of each list is the same. + """ # noqa: E501 documents = ["foo", "bar", "baz"] embeddings = await model.aembed_documents(documents) diff --git a/libs/standard-tests/langchain_tests/integration_tests/vectorstores.py b/libs/standard-tests/langchain_tests/integration_tests/vectorstores.py index 08b0358dcfb..36770823be5 100644 --- a/libs/standard-tests/langchain_tests/integration_tests/vectorstores.py +++ b/libs/standard-tests/langchain_tests/integration_tests/vectorstores.py @@ -15,18 +15,70 @@ EMBEDDING_SIZE = 6 class ReadWriteTestSuite(BaseStandardTests): - """Test suite for checking the read-write API of a vectorstore. - - This test suite verifies the basic read-write API of a vectorstore. - - The test suite is designed for synchronous vectorstores. + """Test suite for checking the synchronous read-write API of a vector store. Implementers should subclass this test suite and provide a fixture - that returns an empty vectorstore for each test. + that returns an empty vector store for each test. - The fixture should use the `get_embeddings` method to get a pre-defined + The fixture should use the ``get_embeddings`` method to get a pre-defined embeddings model that should be used for this test suite. - """ + + Here is a template: + + .. code-block:: python + + from typing import Generator + + import pytest + from langchain_core.vectorstores import VectorStore + from langchain_parrot_link.vectorstores import ParrotVectorStore + from langchain_tests.integration_tests.vectorstores import ReadWriteTestSuite + + + class TestSync(ReadWriteTestSuite): + @pytest.fixture() + def vectorstore(self) -> Generator[VectorStore, None, None]: # type: ignore + \"\"\"Get an empty vectorstore.\"\"\" + store = ParrotVectorStore(self.get_embeddings()) + # note: store should be EMPTY at this point + # if you need to delete data, you may do so here + try: + yield store + finally: + # cleanup operations, or deleting data + pass + + In the fixture, before the ``yield`` we instantiate an empty vector store. In the + ``finally`` block, we call whatever logic is necessary to bring the vector store + to a clean state. + + Example: + + .. code-block:: python + + from typing import Generator + + import pytest + from langchain_core.vectorstores import VectorStore + from langchain_tests.integration_tests.vectorstores import ReadWriteTestSuite + + from langchain_chroma import Chroma + + + class TestSync(ReadWriteTestSuite): + @pytest.fixture() + def vectorstore(self) -> Generator[VectorStore, None, None]: # type: ignore + \"\"\"Get an empty vectorstore.\"\"\" + store = Chroma(embedding_function=self.get_embeddings()) + try: + yield store + finally: + store.delete_collection() + pass + + .. note:: + API references for individual test methods include troubleshooting tips. + """ # noqa: E501 @abstractmethod @pytest.fixture @@ -38,17 +90,39 @@ class ReadWriteTestSuite(BaseStandardTests): @staticmethod def get_embeddings() -> Embeddings: - """A pre-defined embeddings model that should be used for this test.""" + """A pre-defined embeddings model that should be used for this test. + + This currently uses ``DeterministicFakeEmbedding`` from ``langchain-core``, + which uses numpy to generate random numbers based on a hash of the input text. + + The resulting embeddings are not meaningful, but they are deterministic. + """ return DeterministicFakeEmbedding( size=EMBEDDING_SIZE, ) def test_vectorstore_is_empty(self, vectorstore: VectorStore) -> None: - """Test that the vectorstore is empty.""" + """Test that the vectorstore is empty. + + .. dropdown:: Troubleshooting + + If this test fails, check that the test class (i.e., sub class of + ``ReadWriteTestSuite``) initializes an empty vector store in the + ``vectorestore`` fixture. + """ assert vectorstore.similarity_search("foo", k=1) == [] def test_add_documents(self, vectorstore: VectorStore) -> None: - """Test adding documents into the vectorstore.""" + """Test adding documents into the vectorstore. + + .. dropdown:: Troubleshooting + + If this test fails, check that: + + 1. We correctly initialize an empty vector store in the ``vectorestore`` fixture. + 2. Calling ``.similarity_search`` for the top ``k`` similar documents does not threshold by score. + 3. We do not mutate the original document object when adding it to the vector store (e.g., by adding an ID). + """ # noqa: E501 original_documents = [ Document(page_content="foo", metadata={"id": 1}), Document(page_content="bar", metadata={"id": 2}), @@ -71,11 +145,24 @@ class ReadWriteTestSuite(BaseStandardTests): This just verifies that the fixture is set up properly to be empty after each test. + + .. dropdown:: Troubleshooting + + If this test fails, check that the test class (i.e., sub class of + ``ReadWriteTestSuite``) correctly clears the vector store in the + ``finally`` block. """ assert vectorstore.similarity_search("foo", k=1) == [] def test_deleting_documents(self, vectorstore: VectorStore) -> None: - """Test deleting documents from the vectorstore.""" + """Test deleting documents from the vectorstore. + + .. dropdown:: Troubleshooting + + If this test fails, check that ``add_documents`` preserves identifiers + passed in through ``ids``, and that ``delete`` correctly removes + documents. + """ documents = [ Document(page_content="foo", metadata={"id": 1}), Document(page_content="bar", metadata={"id": 2}), @@ -87,7 +174,13 @@ class ReadWriteTestSuite(BaseStandardTests): assert documents == [Document(page_content="bar", metadata={"id": 2}, id="2")] def test_deleting_bulk_documents(self, vectorstore: VectorStore) -> None: - """Test that we can delete several documents at once.""" + """Test that we can delete several documents at once. + + .. dropdown:: Troubleshooting + + If this test fails, check that ``delete`` correctly removes multiple + documents when given a list of IDs. + """ documents = [ Document(page_content="foo", metadata={"id": 1}), Document(page_content="bar", metadata={"id": 2}), @@ -100,14 +193,27 @@ class ReadWriteTestSuite(BaseStandardTests): assert documents == [Document(page_content="baz", metadata={"id": 3}, id="3")] def test_delete_missing_content(self, vectorstore: VectorStore) -> None: - """Deleting missing content should not raise an exception.""" + """Deleting missing content should not raise an exception. + + .. dropdown:: Troubleshooting + + If this test fails, check that ``delete`` does not raise an exception + when deleting IDs that do not exist. + """ vectorstore.delete(["1"]) vectorstore.delete(["1", "2", "3"]) def test_add_documents_with_ids_is_idempotent( self, vectorstore: VectorStore ) -> None: - """Adding by ID should be idempotent.""" + """Adding by ID should be idempotent. + + .. dropdown:: Troubleshooting + + If this test fails, check that adding the same document twice with the + same IDs has the same effect as adding it once (i.e., it does not + duplicate the documents). + """ documents = [ Document(page_content="foo", metadata={"id": 1}), Document(page_content="bar", metadata={"id": 2}), @@ -121,7 +227,14 @@ class ReadWriteTestSuite(BaseStandardTests): ] def test_add_documents_by_id_with_mutation(self, vectorstore: VectorStore) -> None: - """Test that we can overwrite by ID using add_documents.""" + """Test that we can overwrite by ID using add_documents. + + .. dropdown:: Troubleshooting + + If this test fails, check that when ``add_documents`` is called with an + ID that already exists in the vector store, the content is updated + rather than duplicated. + """ documents = [ Document(page_content="foo", metadata={"id": 1}), Document(page_content="bar", metadata={"id": 2}), @@ -150,7 +263,26 @@ class ReadWriteTestSuite(BaseStandardTests): ] def test_get_by_ids(self, vectorstore: VectorStore) -> None: - """Test get by IDs.""" + """Test get by IDs. + + This test requires that ``get_by_ids`` be implemented on the vector store. + + .. dropdown:: Troubleshooting + + If this test fails, check that ``get_by_ids`` is implemented and returns + documents in the same order as the IDs passed in. + + .. note:: + ``get_by_ids`` was added to the ``VectorStore`` interface in + ``langchain-core`` version 0.2.11. If difficult to implement, this + test can be skipped using a pytest ``xfail`` on the test class: + + .. code-block:: python + + @pytest.mark.xfail(reason=("get_by_ids not implemented.")) + def test_get_by_ids(self, vectorstore: VectorStore) -> None: + super().test_get_by_ids(vectorstore) + """ documents = [ Document(page_content="foo", metadata={"id": 1}), Document(page_content="bar", metadata={"id": 2}), @@ -163,13 +295,50 @@ class ReadWriteTestSuite(BaseStandardTests): ] def test_get_by_ids_missing(self, vectorstore: VectorStore) -> None: - """Test get by IDs with missing IDs.""" + """Test get by IDs with missing IDs. + + .. dropdown:: Troubleshooting + + If this test fails, check that ``get_by_ids`` is implemented and does not + raise an exception when given IDs that do not exist. + + .. note:: + ``get_by_ids`` was added to the ``VectorStore`` interface in + ``langchain-core`` version 0.2.11. If difficult to implement, this + test can be skipped using a pytest ``xfail`` on the test class: + + .. code-block:: python + + @pytest.mark.xfail(reason=("get_by_ids not implemented.")) + def test_get_by_ids_missing(self, vectorstore: VectorStore) -> None: + super().test_get_by_ids_missing(vectorstore) + """ # noqa: E501 # This should not raise an exception documents = vectorstore.get_by_ids(["1", "2", "3"]) assert documents == [] def test_add_documents_documents(self, vectorstore: VectorStore) -> None: - """Run add_documents tests.""" + """Run add_documents tests. + + .. dropdown:: Troubleshooting + + If this test fails, check that ``get_by_ids`` is implemented and returns + documents in the same order as the IDs passed in. + + Check also that ``add_documents`` will correctly generate string IDs if + none are provided. + + .. note:: + ``get_by_ids`` was added to the ``VectorStore`` interface in + ``langchain-core`` version 0.2.11. If difficult to implement, this + test can be skipped using a pytest ``xfail`` on the test class: + + .. code-block:: python + + @pytest.mark.xfail(reason=("get_by_ids not implemented.")) + def test_add_documents_documents(self, vectorstore: VectorStore) -> None: + super().test_add_documents_documents(vectorstore) + """ # noqa: E501 documents = [ Document(page_content="foo", metadata={"id": 1}), Document(page_content="bar", metadata={"id": 2}), @@ -181,7 +350,29 @@ class ReadWriteTestSuite(BaseStandardTests): ] def test_add_documents_with_existing_ids(self, vectorstore: VectorStore) -> None: - """Test that add_documentsing with existing IDs is idempotent.""" + """Test that add_documents with existing IDs is idempotent. + + .. dropdown:: Troubleshooting + + If this test fails, check that ``get_by_ids`` is implemented and returns + documents in the same order as the IDs passed in. + + This test also verifies that: + + 1. IDs specified in the ``Document.id`` field are assigned when adding documents. + 2. If some documents include IDs and others don't string IDs are generated for the latter. + + .. note:: + ``get_by_ids`` was added to the ``VectorStore`` interface in + ``langchain-core`` version 0.2.11. If difficult to implement, this + test can be skipped using a pytest ``xfail`` on the test class: + + .. code-block:: python + + @pytest.mark.xfail(reason=("get_by_ids not implemented.")) + def test_add_documents_with_existing_ids(self, vectorstore: VectorStore) -> None: + super().test_add_documents_with_existing_ids(vectorstore) + """ # noqa: E501 documents = [ Document(id="foo", page_content="foo", metadata={"id": 1}), Document(page_content="bar", metadata={"id": 2}), @@ -195,18 +386,70 @@ class ReadWriteTestSuite(BaseStandardTests): class AsyncReadWriteTestSuite(BaseStandardTests): - """Test suite for checking the **async** read-write API of a vectorstore. - - This test suite verifies the basic read-write API of a vectorstore. - - The test suite is designed for asynchronous vectorstores. + """Test suite for checking the async read-write API of a vector store. Implementers should subclass this test suite and provide a fixture - that returns an empty vectorstore for each test. + that returns an empty vector store for each test. - The fixture should use the `get_embeddings` method to get a pre-defined + The fixture should use the ``get_embeddings`` method to get a pre-defined embeddings model that should be used for this test suite. - """ + + Here is a template: + + .. code-block:: python + + from typing import AsyncGenerator + + import pytest + from langchain_core.vectorstores import VectorStore + from langchain_parrot_link.vectorstores import ParrotVectorStore + from langchain_tests.integration_tests.vectorstores import AsyncReadWriteTestSuite + + + class TestAsync(AsyncReadWriteTestSuite): + @pytest.fixture() + def vectorstore(self) -> AsyncGenerator[VectorStore, None]: # type: ignore + \"\"\"Get an empty vectorstore.\"\"\" + store = ParrotVectorStore(self.get_embeddings()) + # note: store should be EMPTY at this point + # if you need to delete data, you may do so here + try: + yield store + finally: + # cleanup operations, or deleting data + pass + + In the fixture, before the ``yield`` we instantiate an empty vector store. In the + ``finally`` block, we call whatever logic is necessary to bring the vector store + to a clean state. + + Example: + + .. code-block:: python + + from typing import AsyncGenerator, Generator + + import pytest + from langchain_core.vectorstores import VectorStore + from langchain_tests.integration_tests.vectorstores import AsyncReadWriteTestSuite + + from langchain_chroma import Chroma + + + class TestAsync(AsyncReadWriteTestSuite): + @pytest.fixture() + async def vectorstore(self) -> AsyncGenerator[VectorStore, None]: # type: ignore + \"\"\"Get an empty vectorstore for unit tests.\"\"\" + store = Chroma(embedding_function=self.get_embeddings()) + try: + yield store + finally: + store.delete_collection() + pass + + .. note:: + API references for individual test methods include troubleshooting tips. + """ # noqa: E501 @abstractmethod @pytest.fixture @@ -218,17 +461,39 @@ class AsyncReadWriteTestSuite(BaseStandardTests): @staticmethod def get_embeddings() -> Embeddings: - """A pre-defined embeddings model that should be used for this test.""" + """A pre-defined embeddings model that should be used for this test. + + This currently uses ``DeterministicFakeEmbedding`` from ``langchain-core``, + which uses numpy to generate random numbers based on a hash of the input text. + + The resulting embeddings are not meaningful, but they are deterministic. + """ return DeterministicFakeEmbedding( size=EMBEDDING_SIZE, ) async def test_vectorstore_is_empty(self, vectorstore: VectorStore) -> None: - """Test that the vectorstore is empty.""" + """Test that the vectorstore is empty. + + .. dropdown:: Troubleshooting + + If this test fails, check that the test class (i.e., sub class of + ``AsyncReadWriteTestSuite``) initializes an empty vector store in the + ``vectorestore`` fixture. + """ assert await vectorstore.asimilarity_search("foo", k=1) == [] async def test_add_documents(self, vectorstore: VectorStore) -> None: - """Test adding documents into the vectorstore.""" + """Test adding documents into the vectorstore. + + .. dropdown:: Troubleshooting + + If this test fails, check that: + + 1. We correctly initialize an empty vector store in the ``vectorestore`` fixture. + 2. Calling ``.asimilarity_search`` for the top ``k`` similar documents does not threshold by score. + 3. We do not mutate the original document object when adding it to the vector store (e.g., by adding an ID). + """ # noqa: E501 original_documents = [ Document(page_content="foo", metadata={"id": 1}), Document(page_content="bar", metadata={"id": 2}), @@ -252,11 +517,24 @@ class AsyncReadWriteTestSuite(BaseStandardTests): This just verifies that the fixture is set up properly to be empty after each test. + + .. dropdown:: Troubleshooting + + If this test fails, check that the test class (i.e., sub class of + ``AsyncReadWriteTestSuite``) correctly clears the vector store in the + ``finally`` block. """ assert await vectorstore.asimilarity_search("foo", k=1) == [] async def test_deleting_documents(self, vectorstore: VectorStore) -> None: - """Test deleting documents from the vectorstore.""" + """Test deleting documents from the vectorstore. + + .. dropdown:: Troubleshooting + + If this test fails, check that ``aadd_documents`` preserves identifiers + passed in through ``ids``, and that ``delete`` correctly removes + documents. + """ documents = [ Document(page_content="foo", metadata={"id": 1}), Document(page_content="bar", metadata={"id": 2}), @@ -268,7 +546,13 @@ class AsyncReadWriteTestSuite(BaseStandardTests): assert documents == [Document(page_content="bar", metadata={"id": 2}, id="2")] async def test_deleting_bulk_documents(self, vectorstore: VectorStore) -> None: - """Test that we can delete several documents at once.""" + """Test that we can delete several documents at once. + + .. dropdown:: Troubleshooting + + If this test fails, check that ``adelete`` correctly removes multiple + documents when given a list of IDs. + """ documents = [ Document(page_content="foo", metadata={"id": 1}), Document(page_content="bar", metadata={"id": 2}), @@ -281,14 +565,27 @@ class AsyncReadWriteTestSuite(BaseStandardTests): assert documents == [Document(page_content="baz", metadata={"id": 3}, id="3")] async def test_delete_missing_content(self, vectorstore: VectorStore) -> None: - """Deleting missing content should not raise an exception.""" + """Deleting missing content should not raise an exception. + + .. dropdown:: Troubleshooting + + If this test fails, check that ``adelete`` does not raise an exception + when deleting IDs that do not exist. + """ await vectorstore.adelete(["1"]) await vectorstore.adelete(["1", "2", "3"]) async def test_add_documents_with_ids_is_idempotent( self, vectorstore: VectorStore ) -> None: - """Adding by ID should be idempotent.""" + """Adding by ID should be idempotent. + + .. dropdown:: Troubleshooting + + If this test fails, check that adding the same document twice with the + same IDs has the same effect as adding it once (i.e., it does not + duplicate the documents). + """ documents = [ Document(page_content="foo", metadata={"id": 1}), Document(page_content="bar", metadata={"id": 2}), @@ -304,7 +601,14 @@ class AsyncReadWriteTestSuite(BaseStandardTests): async def test_add_documents_by_id_with_mutation( self, vectorstore: VectorStore ) -> None: - """Test that we can overwrite by ID using add_documents.""" + """Test that we can overwrite by ID using add_documents. + + .. dropdown:: Troubleshooting + + If this test fails, check that when ``aadd_documents`` is called with an + ID that already exists in the vector store, the content is updated + rather than duplicated. + """ documents = [ Document(page_content="foo", metadata={"id": 1}), Document(page_content="bar", metadata={"id": 2}), @@ -333,7 +637,26 @@ class AsyncReadWriteTestSuite(BaseStandardTests): ] async def test_get_by_ids(self, vectorstore: VectorStore) -> None: - """Test get by IDs.""" + """Test get by IDs. + + This test requires that ``get_by_ids`` be implemented on the vector store. + + .. dropdown:: Troubleshooting + + If this test fails, check that ``get_by_ids`` is implemented and returns + documents in the same order as the IDs passed in. + + .. note:: + ``get_by_ids`` was added to the ``VectorStore`` interface in + ``langchain-core`` version 0.2.11. If difficult to implement, this + test can be skipped using a pytest ``xfail`` on the test class: + + .. code-block:: python + + @pytest.mark.xfail(reason=("get_by_ids not implemented.")) + async def test_get_by_ids(self, vectorstore: VectorStore) -> None: + await super().test_get_by_ids(vectorstore) + """ documents = [ Document(page_content="foo", metadata={"id": 1}), Document(page_content="bar", metadata={"id": 2}), @@ -346,12 +669,49 @@ class AsyncReadWriteTestSuite(BaseStandardTests): ] async def test_get_by_ids_missing(self, vectorstore: VectorStore) -> None: - """Test get by IDs with missing IDs.""" + """Test get by IDs with missing IDs. + + .. dropdown:: Troubleshooting + + If this test fails, check that ``get_by_ids`` is implemented and does not + raise an exception when given IDs that do not exist. + + .. note:: + ``get_by_ids`` was added to the ``VectorStore`` interface in + ``langchain-core`` version 0.2.11. If difficult to implement, this + test can be skipped using a pytest ``xfail`` on the test class: + + .. code-block:: python + + @pytest.mark.xfail(reason=("get_by_ids not implemented.")) + async def test_get_by_ids_missing(self, vectorstore: VectorStore) -> None: + await super().test_get_by_ids_missing(vectorstore) + """ # noqa: E501 # This should not raise an exception assert await vectorstore.aget_by_ids(["1", "2", "3"]) == [] async def test_add_documents_documents(self, vectorstore: VectorStore) -> None: - """Run add_documents tests.""" + """Run add_documents tests. + + .. dropdown:: Troubleshooting + + If this test fails, check that ``get_by_ids`` is implemented and returns + documents in the same order as the IDs passed in. + + Check also that ``aadd_documents`` will correctly generate string IDs if + none are provided. + + .. note:: + ``get_by_ids`` was added to the ``VectorStore`` interface in + ``langchain-core`` version 0.2.11. If difficult to implement, this + test can be skipped using a pytest ``xfail`` on the test class: + + .. code-block:: python + + @pytest.mark.xfail(reason=("get_by_ids not implemented.")) + async def test_add_documents_documents(self, vectorstore: VectorStore) -> None: + await super().test_add_documents_documents(vectorstore) + """ # noqa: E501 documents = [ Document(page_content="foo", metadata={"id": 1}), Document(page_content="bar", metadata={"id": 2}), @@ -365,7 +725,29 @@ class AsyncReadWriteTestSuite(BaseStandardTests): async def test_add_documents_with_existing_ids( self, vectorstore: VectorStore ) -> None: - """Test that add_documentsing with existing IDs is idempotent.""" + """Test that add_documents with existing IDs is idempotent. + + .. dropdown:: Troubleshooting + + If this test fails, check that ``get_by_ids`` is implemented and returns + documents in the same order as the IDs passed in. + + This test also verifies that: + + 1. IDs specified in the ``Document.id`` field are assigned when adding documents. + 2. If some documents include IDs and others don't string IDs are generated for the latter. + + .. note:: + ``get_by_ids`` was added to the ``VectorStore`` interface in + ``langchain-core`` version 0.2.11. If difficult to implement, this + test can be skipped using a pytest ``xfail`` on the test class: + + .. code-block:: python + + @pytest.mark.xfail(reason=("get_by_ids not implemented.")) + async def test_add_documents_with_existing_ids(self, vectorstore: VectorStore) -> None: + await super().test_add_documents_with_existing_ids(vectorstore) + """ # noqa: E501 documents = [ Document(id="foo", page_content="foo", metadata={"id": 1}), Document(page_content="bar", metadata={"id": 2}), diff --git a/libs/standard-tests/langchain_tests/unit_tests/chat_models.py b/libs/standard-tests/langchain_tests/unit_tests/chat_models.py index 2de0776f5e3..71f3dd2169c 100644 --- a/libs/standard-tests/langchain_tests/unit_tests/chat_models.py +++ b/libs/standard-tests/langchain_tests/unit_tests/chat_models.py @@ -380,29 +380,30 @@ class ChatModelTests(BaseStandardTests): class ChatModelUnitTests(ChatModelTests): """Base class for chat model unit tests. - Test subclasses must implement the following two properties: + Test subclasses must implement the ``chat_model_class`` and + ``chat_model_params`` properties to specify what model to test and its + initialization parameters. - chat_model_class - The chat model class to test, e.g., ``ChatParrotLink``. + Example: - Example: + .. code-block:: python - .. code-block:: python + from typing import Type + from langchain_tests.unit_tests import ChatModelUnitTests + from my_package.chat_models import MyChatModel + + + class TestMyChatModelUnit(ChatModelUnitTests): @property - def chat_model_class(self) -> Type[ChatParrotLink]: - return ChatParrotLink - - chat_model_params - Initialization parameters for the chat model. - - Example: - - .. code-block:: python + def chat_model_class(self) -> Type[MyChatModel]: + # Return the chat model class to test here + return MyChatModel @property def chat_model_params(self) -> dict: - return {"model": "bird-brain-001", "temperature": 0} + # Return initialization parameters for the model. + return {"model": "model-001", "temperature": 0} .. note:: API references for individual test methods include troubleshooting tips. @@ -486,7 +487,8 @@ class ChatModelUnitTests(ChatModelTests): .. dropdown:: Troubleshooting If this test fails, ensure that ``init_from_env_params`` is specified - correctly. + correctly and that model parameters are properly set from environment + variables during initialization. """ env_params, model_params, expected_attrs = self.init_from_env_params if not env_params: diff --git a/libs/standard-tests/langchain_tests/unit_tests/embeddings.py b/libs/standard-tests/langchain_tests/unit_tests/embeddings.py index da7b7851384..c580243b16d 100644 --- a/libs/standard-tests/langchain_tests/unit_tests/embeddings.py +++ b/libs/standard-tests/langchain_tests/unit_tests/embeddings.py @@ -25,17 +25,98 @@ class EmbeddingsTests(BaseStandardTests): class EmbeddingsUnitTests(EmbeddingsTests): + """Base class for embeddings unit tests. + + Test subclasses must implement the ``embeddings_class`` property to specify the + embeddings model to be tested. You can also override the + ``embedding_model_params`` property to specify initialization parameters. + + Example: + + .. code-block:: python + + from typing import Type + + from langchain_tests.unit_tests import EmbeddingsUnitTests + from my_package.embeddings import MyEmbeddingsModel + + + class TestMyEmbeddingsModelUnit(EmbeddingsUnitTests): + @property + def embeddings_class(self) -> Type[MyEmbeddingsModel]: + # Return the embeddings model class to test here + return MyEmbeddingsModel + + @property + def embedding_model_params(self) -> dict: + # Return initialization parameters for the model. + return {"model": "model-001"} + + .. note:: + API references for individual test methods include troubleshooting tips. + + Testing initialization from environment variables + Overriding the ``init_from_env_params`` property will enable additional tests + for initialization from environment variables. See below for details. + + .. dropdown:: init_from_env_params + + This property is used in unit tests to test initialization from + environment variables. It should return a tuple of three dictionaries + that specify the environment variables, additional initialization args, + and expected instance attributes to check. + + Defaults to empty dicts. If not overridden, the test is skipped. + + Example: + + .. code-block:: python + + @property + def init_from_env_params(self) -> Tuple[dict, dict, dict]: + return ( + { + "MY_API_KEY": "api_key", + }, + { + "model": "model-001", + }, + { + "my_api_key": "api_key", + }, + ) + """ # noqa: E501 + def test_init(self) -> None: + """Test model initialization. + + .. dropdown:: Troubleshooting + + If this test fails, ensure that ``embedding_model_params`` is specified + and the model can be initialized from those params. + """ model = self.embeddings_class(**self.embedding_model_params) assert model is not None @property def init_from_env_params(self) -> Tuple[dict, dict, dict]: - """Return env vars, init args, and expected instance attrs for initializing - from env vars.""" + """This property is used in unit tests to test initialization from environment + variables. It should return a tuple of three dictionaries that specify the + environment variables, additional initialization args, and expected instance + attributes to check.""" return {}, {}, {} def test_init_from_env(self) -> None: + """Test initialization from environment variables. Relies on the + ``init_from_env_params`` property. Test is skipped if that property is not + set. + + .. dropdown:: Troubleshooting + + If this test fails, ensure that ``init_from_env_params`` is specified + correctly and that model parameters are properly set from environment + variables during initialization. + """ env_params, embeddings_params, expected_attrs = self.init_from_env_params if env_params: with mock.patch.dict(os.environ, env_params): diff --git a/libs/standard-tests/poetry.lock b/libs/standard-tests/poetry.lock index a10861100df..0bb01c5870e 100644 --- a/libs/standard-tests/poetry.lock +++ b/libs/standard-tests/poetry.lock @@ -309,7 +309,7 @@ files = [ [[package]] name = "langchain-core" -version = "0.3.19" +version = "0.3.21" description = "Building applications with LLMs through composability" optional = false python-versions = ">=3.9,<4.0" @@ -334,13 +334,13 @@ url = "../core" [[package]] name = "langsmith" -version = "0.1.144" +version = "0.1.147" description = "Client library to connect to the LangSmith LLM Tracing and Evaluation Platform." optional = false python-versions = "<4.0,>=3.8.1" files = [ - {file = "langsmith-0.1.144-py3-none-any.whl", hash = "sha256:08ffb975bff2e82fc6f5428837c64c074ea25102d08a25e256361a80812c6100"}, - {file = "langsmith-0.1.144.tar.gz", hash = "sha256:b621f358d5a33441d7b5e7264c376bf4ea82bfc62d7e41aafc0f8094e3bd6369"}, + {file = "langsmith-0.1.147-py3-none-any.whl", hash = "sha256:7166fc23b965ccf839d64945a78e9f1157757add228b086141eb03a60d699a15"}, + {file = "langsmith-0.1.147.tar.gz", hash = "sha256:2e933220318a4e73034657103b3b1a3a6109cc5db3566a7e8e03be8d6d7def7a"}, ] [package.dependencies] @@ -353,6 +353,9 @@ pydantic = [ requests = ">=2,<3" requests-toolbelt = ">=1.0.0,<2.0.0" +[package.extras] +langsmith-pyo3 = ["langsmith-pyo3 (>=0.1.0rc2,<0.2.0)"] + [[package]] name = "mypy" version = "1.13.0" @@ -464,69 +467,86 @@ files = [ [[package]] name = "orjson" -version = "3.10.11" +version = "3.10.12" description = "Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy" optional = false python-versions = ">=3.8" files = [ - {file = "orjson-3.10.11-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:6dade64687f2bd7c090281652fe18f1151292d567a9302b34c2dbb92a3872f1f"}, - {file = "orjson-3.10.11-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:82f07c550a6ccd2b9290849b22316a609023ed851a87ea888c0456485a7d196a"}, - {file = "orjson-3.10.11-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bd9a187742d3ead9df2e49240234d728c67c356516cf4db018833a86f20ec18c"}, - {file = "orjson-3.10.11-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:77b0fed6f209d76c1c39f032a70df2d7acf24b1812ca3e6078fd04e8972685a3"}, - {file = "orjson-3.10.11-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:63fc9d5fe1d4e8868f6aae547a7b8ba0a2e592929245fff61d633f4caccdcdd6"}, - {file = "orjson-3.10.11-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:65cd3e3bb4fbb4eddc3c1e8dce10dc0b73e808fcb875f9fab40c81903dd9323e"}, - {file = "orjson-3.10.11-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:6f67c570602300c4befbda12d153113b8974a3340fdcf3d6de095ede86c06d92"}, - {file = "orjson-3.10.11-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:1f39728c7f7d766f1f5a769ce4d54b5aaa4c3f92d5b84817053cc9995b977acc"}, - {file = "orjson-3.10.11-cp310-none-win32.whl", hash = "sha256:1789d9db7968d805f3d94aae2c25d04014aae3a2fa65b1443117cd462c6da647"}, - {file = "orjson-3.10.11-cp310-none-win_amd64.whl", hash = "sha256:5576b1e5a53a5ba8f8df81872bb0878a112b3ebb1d392155f00f54dd86c83ff6"}, - {file = "orjson-3.10.11-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:1444f9cb7c14055d595de1036f74ecd6ce15f04a715e73f33bb6326c9cef01b6"}, - {file = "orjson-3.10.11-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cdec57fe3b4bdebcc08a946db3365630332dbe575125ff3d80a3272ebd0ddafe"}, - {file = "orjson-3.10.11-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4eed32f33a0ea6ef36ccc1d37f8d17f28a1d6e8eefae5928f76aff8f1df85e67"}, - {file = "orjson-3.10.11-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:80df27dd8697242b904f4ea54820e2d98d3f51f91e97e358fc13359721233e4b"}, - {file = "orjson-3.10.11-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:705f03cee0cb797256d54de6695ef219e5bc8c8120b6654dd460848d57a9af3d"}, - {file = "orjson-3.10.11-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:03246774131701de8e7059b2e382597da43144a9a7400f178b2a32feafc54bd5"}, - {file = "orjson-3.10.11-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8b5759063a6c940a69c728ea70d7c33583991c6982915a839c8da5f957e0103a"}, - {file = "orjson-3.10.11-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:677f23e32491520eebb19c99bb34675daf5410c449c13416f7f0d93e2cf5f981"}, - {file = "orjson-3.10.11-cp311-none-win32.whl", hash = "sha256:a11225d7b30468dcb099498296ffac36b4673a8398ca30fdaec1e6c20df6aa55"}, - {file = "orjson-3.10.11-cp311-none-win_amd64.whl", hash = "sha256:df8c677df2f9f385fcc85ab859704045fa88d4668bc9991a527c86e710392bec"}, - {file = "orjson-3.10.11-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:360a4e2c0943da7c21505e47cf6bd725588962ff1d739b99b14e2f7f3545ba51"}, - {file = "orjson-3.10.11-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:496e2cb45de21c369079ef2d662670a4892c81573bcc143c4205cae98282ba97"}, - {file = "orjson-3.10.11-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7dfa8db55c9792d53c5952900c6a919cfa377b4f4534c7a786484a6a4a350c19"}, - {file = "orjson-3.10.11-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:51f3382415747e0dbda9dade6f1e1a01a9d37f630d8c9049a8ed0e385b7a90c0"}, - {file = "orjson-3.10.11-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f35a1b9f50a219f470e0e497ca30b285c9f34948d3c8160d5ad3a755d9299433"}, - {file = "orjson-3.10.11-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e2f3b7c5803138e67028dde33450e054c87e0703afbe730c105f1fcd873496d5"}, - {file = "orjson-3.10.11-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f91d9eb554310472bd09f5347950b24442600594c2edc1421403d7610a0998fd"}, - {file = "orjson-3.10.11-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:dfbb2d460a855c9744bbc8e36f9c3a997c4b27d842f3d5559ed54326e6911f9b"}, - {file = "orjson-3.10.11-cp312-none-win32.whl", hash = "sha256:d4a62c49c506d4d73f59514986cadebb7e8d186ad510c518f439176cf8d5359d"}, - {file = "orjson-3.10.11-cp312-none-win_amd64.whl", hash = "sha256:f1eec3421a558ff7a9b010a6c7effcfa0ade65327a71bb9b02a1c3b77a247284"}, - {file = "orjson-3.10.11-cp313-cp313-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:c46294faa4e4d0eb73ab68f1a794d2cbf7bab33b1dda2ac2959ffb7c61591899"}, - {file = "orjson-3.10.11-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:52e5834d7d6e58a36846e059d00559cb9ed20410664f3ad156cd2cc239a11230"}, - {file = "orjson-3.10.11-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a2fc947e5350fdce548bfc94f434e8760d5cafa97fb9c495d2fef6757aa02ec0"}, - {file = "orjson-3.10.11-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0efabbf839388a1dab5b72b5d3baedbd6039ac83f3b55736eb9934ea5494d258"}, - {file = "orjson-3.10.11-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a3f29634260708c200c4fe148e42b4aae97d7b9fee417fbdd74f8cfc265f15b0"}, - {file = "orjson-3.10.11-cp313-none-win32.whl", hash = "sha256:1a1222ffcee8a09476bbdd5d4f6f33d06d0d6642df2a3d78b7a195ca880d669b"}, - {file = "orjson-3.10.11-cp313-none-win_amd64.whl", hash = "sha256:bc274ac261cc69260913b2d1610760e55d3c0801bb3457ba7b9004420b6b4270"}, - {file = "orjson-3.10.11-cp38-cp38-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:19b3763e8bbf8ad797df6b6b5e0fc7c843ec2e2fc0621398534e0c6400098f87"}, - {file = "orjson-3.10.11-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1be83a13312e5e58d633580c5eb8d0495ae61f180da2722f20562974188af205"}, - {file = "orjson-3.10.11-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:afacfd1ab81f46dedd7f6001b6d4e8de23396e4884cd3c3436bd05defb1a6446"}, - {file = "orjson-3.10.11-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cb4d0bea56bba596723d73f074c420aec3b2e5d7d30698bc56e6048066bd560c"}, - {file = "orjson-3.10.11-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:96ed1de70fcb15d5fed529a656df29f768187628727ee2788344e8a51e1c1350"}, - {file = "orjson-3.10.11-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4bfb30c891b530f3f80e801e3ad82ef150b964e5c38e1fb8482441c69c35c61c"}, - {file = "orjson-3.10.11-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:d496c74fc2b61341e3cefda7eec21b7854c5f672ee350bc55d9a4997a8a95204"}, - {file = "orjson-3.10.11-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:655a493bac606655db9a47fe94d3d84fc7f3ad766d894197c94ccf0c5408e7d3"}, - {file = "orjson-3.10.11-cp38-none-win32.whl", hash = "sha256:b9546b278c9fb5d45380f4809e11b4dd9844ca7aaf1134024503e134ed226161"}, - {file = "orjson-3.10.11-cp38-none-win_amd64.whl", hash = "sha256:b592597fe551d518f42c5a2eb07422eb475aa8cfdc8c51e6da7054b836b26782"}, - {file = "orjson-3.10.11-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:c95f2ecafe709b4e5c733b5e2768ac569bed308623c85806c395d9cca00e08af"}, - {file = "orjson-3.10.11-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:80c00d4acded0c51c98754fe8218cb49cb854f0f7eb39ea4641b7f71732d2cb7"}, - {file = "orjson-3.10.11-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:461311b693d3d0a060439aa669c74f3603264d4e7a08faa68c47ae5a863f352d"}, - {file = "orjson-3.10.11-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:52ca832f17d86a78cbab86cdc25f8c13756ebe182b6fc1a97d534051c18a08de"}, - {file = "orjson-3.10.11-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f4c57ea78a753812f528178aa2f1c57da633754c91d2124cb28991dab4c79a54"}, - {file = "orjson-3.10.11-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b7fcfc6f7ca046383fb954ba528587e0f9336828b568282b27579c49f8e16aad"}, - {file = "orjson-3.10.11-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:86b9dd983857970c29e4c71bb3e95ff085c07d3e83e7c46ebe959bac07ebd80b"}, - {file = "orjson-3.10.11-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:4d83f87582d223e54efb2242a79547611ba4ebae3af8bae1e80fa9a0af83bb7f"}, - {file = "orjson-3.10.11-cp39-none-win32.whl", hash = "sha256:9fd0ad1c129bc9beb1154c2655f177620b5beaf9a11e0d10bac63ef3fce96950"}, - {file = "orjson-3.10.11-cp39-none-win_amd64.whl", hash = "sha256:10f416b2a017c8bd17f325fb9dee1fb5cdd7a54e814284896b7c3f2763faa017"}, - {file = "orjson-3.10.11.tar.gz", hash = "sha256:e35b6d730de6384d5b2dab5fd23f0d76fae8bbc8c353c2f78210aa5fa4beb3ef"}, + {file = "orjson-3.10.12-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:ece01a7ec71d9940cc654c482907a6b65df27251255097629d0dea781f255c6d"}, + {file = "orjson-3.10.12-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c34ec9aebc04f11f4b978dd6caf697a2df2dd9b47d35aa4cc606cabcb9df69d7"}, + {file = "orjson-3.10.12-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fd6ec8658da3480939c79b9e9e27e0db31dffcd4ba69c334e98c9976ac29140e"}, + {file = "orjson-3.10.12-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f17e6baf4cf01534c9de8a16c0c611f3d94925d1701bf5f4aff17003677d8ced"}, + {file = "orjson-3.10.12-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6402ebb74a14ef96f94a868569f5dccf70d791de49feb73180eb3c6fda2ade56"}, + {file = "orjson-3.10.12-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0000758ae7c7853e0a4a6063f534c61656ebff644391e1f81698c1b2d2fc8cd2"}, + {file = "orjson-3.10.12-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:888442dcee99fd1e5bd37a4abb94930915ca6af4db50e23e746cdf4d1e63db13"}, + {file = "orjson-3.10.12-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:c1f7a3ce79246aa0e92f5458d86c54f257fb5dfdc14a192651ba7ec2c00f8a05"}, + {file = "orjson-3.10.12-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:802a3935f45605c66fb4a586488a38af63cb37aaad1c1d94c982c40dcc452e85"}, + {file = "orjson-3.10.12-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:1da1ef0113a2be19bb6c557fb0ec2d79c92ebd2fed4cfb1b26bab93f021fb885"}, + {file = "orjson-3.10.12-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7a3273e99f367f137d5b3fecb5e9f45bcdbfac2a8b2f32fbc72129bbd48789c2"}, + {file = "orjson-3.10.12-cp310-none-win32.whl", hash = "sha256:475661bf249fd7907d9b0a2a2421b4e684355a77ceef85b8352439a9163418c3"}, + {file = "orjson-3.10.12-cp310-none-win_amd64.whl", hash = "sha256:87251dc1fb2b9e5ab91ce65d8f4caf21910d99ba8fb24b49fd0c118b2362d509"}, + {file = "orjson-3.10.12-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:a734c62efa42e7df94926d70fe7d37621c783dea9f707a98cdea796964d4cf74"}, + {file = "orjson-3.10.12-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:750f8b27259d3409eda8350c2919a58b0cfcd2054ddc1bd317a643afc646ef23"}, + {file = "orjson-3.10.12-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bb52c22bfffe2857e7aa13b4622afd0dd9d16ea7cc65fd2bf318d3223b1b6252"}, + {file = "orjson-3.10.12-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:440d9a337ac8c199ff8251e100c62e9488924c92852362cd27af0e67308c16ef"}, + {file = "orjson-3.10.12-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a9e15c06491c69997dfa067369baab3bf094ecb74be9912bdc4339972323f252"}, + {file = "orjson-3.10.12-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:362d204ad4b0b8724cf370d0cd917bb2dc913c394030da748a3bb632445ce7c4"}, + {file = "orjson-3.10.12-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2b57cbb4031153db37b41622eac67329c7810e5f480fda4cfd30542186f006ae"}, + {file = "orjson-3.10.12-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:165c89b53ef03ce0d7c59ca5c82fa65fe13ddf52eeb22e859e58c237d4e33b9b"}, + {file = "orjson-3.10.12-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:5dee91b8dfd54557c1a1596eb90bcd47dbcd26b0baaed919e6861f076583e9da"}, + {file = "orjson-3.10.12-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:77a4e1cfb72de6f905bdff061172adfb3caf7a4578ebf481d8f0530879476c07"}, + {file = "orjson-3.10.12-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:038d42c7bc0606443459b8fe2d1f121db474c49067d8d14c6a075bbea8bf14dd"}, + {file = "orjson-3.10.12-cp311-none-win32.whl", hash = "sha256:03b553c02ab39bed249bedd4abe37b2118324d1674e639b33fab3d1dafdf4d79"}, + {file = "orjson-3.10.12-cp311-none-win_amd64.whl", hash = "sha256:8b8713b9e46a45b2af6b96f559bfb13b1e02006f4242c156cbadef27800a55a8"}, + {file = "orjson-3.10.12-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:53206d72eb656ca5ac7d3a7141e83c5bbd3ac30d5eccfe019409177a57634b0d"}, + {file = "orjson-3.10.12-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac8010afc2150d417ebda810e8df08dd3f544e0dd2acab5370cfa6bcc0662f8f"}, + {file = "orjson-3.10.12-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ed459b46012ae950dd2e17150e838ab08215421487371fa79d0eced8d1461d70"}, + {file = "orjson-3.10.12-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8dcb9673f108a93c1b52bfc51b0af422c2d08d4fc710ce9c839faad25020bb69"}, + {file = "orjson-3.10.12-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:22a51ae77680c5c4652ebc63a83d5255ac7d65582891d9424b566fb3b5375ee9"}, + {file = "orjson-3.10.12-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:910fdf2ac0637b9a77d1aad65f803bac414f0b06f720073438a7bd8906298192"}, + {file = "orjson-3.10.12-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:24ce85f7100160936bc2116c09d1a8492639418633119a2224114f67f63a4559"}, + {file = "orjson-3.10.12-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8a76ba5fc8dd9c913640292df27bff80a685bed3a3c990d59aa6ce24c352f8fc"}, + {file = "orjson-3.10.12-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:ff70ef093895fd53f4055ca75f93f047e088d1430888ca1229393a7c0521100f"}, + {file = "orjson-3.10.12-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:f4244b7018b5753ecd10a6d324ec1f347da130c953a9c88432c7fbc8875d13be"}, + {file = "orjson-3.10.12-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:16135ccca03445f37921fa4b585cff9a58aa8d81ebcb27622e69bfadd220b32c"}, + {file = "orjson-3.10.12-cp312-none-win32.whl", hash = "sha256:2d879c81172d583e34153d524fcba5d4adafbab8349a7b9f16ae511c2cee8708"}, + {file = "orjson-3.10.12-cp312-none-win_amd64.whl", hash = "sha256:fc23f691fa0f5c140576b8c365bc942d577d861a9ee1142e4db468e4e17094fb"}, + {file = "orjson-3.10.12-cp313-cp313-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:47962841b2a8aa9a258b377f5188db31ba49af47d4003a32f55d6f8b19006543"}, + {file = "orjson-3.10.12-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6334730e2532e77b6054e87ca84f3072bee308a45a452ea0bffbbbc40a67e296"}, + {file = "orjson-3.10.12-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:accfe93f42713c899fdac2747e8d0d5c659592df2792888c6c5f829472e4f85e"}, + {file = "orjson-3.10.12-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a7974c490c014c48810d1dede6c754c3cc46598da758c25ca3b4001ac45b703f"}, + {file = "orjson-3.10.12-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:3f250ce7727b0b2682f834a3facff88e310f52f07a5dcfd852d99637d386e79e"}, + {file = "orjson-3.10.12-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:f31422ff9486ae484f10ffc51b5ab2a60359e92d0716fcce1b3593d7bb8a9af6"}, + {file = "orjson-3.10.12-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5f29c5d282bb2d577c2a6bbde88d8fdcc4919c593f806aac50133f01b733846e"}, + {file = "orjson-3.10.12-cp313-none-win32.whl", hash = "sha256:f45653775f38f63dc0e6cd4f14323984c3149c05d6007b58cb154dd080ddc0dc"}, + {file = "orjson-3.10.12-cp313-none-win_amd64.whl", hash = "sha256:229994d0c376d5bdc91d92b3c9e6be2f1fbabd4cc1b59daae1443a46ee5e9825"}, + {file = "orjson-3.10.12-cp38-cp38-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:7d69af5b54617a5fac5c8e5ed0859eb798e2ce8913262eb522590239db6c6763"}, + {file = "orjson-3.10.12-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ed119ea7d2953365724a7059231a44830eb6bbb0cfead33fcbc562f5fd8f935"}, + {file = "orjson-3.10.12-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9c5fc1238ef197e7cad5c91415f524aaa51e004be5a9b35a1b8a84ade196f73f"}, + {file = "orjson-3.10.12-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:43509843990439b05f848539d6f6198d4ac86ff01dd024b2f9a795c0daeeab60"}, + {file = "orjson-3.10.12-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f72e27a62041cfb37a3de512247ece9f240a561e6c8662276beaf4d53d406db4"}, + {file = "orjson-3.10.12-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9a904f9572092bb6742ab7c16c623f0cdccbad9eeb2d14d4aa06284867bddd31"}, + {file = "orjson-3.10.12-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:855c0833999ed5dc62f64552db26f9be767434917d8348d77bacaab84f787d7b"}, + {file = "orjson-3.10.12-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:897830244e2320f6184699f598df7fb9db9f5087d6f3f03666ae89d607e4f8ed"}, + {file = "orjson-3.10.12-cp38-cp38-musllinux_1_2_armv7l.whl", hash = "sha256:0b32652eaa4a7539f6f04abc6243619c56f8530c53bf9b023e1269df5f7816dd"}, + {file = "orjson-3.10.12-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:36b4aa31e0f6a1aeeb6f8377769ca5d125db000f05c20e54163aef1d3fe8e833"}, + {file = "orjson-3.10.12-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:5535163054d6cbf2796f93e4f0dbc800f61914c0e3c4ed8499cf6ece22b4a3da"}, + {file = "orjson-3.10.12-cp38-none-win32.whl", hash = "sha256:90a5551f6f5a5fa07010bf3d0b4ca2de21adafbbc0af6cb700b63cd767266cb9"}, + {file = "orjson-3.10.12-cp38-none-win_amd64.whl", hash = "sha256:703a2fb35a06cdd45adf5d733cf613cbc0cb3ae57643472b16bc22d325b5fb6c"}, + {file = "orjson-3.10.12-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:f29de3ef71a42a5822765def1febfb36e0859d33abf5c2ad240acad5c6a1b78d"}, + {file = "orjson-3.10.12-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:de365a42acc65d74953f05e4772c974dad6c51cfc13c3240899f534d611be967"}, + {file = "orjson-3.10.12-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:91a5a0158648a67ff0004cb0df5df7dcc55bfc9ca154d9c01597a23ad54c8d0c"}, + {file = "orjson-3.10.12-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c47ce6b8d90fe9646a25b6fb52284a14ff215c9595914af63a5933a49972ce36"}, + {file = "orjson-3.10.12-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0eee4c2c5bfb5c1b47a5db80d2ac7aaa7e938956ae88089f098aff2c0f35d5d8"}, + {file = "orjson-3.10.12-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:35d3081bbe8b86587eb5c98a73b97f13d8f9fea685cf91a579beddacc0d10566"}, + {file = "orjson-3.10.12-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:73c23a6e90383884068bc2dba83d5222c9fcc3b99a0ed2411d38150734236755"}, + {file = "orjson-3.10.12-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:5472be7dc3269b4b52acba1433dac239215366f89dc1d8d0e64029abac4e714e"}, + {file = "orjson-3.10.12-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:7319cda750fca96ae5973efb31b17d97a5c5225ae0bc79bf5bf84df9e1ec2ab6"}, + {file = "orjson-3.10.12-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:74d5ca5a255bf20b8def6a2b96b1e18ad37b4a122d59b154c458ee9494377f80"}, + {file = "orjson-3.10.12-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:ff31d22ecc5fb85ef62c7d4afe8301d10c558d00dd24274d4bbe464380d3cd69"}, + {file = "orjson-3.10.12-cp39-none-win32.whl", hash = "sha256:c22c3ea6fba91d84fcb4cda30e64aff548fcf0c44c876e681f47d61d24b12e6b"}, + {file = "orjson-3.10.12-cp39-none-win_amd64.whl", hash = "sha256:be604f60d45ace6b0b33dd990a66b4526f1a7a186ac411c942674625456ca548"}, + {file = "orjson-3.10.12.tar.gz", hash = "sha256:0a78bbda3aea0f9f079057ee1ee8a1ecf790d4f1af88dd67493c6b8ee52506ff"}, ] [[package]] @@ -557,18 +577,18 @@ testing = ["pytest", "pytest-benchmark"] [[package]] name = "pydantic" -version = "2.10.0" +version = "2.10.3" description = "Data validation using Python type hints" optional = false python-versions = ">=3.8" files = [ - {file = "pydantic-2.10.0-py3-none-any.whl", hash = "sha256:5e7807ba9201bdf61b1b58aa6eb690916c40a47acfb114b1b4fef3e7fd5b30fc"}, - {file = "pydantic-2.10.0.tar.gz", hash = "sha256:0aca0f045ff6e2f097f1fe89521115335f15049eeb8a7bef3dafe4b19a74e289"}, + {file = "pydantic-2.10.3-py3-none-any.whl", hash = "sha256:be04d85bbc7b65651c5f8e6b9976ed9c6f41782a55524cef079a34a0bb82144d"}, + {file = "pydantic-2.10.3.tar.gz", hash = "sha256:cb5ac360ce894ceacd69c403187900a02c4b20b693a9dd1d643e1effab9eadf9"}, ] [package.dependencies] annotated-types = ">=0.6.0" -pydantic-core = "2.27.0" +pydantic-core = "2.27.1" typing-extensions = ">=4.12.2" [package.extras] @@ -577,111 +597,111 @@ timezone = ["tzdata"] [[package]] name = "pydantic-core" -version = "2.27.0" +version = "2.27.1" description = "Core functionality for Pydantic validation and serialization" optional = false python-versions = ">=3.8" files = [ - {file = "pydantic_core-2.27.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:cd2ac6b919f7fed71b17fe0b4603c092a4c9b5bae414817c9c81d3c22d1e1bcc"}, - {file = "pydantic_core-2.27.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e015833384ca3e1a0565a79f5d953b0629d9138021c27ad37c92a9fa1af7623c"}, - {file = "pydantic_core-2.27.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:db72e40628967f6dc572020d04b5f800d71264e0531c6da35097e73bdf38b003"}, - {file = "pydantic_core-2.27.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:df45c4073bed486ea2f18757057953afed8dd77add7276ff01bccb79982cf46c"}, - {file = "pydantic_core-2.27.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:836a4bfe0cc6d36dc9a9cc1a7b391265bf6ce9d1eb1eac62ac5139f5d8d9a6fa"}, - {file = "pydantic_core-2.27.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4bf1340ae507f6da6360b24179c2083857c8ca7644aab65807023cf35404ea8d"}, - {file = "pydantic_core-2.27.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5ab325fc86fbc077284c8d7f996d904d30e97904a87d6fb303dce6b3de7ebba9"}, - {file = "pydantic_core-2.27.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1da0c98a85a6c6ed702d5556db3b09c91f9b0b78de37b7593e2de8d03238807a"}, - {file = "pydantic_core-2.27.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:7b0202ebf2268954090209a84f9897345719e46a57c5f2c9b7b250ca0a9d3e63"}, - {file = "pydantic_core-2.27.0-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:35380671c3c921fe8adf31ad349dc6f7588b7e928dbe44e1093789734f607399"}, - {file = "pydantic_core-2.27.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6b4c19525c3538fbc0bbda6229f9682fb8199ce9ac37395880e6952798e00373"}, - {file = "pydantic_core-2.27.0-cp310-none-win32.whl", hash = "sha256:333c840a1303d1474f491e7be0b718226c730a39ead0f7dab2c7e6a2f3855555"}, - {file = "pydantic_core-2.27.0-cp310-none-win_amd64.whl", hash = "sha256:99b2863c1365f43f74199c980a3d40f18a218fbe683dd64e470199db426c4d6a"}, - {file = "pydantic_core-2.27.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:4523c4009c3f39d948e01962223c9f5538602e7087a628479b723c939fab262d"}, - {file = "pydantic_core-2.27.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:84af1cf7bfdcbc6fcf5a5f70cc9896205e0350306e4dd73d54b6a18894f79386"}, - {file = "pydantic_core-2.27.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e65466b31be1070b4a5b7dbfbd14b247884cb8e8b79c64fb0f36b472912dbaea"}, - {file = "pydantic_core-2.27.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a5c022bb0d453192426221605efc865373dde43b17822a264671c53b068ac20c"}, - {file = "pydantic_core-2.27.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6bb69bf3b6500f195c3deb69c1205ba8fc3cb21d1915f1f158a10d6b1ef29b6a"}, - {file = "pydantic_core-2.27.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0aa4d1b2eba9a325897308b3124014a142cdccb9f3e016f31d3ebee6b5ea5e75"}, - {file = "pydantic_core-2.27.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8e96ca781e0c01e32115912ebdf7b3fb0780ce748b80d7d28a0802fa9fbaf44e"}, - {file = "pydantic_core-2.27.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b872c86d8d71827235c7077461c502feb2db3f87d9d6d5a9daa64287d75e4fa0"}, - {file = "pydantic_core-2.27.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:82e1ad4ca170e8af4c928b67cff731b6296e6a0a0981b97b2eb7c275cc4e15bd"}, - {file = "pydantic_core-2.27.0-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:eb40f828bc2f73f777d1eb8fee2e86cd9692a4518b63b6b5aa8af915dfd3207b"}, - {file = "pydantic_core-2.27.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9a8fbf506fde1529a1e3698198fe64bfbe2e0c09557bc6a7dcf872e7c01fec40"}, - {file = "pydantic_core-2.27.0-cp311-none-win32.whl", hash = "sha256:24f984fc7762ed5f806d9e8c4c77ea69fdb2afd987b4fd319ef06c87595a8c55"}, - {file = "pydantic_core-2.27.0-cp311-none-win_amd64.whl", hash = "sha256:68950bc08f9735306322bfc16a18391fcaac99ded2509e1cc41d03ccb6013cfe"}, - {file = "pydantic_core-2.27.0-cp311-none-win_arm64.whl", hash = "sha256:3eb8849445c26b41c5a474061032c53e14fe92a11a5db969f722a2716cd12206"}, - {file = "pydantic_core-2.27.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:8117839a9bdbba86e7f9df57018fe3b96cec934c3940b591b0fd3fbfb485864a"}, - {file = "pydantic_core-2.27.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a291d0b4243a259c8ea7e2b84eb9ccb76370e569298875a7c5e3e71baf49057a"}, - {file = "pydantic_core-2.27.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:84e35afd9e10b2698e6f2f32256678cb23ca6c1568d02628033a837638b3ed12"}, - {file = "pydantic_core-2.27.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:58ab0d979c969983cdb97374698d847a4acffb217d543e172838864636ef10d9"}, - {file = "pydantic_core-2.27.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0d06b667e53320332be2bf6f9461f4a9b78092a079b8ce8634c9afaa7e10cd9f"}, - {file = "pydantic_core-2.27.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:78f841523729e43e3928a364ec46e2e3f80e6625a4f62aca5c345f3f626c6e8a"}, - {file = "pydantic_core-2.27.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:400bf470e4327e920883b51e255617dfe4496d4e80c3fea0b5a5d0bf2c404dd4"}, - {file = "pydantic_core-2.27.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:951e71da6c89d354572098bada5ba5b5dc3a9390c933af8a614e37755d3d1840"}, - {file = "pydantic_core-2.27.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:2a51ce96224eadd1845150b204389623c8e129fde5a67a84b972bd83a85c6c40"}, - {file = "pydantic_core-2.27.0-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:483c2213a609e7db2c592bbc015da58b6c75af7360ca3c981f178110d9787bcf"}, - {file = "pydantic_core-2.27.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:359e7951f04ad35111b5ddce184db3391442345d0ab073aa63a95eb8af25a5ef"}, - {file = "pydantic_core-2.27.0-cp312-none-win32.whl", hash = "sha256:ee7d9d5537daf6d5c74a83b38a638cc001b648096c1cae8ef695b0c919d9d379"}, - {file = "pydantic_core-2.27.0-cp312-none-win_amd64.whl", hash = "sha256:2be0ad541bb9f059954ccf8877a49ed73877f862529575ff3d54bf4223e4dd61"}, - {file = "pydantic_core-2.27.0-cp312-none-win_arm64.whl", hash = "sha256:6e19401742ed7b69e51d8e4df3c03ad5ec65a83b36244479fd70edde2828a5d9"}, - {file = "pydantic_core-2.27.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:5f2b19b8d6fca432cb3acf48cf5243a7bf512988029b6e6fd27e9e8c0a204d85"}, - {file = "pydantic_core-2.27.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:c86679f443e7085ea55a7376462553996c688395d18ef3f0d3dbad7838f857a2"}, - {file = "pydantic_core-2.27.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:510b11e9c3b1a852876d1ccd8d5903684336d635214148637ceb27366c75a467"}, - {file = "pydantic_core-2.27.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eb704155e73b833801c247f39d562229c0303f54770ca14fb1c053acb376cf10"}, - {file = "pydantic_core-2.27.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9ce048deb1e033e7a865ca384770bccc11d44179cf09e5193a535c4c2f497bdc"}, - {file = "pydantic_core-2.27.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:58560828ee0951bb125c6f2862fbc37f039996d19ceb6d8ff1905abf7da0bf3d"}, - {file = "pydantic_core-2.27.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:abb4785894936d7682635726613c44578c420a096729f1978cd061a7e72d5275"}, - {file = "pydantic_core-2.27.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2883b260f7a93235488699d39cbbd94fa7b175d3a8063fbfddd3e81ad9988cb2"}, - {file = "pydantic_core-2.27.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:c6fcb3fa3855d583aa57b94cf146f7781d5d5bc06cb95cb3afece33d31aac39b"}, - {file = "pydantic_core-2.27.0-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:e851a051f7260e6d688267eb039c81f05f23a19431bd7dfa4bf5e3cb34c108cd"}, - {file = "pydantic_core-2.27.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:edb1bfd45227dec8d50bc7c7d86463cd8728bcc574f9b07de7369880de4626a3"}, - {file = "pydantic_core-2.27.0-cp313-none-win32.whl", hash = "sha256:678f66462058dd978702db17eb6a3633d634f7aa0deaea61e0a674152766d3fc"}, - {file = "pydantic_core-2.27.0-cp313-none-win_amd64.whl", hash = "sha256:d28ca7066d6cdd347a50d8b725dc10d9a1d6a1cce09836cf071ea6a2d4908be0"}, - {file = "pydantic_core-2.27.0-cp313-none-win_arm64.whl", hash = "sha256:6f4a53af9e81d757756508b57cae1cf28293f0f31b9fa2bfcb416cc7fb230f9d"}, - {file = "pydantic_core-2.27.0-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:e9f9feee7f334b72ceae46313333d002b56f325b5f04271b4ae2aadd9e993ae4"}, - {file = "pydantic_core-2.27.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:225bfff5d425c34e1fd562cef52d673579d59b967d9de06178850c4802af9039"}, - {file = "pydantic_core-2.27.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c921ad596ff1a82f9c692b0758c944355abc9f0de97a4c13ca60ffc6d8dc15d4"}, - {file = "pydantic_core-2.27.0-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6354e18a9be37bfa124d6b288a87fb30c673745806c92956f1a25e3ae6e76b96"}, - {file = "pydantic_core-2.27.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8ee4c2a75af9fe21269a4a0898c5425afb01af1f5d276063f57e2ae1bc64e191"}, - {file = "pydantic_core-2.27.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c91e3c04f5191fd3fb68764bddeaf02025492d5d9f23343b283870f6ace69708"}, - {file = "pydantic_core-2.27.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a6ebfac28fd51890a61df36ef202adbd77d00ee5aca4a3dadb3d9ed49cfb929"}, - {file = "pydantic_core-2.27.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:36aa167f69d8807ba7e341d67ea93e50fcaaf6bc433bb04939430fa3dab06f31"}, - {file = "pydantic_core-2.27.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:3e8d89c276234579cd3d095d5fa2a44eb10db9a218664a17b56363cddf226ff3"}, - {file = "pydantic_core-2.27.0-cp38-cp38-musllinux_1_1_armv7l.whl", hash = "sha256:5cc822ab90a70ea3a91e6aed3afac570b276b1278c6909b1d384f745bd09c714"}, - {file = "pydantic_core-2.27.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:e15315691fe2253eb447503153acef4d7223dfe7e7702f9ed66539fcd0c43801"}, - {file = "pydantic_core-2.27.0-cp38-none-win32.whl", hash = "sha256:dfa5f5c0a4c8fced1422dc2ca7eefd872d5d13eb33cf324361dbf1dbfba0a9fe"}, - {file = "pydantic_core-2.27.0-cp38-none-win_amd64.whl", hash = "sha256:513cb14c0cc31a4dfd849a4674b20c46d87b364f997bbcb02282306f5e187abf"}, - {file = "pydantic_core-2.27.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:4148dc9184ab79e356dc00a4199dc0ee8647973332cb385fc29a7cced49b9f9c"}, - {file = "pydantic_core-2.27.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5fc72fbfebbf42c0856a824b8b0dc2b5cd2e4a896050281a21cfa6fed8879cb1"}, - {file = "pydantic_core-2.27.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:185ef205256cd8b38431205698531026979db89a79587725c1e55c59101d64e9"}, - {file = "pydantic_core-2.27.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:395e3e1148fa7809016231f8065f30bb0dc285a97b4dc4360cd86e17bab58af7"}, - {file = "pydantic_core-2.27.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:33d14369739c5d07e2e7102cdb0081a1fa46ed03215e07f097b34e020b83b1ae"}, - {file = "pydantic_core-2.27.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e7820bb0d65e3ce1e3e70b6708c2f66143f55912fa02f4b618d0f08b61575f12"}, - {file = "pydantic_core-2.27.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:43b61989068de9ce62296cde02beffabcadb65672207fc51e7af76dca75e6636"}, - {file = "pydantic_core-2.27.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:15e350efb67b855cd014c218716feea4986a149ed1f42a539edd271ee074a196"}, - {file = "pydantic_core-2.27.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:433689845288f9a1ee5714444e65957be26d30915f7745091ede4a83cfb2d7bb"}, - {file = "pydantic_core-2.27.0-cp39-cp39-musllinux_1_1_armv7l.whl", hash = "sha256:3fd8bc2690e7c39eecdf9071b6a889ce7b22b72073863940edc2a0a23750ca90"}, - {file = "pydantic_core-2.27.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:884f1806609c2c66564082540cffc96868c5571c7c3cf3a783f63f2fb49bd3cd"}, - {file = "pydantic_core-2.27.0-cp39-none-win32.whl", hash = "sha256:bf37b72834e7239cf84d4a0b2c050e7f9e48bced97bad9bdf98d26b8eb72e846"}, - {file = "pydantic_core-2.27.0-cp39-none-win_amd64.whl", hash = "sha256:31a2cae5f059329f9cfe3d8d266d3da1543b60b60130d186d9b6a3c20a346361"}, - {file = "pydantic_core-2.27.0-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:4fb49cfdb53af5041aba909be00cccfb2c0d0a2e09281bf542371c5fd36ad04c"}, - {file = "pydantic_core-2.27.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:49633583eb7dc5cba61aaf7cdb2e9e662323ad394e543ee77af265736bcd3eaa"}, - {file = "pydantic_core-2.27.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:153017e3d6cd3ce979de06d84343ca424bb6092727375eba1968c8b4693c6ecb"}, - {file = "pydantic_core-2.27.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ff63a92f6e249514ef35bc795de10745be0226eaea06eb48b4bbeaa0c8850a4a"}, - {file = "pydantic_core-2.27.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5982048129f40b082c2654de10c0f37c67a14f5ff9d37cf35be028ae982f26df"}, - {file = "pydantic_core-2.27.0-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:91bc66f878557313c2a6bcf396e7befcffe5ab4354cfe4427318968af31143c3"}, - {file = "pydantic_core-2.27.0-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:68ef5377eb582fa4343c9d0b57a5b094046d447b4c73dd9fbd9ffb216f829e7d"}, - {file = "pydantic_core-2.27.0-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:c5726eec789ee38f2c53b10b1821457b82274f81f4f746bb1e666d8741fcfadb"}, - {file = "pydantic_core-2.27.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:c0c431e4be5c1a0c6654e0c31c661cd89e0ca956ef65305c3c3fd96f4e72ca39"}, - {file = "pydantic_core-2.27.0-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:8e21d927469d04b39386255bf00d0feedead16f6253dcc85e9e10ddebc334084"}, - {file = "pydantic_core-2.27.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:4b51f964fcbb02949fc546022e56cdb16cda457af485e9a3e8b78ac2ecf5d77e"}, - {file = "pydantic_core-2.27.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25a7fd4de38f7ff99a37e18fa0098c3140286451bc823d1746ba80cec5b433a1"}, - {file = "pydantic_core-2.27.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6fda87808429c520a002a85d6e7cdadbf58231d60e96260976c5b8f9a12a8e13"}, - {file = "pydantic_core-2.27.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8a150392102c402c538190730fda06f3bce654fc498865579a9f2c1d2b425833"}, - {file = "pydantic_core-2.27.0-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:c9ed88b398ba7e3bad7bd64d66cc01dcde9cfcb7ec629a6fd78a82fa0b559d78"}, - {file = "pydantic_core-2.27.0-pp39-pypy39_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:9fe94d9d2a2b4edd7a4b22adcd45814b1b59b03feb00e56deb2e89747aec7bfe"}, - {file = "pydantic_core-2.27.0-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:d8b5ee4ae9170e2775d495b81f414cc20268041c42571530513496ba61e94ba3"}, - {file = "pydantic_core-2.27.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:d29e235ce13c91902ef3efc3d883a677655b3908b1cbc73dee816e5e1f8f7739"}, - {file = "pydantic_core-2.27.0.tar.gz", hash = "sha256:f57783fbaf648205ac50ae7d646f27582fc706be3977e87c3c124e7a92407b10"}, + {file = "pydantic_core-2.27.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:71a5e35c75c021aaf400ac048dacc855f000bdfed91614b4a726f7432f1f3d6a"}, + {file = "pydantic_core-2.27.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f82d068a2d6ecfc6e054726080af69a6764a10015467d7d7b9f66d6ed5afa23b"}, + {file = "pydantic_core-2.27.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:121ceb0e822f79163dd4699e4c54f5ad38b157084d97b34de8b232bcaad70278"}, + {file = "pydantic_core-2.27.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4603137322c18eaf2e06a4495f426aa8d8388940f3c457e7548145011bb68e05"}, + {file = "pydantic_core-2.27.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a33cd6ad9017bbeaa9ed78a2e0752c5e250eafb9534f308e7a5f7849b0b1bfb4"}, + {file = "pydantic_core-2.27.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:15cc53a3179ba0fcefe1e3ae50beb2784dede4003ad2dfd24f81bba4b23a454f"}, + {file = "pydantic_core-2.27.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45d9c5eb9273aa50999ad6adc6be5e0ecea7e09dbd0d31bd0c65a55a2592ca08"}, + {file = "pydantic_core-2.27.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8bf7b66ce12a2ac52d16f776b31d16d91033150266eb796967a7e4621707e4f6"}, + {file = "pydantic_core-2.27.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:655d7dd86f26cb15ce8a431036f66ce0318648f8853d709b4167786ec2fa4807"}, + {file = "pydantic_core-2.27.1-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:5556470f1a2157031e676f776c2bc20acd34c1990ca5f7e56f1ebf938b9ab57c"}, + {file = "pydantic_core-2.27.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f69ed81ab24d5a3bd93861c8c4436f54afdf8e8cc421562b0c7504cf3be58206"}, + {file = "pydantic_core-2.27.1-cp310-none-win32.whl", hash = "sha256:f5a823165e6d04ccea61a9f0576f345f8ce40ed533013580e087bd4d7442b52c"}, + {file = "pydantic_core-2.27.1-cp310-none-win_amd64.whl", hash = "sha256:57866a76e0b3823e0b56692d1a0bf722bffb324839bb5b7226a7dbd6c9a40b17"}, + {file = "pydantic_core-2.27.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:ac3b20653bdbe160febbea8aa6c079d3df19310d50ac314911ed8cc4eb7f8cb8"}, + {file = "pydantic_core-2.27.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a5a8e19d7c707c4cadb8c18f5f60c843052ae83c20fa7d44f41594c644a1d330"}, + {file = "pydantic_core-2.27.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7f7059ca8d64fea7f238994c97d91f75965216bcbe5f695bb44f354893f11d52"}, + {file = "pydantic_core-2.27.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bed0f8a0eeea9fb72937ba118f9db0cb7e90773462af7962d382445f3005e5a4"}, + {file = "pydantic_core-2.27.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a3cb37038123447cf0f3ea4c74751f6a9d7afef0eb71aa07bf5f652b5e6a132c"}, + {file = "pydantic_core-2.27.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:84286494f6c5d05243456e04223d5a9417d7f443c3b76065e75001beb26f88de"}, + {file = "pydantic_core-2.27.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:acc07b2cfc5b835444b44a9956846b578d27beeacd4b52e45489e93276241025"}, + {file = "pydantic_core-2.27.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4fefee876e07a6e9aad7a8c8c9f85b0cdbe7df52b8a9552307b09050f7512c7e"}, + {file = "pydantic_core-2.27.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:258c57abf1188926c774a4c94dd29237e77eda19462e5bb901d88adcab6af919"}, + {file = "pydantic_core-2.27.1-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:35c14ac45fcfdf7167ca76cc80b2001205a8d5d16d80524e13508371fb8cdd9c"}, + {file = "pydantic_core-2.27.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d1b26e1dff225c31897696cab7d4f0a315d4c0d9e8666dbffdb28216f3b17fdc"}, + {file = "pydantic_core-2.27.1-cp311-none-win32.whl", hash = "sha256:2cdf7d86886bc6982354862204ae3b2f7f96f21a3eb0ba5ca0ac42c7b38598b9"}, + {file = "pydantic_core-2.27.1-cp311-none-win_amd64.whl", hash = "sha256:3af385b0cee8df3746c3f406f38bcbfdc9041b5c2d5ce3e5fc6637256e60bbc5"}, + {file = "pydantic_core-2.27.1-cp311-none-win_arm64.whl", hash = "sha256:81f2ec23ddc1b476ff96563f2e8d723830b06dceae348ce02914a37cb4e74b89"}, + {file = "pydantic_core-2.27.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:9cbd94fc661d2bab2bc702cddd2d3370bbdcc4cd0f8f57488a81bcce90c7a54f"}, + {file = "pydantic_core-2.27.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5f8c4718cd44ec1580e180cb739713ecda2bdee1341084c1467802a417fe0f02"}, + {file = "pydantic_core-2.27.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:15aae984e46de8d376df515f00450d1522077254ef6b7ce189b38ecee7c9677c"}, + {file = "pydantic_core-2.27.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1ba5e3963344ff25fc8c40da90f44b0afca8cfd89d12964feb79ac1411a260ac"}, + {file = "pydantic_core-2.27.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:992cea5f4f3b29d6b4f7f1726ed8ee46c8331c6b4eed6db5b40134c6fe1768bb"}, + {file = "pydantic_core-2.27.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0325336f348dbee6550d129b1627cb8f5351a9dc91aad141ffb96d4937bd9529"}, + {file = "pydantic_core-2.27.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7597c07fbd11515f654d6ece3d0e4e5093edc30a436c63142d9a4b8e22f19c35"}, + {file = "pydantic_core-2.27.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3bbd5d8cc692616d5ef6fbbbd50dbec142c7e6ad9beb66b78a96e9c16729b089"}, + {file = "pydantic_core-2.27.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:dc61505e73298a84a2f317255fcc72b710b72980f3a1f670447a21efc88f8381"}, + {file = "pydantic_core-2.27.1-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:e1f735dc43da318cad19b4173dd1ffce1d84aafd6c9b782b3abc04a0d5a6f5bb"}, + {file = "pydantic_core-2.27.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:f4e5658dbffe8843a0f12366a4c2d1c316dbe09bb4dfbdc9d2d9cd6031de8aae"}, + {file = "pydantic_core-2.27.1-cp312-none-win32.whl", hash = "sha256:672ebbe820bb37988c4d136eca2652ee114992d5d41c7e4858cdd90ea94ffe5c"}, + {file = "pydantic_core-2.27.1-cp312-none-win_amd64.whl", hash = "sha256:66ff044fd0bb1768688aecbe28b6190f6e799349221fb0de0e6f4048eca14c16"}, + {file = "pydantic_core-2.27.1-cp312-none-win_arm64.whl", hash = "sha256:9a3b0793b1bbfd4146304e23d90045f2a9b5fd5823aa682665fbdaf2a6c28f3e"}, + {file = "pydantic_core-2.27.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:f216dbce0e60e4d03e0c4353c7023b202d95cbaeff12e5fd2e82ea0a66905073"}, + {file = "pydantic_core-2.27.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a2e02889071850bbfd36b56fd6bc98945e23670773bc7a76657e90e6b6603c08"}, + {file = "pydantic_core-2.27.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42b0e23f119b2b456d07ca91b307ae167cc3f6c846a7b169fca5326e32fdc6cf"}, + {file = "pydantic_core-2.27.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:764be71193f87d460a03f1f7385a82e226639732214b402f9aa61f0d025f0737"}, + {file = "pydantic_core-2.27.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1c00666a3bd2f84920a4e94434f5974d7bbc57e461318d6bb34ce9cdbbc1f6b2"}, + {file = "pydantic_core-2.27.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3ccaa88b24eebc0f849ce0a4d09e8a408ec5a94afff395eb69baf868f5183107"}, + {file = "pydantic_core-2.27.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c65af9088ac534313e1963443d0ec360bb2b9cba6c2909478d22c2e363d98a51"}, + {file = "pydantic_core-2.27.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:206b5cf6f0c513baffaeae7bd817717140770c74528f3e4c3e1cec7871ddd61a"}, + {file = "pydantic_core-2.27.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:062f60e512fc7fff8b8a9d680ff0ddaaef0193dba9fa83e679c0c5f5fbd018bc"}, + {file = "pydantic_core-2.27.1-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:a0697803ed7d4af5e4c1adf1670af078f8fcab7a86350e969f454daf598c4960"}, + {file = "pydantic_core-2.27.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:58ca98a950171f3151c603aeea9303ef6c235f692fe555e883591103da709b23"}, + {file = "pydantic_core-2.27.1-cp313-none-win32.whl", hash = "sha256:8065914ff79f7eab1599bd80406681f0ad08f8e47c880f17b416c9f8f7a26d05"}, + {file = "pydantic_core-2.27.1-cp313-none-win_amd64.whl", hash = "sha256:ba630d5e3db74c79300d9a5bdaaf6200172b107f263c98a0539eeecb857b2337"}, + {file = "pydantic_core-2.27.1-cp313-none-win_arm64.whl", hash = "sha256:45cf8588c066860b623cd11c4ba687f8d7175d5f7ef65f7129df8a394c502de5"}, + {file = "pydantic_core-2.27.1-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:5897bec80a09b4084aee23f9b73a9477a46c3304ad1d2d07acca19723fb1de62"}, + {file = "pydantic_core-2.27.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:d0165ab2914379bd56908c02294ed8405c252250668ebcb438a55494c69f44ab"}, + {file = "pydantic_core-2.27.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b9af86e1d8e4cfc82c2022bfaa6f459381a50b94a29e95dcdda8442d6d83864"}, + {file = "pydantic_core-2.27.1-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5f6c8a66741c5f5447e047ab0ba7a1c61d1e95580d64bce852e3df1f895c4067"}, + {file = "pydantic_core-2.27.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9a42d6a8156ff78981f8aa56eb6394114e0dedb217cf8b729f438f643608cbcd"}, + {file = "pydantic_core-2.27.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:64c65f40b4cd8b0e049a8edde07e38b476da7e3aaebe63287c899d2cff253fa5"}, + {file = "pydantic_core-2.27.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fdcf339322a3fae5cbd504edcefddd5a50d9ee00d968696846f089b4432cf78"}, + {file = "pydantic_core-2.27.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bf99c8404f008750c846cb4ac4667b798a9f7de673ff719d705d9b2d6de49c5f"}, + {file = "pydantic_core-2.27.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:8f1edcea27918d748c7e5e4d917297b2a0ab80cad10f86631e488b7cddf76a36"}, + {file = "pydantic_core-2.27.1-cp38-cp38-musllinux_1_1_armv7l.whl", hash = "sha256:159cac0a3d096f79ab6a44d77a961917219707e2a130739c64d4dd46281f5c2a"}, + {file = "pydantic_core-2.27.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:029d9757eb621cc6e1848fa0b0310310de7301057f623985698ed7ebb014391b"}, + {file = "pydantic_core-2.27.1-cp38-none-win32.whl", hash = "sha256:a28af0695a45f7060e6f9b7092558a928a28553366519f64083c63a44f70e618"}, + {file = "pydantic_core-2.27.1-cp38-none-win_amd64.whl", hash = "sha256:2d4567c850905d5eaaed2f7a404e61012a51caf288292e016360aa2b96ff38d4"}, + {file = "pydantic_core-2.27.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:e9386266798d64eeb19dd3677051f5705bf873e98e15897ddb7d76f477131967"}, + {file = "pydantic_core-2.27.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4228b5b646caa73f119b1ae756216b59cc6e2267201c27d3912b592c5e323b60"}, + {file = "pydantic_core-2.27.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0b3dfe500de26c52abe0477dde16192ac39c98f05bf2d80e76102d394bd13854"}, + {file = "pydantic_core-2.27.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:aee66be87825cdf72ac64cb03ad4c15ffef4143dbf5c113f64a5ff4f81477bf9"}, + {file = "pydantic_core-2.27.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b748c44bb9f53031c8cbc99a8a061bc181c1000c60a30f55393b6e9c45cc5bd"}, + {file = "pydantic_core-2.27.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ca038c7f6a0afd0b2448941b6ef9d5e1949e999f9e5517692eb6da58e9d44be"}, + {file = "pydantic_core-2.27.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e0bd57539da59a3e4671b90a502da9a28c72322a4f17866ba3ac63a82c4498e"}, + {file = "pydantic_core-2.27.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ac6c2c45c847bbf8f91930d88716a0fb924b51e0c6dad329b793d670ec5db792"}, + {file = "pydantic_core-2.27.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b94d4ba43739bbe8b0ce4262bcc3b7b9f31459ad120fb595627eaeb7f9b9ca01"}, + {file = "pydantic_core-2.27.1-cp39-cp39-musllinux_1_1_armv7l.whl", hash = "sha256:00e6424f4b26fe82d44577b4c842d7df97c20be6439e8e685d0d715feceb9fb9"}, + {file = "pydantic_core-2.27.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:38de0a70160dd97540335b7ad3a74571b24f1dc3ed33f815f0880682e6880131"}, + {file = "pydantic_core-2.27.1-cp39-none-win32.whl", hash = "sha256:7ccebf51efc61634f6c2344da73e366c75e735960b5654b63d7e6f69a5885fa3"}, + {file = "pydantic_core-2.27.1-cp39-none-win_amd64.whl", hash = "sha256:a57847b090d7892f123726202b7daa20df6694cbd583b67a592e856bff603d6c"}, + {file = "pydantic_core-2.27.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:3fa80ac2bd5856580e242dbc202db873c60a01b20309c8319b5c5986fbe53ce6"}, + {file = "pydantic_core-2.27.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:d950caa237bb1954f1b8c9227b5065ba6875ac9771bb8ec790d956a699b78676"}, + {file = "pydantic_core-2.27.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e4216e64d203e39c62df627aa882f02a2438d18a5f21d7f721621f7a5d3611d"}, + {file = "pydantic_core-2.27.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:02a3d637bd387c41d46b002f0e49c52642281edacd2740e5a42f7017feea3f2c"}, + {file = "pydantic_core-2.27.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:161c27ccce13b6b0c8689418da3885d3220ed2eae2ea5e9b2f7f3d48f1d52c27"}, + {file = "pydantic_core-2.27.1-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:19910754e4cc9c63bc1c7f6d73aa1cfee82f42007e407c0f413695c2f7ed777f"}, + {file = "pydantic_core-2.27.1-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:e173486019cc283dc9778315fa29a363579372fe67045e971e89b6365cc035ed"}, + {file = "pydantic_core-2.27.1-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:af52d26579b308921b73b956153066481f064875140ccd1dfd4e77db89dbb12f"}, + {file = "pydantic_core-2.27.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:981fb88516bd1ae8b0cbbd2034678a39dedc98752f264ac9bc5839d3923fa04c"}, + {file = "pydantic_core-2.27.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5fde892e6c697ce3e30c61b239330fc5d569a71fefd4eb6512fc6caec9dd9e2f"}, + {file = "pydantic_core-2.27.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:816f5aa087094099fff7edabb5e01cc370eb21aa1a1d44fe2d2aefdfb5599b31"}, + {file = "pydantic_core-2.27.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9c10c309e18e443ddb108f0ef64e8729363adbfd92d6d57beec680f6261556f3"}, + {file = "pydantic_core-2.27.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98476c98b02c8e9b2eec76ac4156fd006628b1b2d0ef27e548ffa978393fd154"}, + {file = "pydantic_core-2.27.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c3027001c28434e7ca5a6e1e527487051136aa81803ac812be51802150d880dd"}, + {file = "pydantic_core-2.27.1-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:7699b1df36a48169cdebda7ab5a2bac265204003f153b4bd17276153d997670a"}, + {file = "pydantic_core-2.27.1-pp39-pypy39_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:1c39b07d90be6b48968ddc8c19e7585052088fd7ec8d568bb31ff64c70ae3c97"}, + {file = "pydantic_core-2.27.1-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:46ccfe3032b3915586e469d4972973f893c0a2bb65669194a5bdea9bacc088c2"}, + {file = "pydantic_core-2.27.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:62ba45e21cf6571d7f716d903b5b7b6d2617e2d5d67c0923dc47b9d41369f840"}, + {file = "pydantic_core-2.27.1.tar.gz", hash = "sha256:62a763352879b84aa31058fc931884055fd75089cccbd9d58bb6afd01141b235"}, ] [package.dependencies] @@ -689,13 +709,13 @@ typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" [[package]] name = "pytest" -version = "8.3.3" +version = "8.3.4" description = "pytest: simple powerful testing with Python" optional = false python-versions = ">=3.8" files = [ - {file = "pytest-8.3.3-py3-none-any.whl", hash = "sha256:a6853c7375b2663155079443d2e45de913a911a11d669df02a50814944db57b2"}, - {file = "pytest-8.3.3.tar.gz", hash = "sha256:70b98107bd648308a7952b06e6ca9a50bc660be218d53c257cc1fc94fda10181"}, + {file = "pytest-8.3.4-py3-none-any.whl", hash = "sha256:50e16d954148559c9a74109af1eaf0c945ba2d8f30f0a3d3335edde19788b6f6"}, + {file = "pytest-8.3.4.tar.gz", hash = "sha256:965370d062bce11e73868e0335abac31b4d3de0e82f4007408d242b4f8610761"}, ] [package.dependencies] @@ -826,29 +846,29 @@ requests = ">=2.0.1,<3.0.0" [[package]] name = "ruff" -version = "0.7.4" +version = "0.8.1" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" files = [ - {file = "ruff-0.7.4-py3-none-linux_armv6l.whl", hash = "sha256:a4919925e7684a3f18e18243cd6bea7cfb8e968a6eaa8437971f681b7ec51478"}, - {file = "ruff-0.7.4-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:cfb365c135b830778dda8c04fb7d4280ed0b984e1aec27f574445231e20d6c63"}, - {file = "ruff-0.7.4-py3-none-macosx_11_0_arm64.whl", hash = "sha256:63a569b36bc66fbadec5beaa539dd81e0527cb258b94e29e0531ce41bacc1f20"}, - {file = "ruff-0.7.4-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0d06218747d361d06fd2fdac734e7fa92df36df93035db3dc2ad7aa9852cb109"}, - {file = "ruff-0.7.4-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e0cea28d0944f74ebc33e9f934238f15c758841f9f5edd180b5315c203293452"}, - {file = "ruff-0.7.4-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:80094ecd4793c68b2571b128f91754d60f692d64bc0d7272ec9197fdd09bf9ea"}, - {file = "ruff-0.7.4-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:997512325c6620d1c4c2b15db49ef59543ef9cd0f4aa8065ec2ae5103cedc7e7"}, - {file = "ruff-0.7.4-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:00b4cf3a6b5fad6d1a66e7574d78956bbd09abfd6c8a997798f01f5da3d46a05"}, - {file = "ruff-0.7.4-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7dbdc7d8274e1422722933d1edddfdc65b4336abf0b16dfcb9dedd6e6a517d06"}, - {file = "ruff-0.7.4-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e92dfb5f00eaedb1501b2f906ccabfd67b2355bdf117fea9719fc99ac2145bc"}, - {file = "ruff-0.7.4-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:3bd726099f277d735dc38900b6a8d6cf070f80828877941983a57bca1cd92172"}, - {file = "ruff-0.7.4-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:2e32829c429dd081ee5ba39aef436603e5b22335c3d3fff013cd585806a6486a"}, - {file = "ruff-0.7.4-py3-none-musllinux_1_2_i686.whl", hash = "sha256:662a63b4971807623f6f90c1fb664613f67cc182dc4d991471c23c541fee62dd"}, - {file = "ruff-0.7.4-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:876f5e09eaae3eb76814c1d3b68879891d6fde4824c015d48e7a7da4cf066a3a"}, - {file = "ruff-0.7.4-py3-none-win32.whl", hash = "sha256:75c53f54904be42dd52a548728a5b572344b50d9b2873d13a3f8c5e3b91f5cac"}, - {file = "ruff-0.7.4-py3-none-win_amd64.whl", hash = "sha256:745775c7b39f914238ed1f1b0bebed0b9155a17cd8bc0b08d3c87e4703b990d6"}, - {file = "ruff-0.7.4-py3-none-win_arm64.whl", hash = "sha256:11bff065102c3ae9d3ea4dc9ecdfe5a5171349cdd0787c1fc64761212fc9cf1f"}, - {file = "ruff-0.7.4.tar.gz", hash = "sha256:cd12e35031f5af6b9b93715d8c4f40360070b2041f81273d0527683d5708fce2"}, + {file = "ruff-0.8.1-py3-none-linux_armv6l.whl", hash = "sha256:fae0805bd514066f20309f6742f6ee7904a773eb9e6c17c45d6b1600ca65c9b5"}, + {file = "ruff-0.8.1-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:b8a4f7385c2285c30f34b200ca5511fcc865f17578383db154e098150ce0a087"}, + {file = "ruff-0.8.1-py3-none-macosx_11_0_arm64.whl", hash = "sha256:cd054486da0c53e41e0086e1730eb77d1f698154f910e0cd9e0d64274979a209"}, + {file = "ruff-0.8.1-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2029b8c22da147c50ae577e621a5bfbc5d1fed75d86af53643d7a7aee1d23871"}, + {file = "ruff-0.8.1-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2666520828dee7dfc7e47ee4ea0d928f40de72056d929a7c5292d95071d881d1"}, + {file = "ruff-0.8.1-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:333c57013ef8c97a53892aa56042831c372e0bb1785ab7026187b7abd0135ad5"}, + {file = "ruff-0.8.1-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:288326162804f34088ac007139488dcb43de590a5ccfec3166396530b58fb89d"}, + {file = "ruff-0.8.1-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b12c39b9448632284561cbf4191aa1b005882acbc81900ffa9f9f471c8ff7e26"}, + {file = "ruff-0.8.1-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:364e6674450cbac8e998f7b30639040c99d81dfb5bbc6dfad69bc7a8f916b3d1"}, + {file = "ruff-0.8.1-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b22346f845fec132aa39cd29acb94451d030c10874408dbf776af3aaeb53284c"}, + {file = "ruff-0.8.1-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:b2f2f7a7e7648a2bfe6ead4e0a16745db956da0e3a231ad443d2a66a105c04fa"}, + {file = "ruff-0.8.1-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:adf314fc458374c25c5c4a4a9270c3e8a6a807b1bec018cfa2813d6546215540"}, + {file = "ruff-0.8.1-py3-none-musllinux_1_2_i686.whl", hash = "sha256:a885d68342a231b5ba4d30b8c6e1b1ee3a65cf37e3d29b3c74069cdf1ee1e3c9"}, + {file = "ruff-0.8.1-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:d2c16e3508c8cc73e96aa5127d0df8913d2290098f776416a4b157657bee44c5"}, + {file = "ruff-0.8.1-py3-none-win32.whl", hash = "sha256:93335cd7c0eaedb44882d75a7acb7df4b77cd7cd0d2255c93b28791716e81790"}, + {file = "ruff-0.8.1-py3-none-win_amd64.whl", hash = "sha256:2954cdbe8dfd8ab359d4a30cd971b589d335a44d444b6ca2cb3d1da21b75e4b6"}, + {file = "ruff-0.8.1-py3-none-win_arm64.whl", hash = "sha256:55873cc1a473e5ac129d15eccb3c008c096b94809d693fc7053f588b67822737"}, + {file = "ruff-0.8.1.tar.gz", hash = "sha256:3583db9a6450364ed5ca3f3b4225958b24f78178908d5c4bc0f46251ccca898f"}, ] [[package]] @@ -864,13 +884,13 @@ files = [ [[package]] name = "syrupy" -version = "4.7.2" +version = "4.8.0" description = "Pytest Snapshot Test Utility" optional = false python-versions = ">=3.8.1" files = [ - {file = "syrupy-4.7.2-py3-none-any.whl", hash = "sha256:eae7ba6be5aed190237caa93be288e97ca1eec5ca58760e4818972a10c4acc64"}, - {file = "syrupy-4.7.2.tar.gz", hash = "sha256:ea45e099f242de1bb53018c238f408a5bb6c82007bc687aefcbeaa0e1c2e935a"}, + {file = "syrupy-4.8.0-py3-none-any.whl", hash = "sha256:544f4ec6306f4b1c460fdab48fd60b2c7fe54a6c0a8243aeea15f9ad9c638c3f"}, + {file = "syrupy-4.8.0.tar.gz", hash = "sha256:648f0e9303aaa8387c8365d7314784c09a6bab0a407455c6a01d6a4f5c6a8ede"}, ] [package.dependencies] @@ -893,13 +913,43 @@ test = ["pytest", "tornado (>=4.5)", "typeguard"] [[package]] name = "tomli" -version = "2.1.0" +version = "2.2.1" description = "A lil' TOML parser" optional = false python-versions = ">=3.8" files = [ - {file = "tomli-2.1.0-py3-none-any.whl", hash = "sha256:a5c57c3d1c56f5ccdf89f6523458f60ef716e210fc47c4cfb188c5ba473e0391"}, - {file = "tomli-2.1.0.tar.gz", hash = "sha256:3f646cae2aec94e17d04973e4249548320197cfabdf130015d023de4b74d8ab8"}, + {file = "tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249"}, + {file = "tomli-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6"}, + {file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a"}, + {file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee"}, + {file = "tomli-2.2.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e"}, + {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4"}, + {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106"}, + {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8"}, + {file = "tomli-2.2.1-cp311-cp311-win32.whl", hash = "sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff"}, + {file = "tomli-2.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b"}, + {file = "tomli-2.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea"}, + {file = "tomli-2.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8"}, + {file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192"}, + {file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222"}, + {file = "tomli-2.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77"}, + {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6"}, + {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd"}, + {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e"}, + {file = "tomli-2.2.1-cp312-cp312-win32.whl", hash = "sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98"}, + {file = "tomli-2.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4"}, + {file = "tomli-2.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7"}, + {file = "tomli-2.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c"}, + {file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13"}, + {file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281"}, + {file = "tomli-2.2.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272"}, + {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140"}, + {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2"}, + {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744"}, + {file = "tomli-2.2.1-cp313-cp313-win32.whl", hash = "sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec"}, + {file = "tomli-2.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69"}, + {file = "tomli-2.2.1-py3-none-any.whl", hash = "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc"}, + {file = "tomli-2.2.1.tar.gz", hash = "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff"}, ] [[package]] @@ -933,4 +983,4 @@ zstd = ["zstandard (>=0.18.0)"] [metadata] lock-version = "2.0" python-versions = ">=3.9,<4.0" -content-hash = "f92550d052b48eb60c41c6baa12c158391f7c1e5453b824ac212aa1e75260b1f" +content-hash = "71103f2fbdf0b2808eac7e7ffeeadb9e68502a06a4a9c40d8f4f698c8ddd22a9" diff --git a/libs/standard-tests/pyproject.toml b/libs/standard-tests/pyproject.toml index cb15fa49683..f9633ec0371 100644 --- a/libs/standard-tests/pyproject.toml +++ b/libs/standard-tests/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api" [tool.poetry] name = "langchain-tests" -version = "0.3.4" +version = "0.3.5" description = "Standard tests for LangChain implementations" authors = ["Erick Friis "] readme = "README.md" @@ -19,7 +19,7 @@ disallow_untyped_defs = "True" [tool.poetry.dependencies] python = ">=3.9,<4.0" -langchain-core = "^0.3.19" +langchain-core = "^0.3.21" pytest = ">=7,<9" httpx = "^0.27.0" syrupy = "^4" diff --git a/libs/standard-tests/tests/unit_tests/test_embeddings.py b/libs/standard-tests/tests/unit_tests/test_embeddings.py new file mode 100644 index 00000000000..d2a551decca --- /dev/null +++ b/libs/standard-tests/tests/unit_tests/test_embeddings.py @@ -0,0 +1,26 @@ +from typing import Type + +from langchain_core.embeddings import DeterministicFakeEmbedding, Embeddings + +from langchain_tests.integration_tests import EmbeddingsIntegrationTests +from langchain_tests.unit_tests import EmbeddingsUnitTests + + +class TestFakeEmbeddingsUnit(EmbeddingsUnitTests): + @property + def embeddings_class(self) -> Type[Embeddings]: + return DeterministicFakeEmbedding + + @property + def embedding_model_params(self) -> dict: + return {"size": 6} # embedding dimension + + +class TestFakeEmbeddingsIntegration(EmbeddingsIntegrationTests): + @property + def embeddings_class(self) -> Type[Embeddings]: + return DeterministicFakeEmbedding + + @property + def embedding_model_params(self) -> dict: + return {"size": 6} diff --git a/libs/text-splitters/README.md b/libs/text-splitters/README.md index 83d711b8ec0..fbbfc34f5d6 100644 --- a/libs/text-splitters/README.md +++ b/libs/text-splitters/README.md @@ -13,7 +13,7 @@ pip install langchain-text-splitters LangChain Text Splitters contains utilities for splitting into chunks a wide variety of text documents. -For full documentation see the [API reference](https://api.python.langchain.com/en/stable/text_splitters_api_reference.html) +For full documentation see the [API reference](https://python.langchain.com/api_reference/text_splitters/index.html) and the [Text Splitters](https://python.langchain.com/docs/modules/data_connection/document_transformers/) module in the main docs. ## 📕 Releases & Versioning