mirror of
https://github.com/hwchase17/langchain.git
synced 2026-02-08 02:00:06 +00:00
Compare commits
31 Commits
vb/test-na
...
migrate_uv
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d9d8735d9f | ||
|
|
fb4adb444d | ||
|
|
dd47b8c454 | ||
|
|
1c634f9436 | ||
|
|
e939cd462a | ||
|
|
bc24f60a39 | ||
|
|
7a8d5586de | ||
|
|
3898048b49 | ||
|
|
cfa56be510 | ||
|
|
fb79799571 | ||
|
|
d9ce5f4464 | ||
|
|
d6e2af40eb | ||
|
|
1a22baf999 | ||
|
|
e20603e225 | ||
|
|
c71fc8b58a | ||
|
|
1a4af623f1 | ||
|
|
dfce027c57 | ||
|
|
701387066c | ||
|
|
ea838e80c7 | ||
|
|
4dcc659f48 | ||
|
|
dcbedef4d8 | ||
|
|
070e12f886 | ||
|
|
aa7637b2e4 | ||
|
|
b7bdf0b81a | ||
|
|
e034999cb6 | ||
|
|
a1a6ef10a9 | ||
|
|
6693a0c80b | ||
|
|
4202c1411b | ||
|
|
10f677f2f7 | ||
|
|
f71cf387f0 | ||
|
|
b07e6be354 |
2
.github/actions/uv_setup/action.yml
vendored
2
.github/actions/uv_setup/action.yml
vendored
@@ -14,6 +14,8 @@ env:
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install uv and set the python version
|
||||
uses: astral-sh/setup-uv@v5
|
||||
with:
|
||||
|
||||
6
.github/scripts/check_diff.py
vendored
6
.github/scripts/check_diff.py
vendored
@@ -39,8 +39,6 @@ IGNORED_PARTNERS = [
|
||||
|
||||
PY_312_MAX_PACKAGES = [
|
||||
"libs/partners/huggingface", # https://github.com/pytorch/pytorch/issues/130249
|
||||
"libs/partners/pinecone",
|
||||
"libs/partners/voyageai",
|
||||
]
|
||||
|
||||
|
||||
@@ -59,7 +57,9 @@ def dependents_graph() -> dict:
|
||||
"""
|
||||
dependents = defaultdict(set)
|
||||
|
||||
for path in glob.glob("./libs/**/pyproject.toml", recursive=True):
|
||||
# for path in glob.glob("./libs/**/pyproject.toml", recursive=True):
|
||||
# TODO: fix this
|
||||
for path in ["./libs/langchain/pyproject.toml", "./libs/core/pyproject.toml"]:
|
||||
if "template" in path:
|
||||
continue
|
||||
|
||||
|
||||
11
.github/scripts/check_prerelease_dependencies.py
vendored
11
.github/scripts/check_prerelease_dependencies.py
vendored
@@ -10,25 +10,26 @@ if __name__ == "__main__":
|
||||
toml_data = tomllib.load(file)
|
||||
|
||||
# see if we're releasing an rc
|
||||
version = toml_data["project"]["version"]
|
||||
version = toml_data["tool"]["poetry"]["version"]
|
||||
releasing_rc = "rc" in version or "dev" in version
|
||||
|
||||
# if not, iterate through dependencies and make sure none allow prereleases
|
||||
if not releasing_rc:
|
||||
dependencies = toml_data["project"]["dependencies"]
|
||||
for dep_version in dependencies:
|
||||
dependencies = toml_data["tool"]["poetry"]["dependencies"]
|
||||
for lib in dependencies:
|
||||
dep_version = dependencies[lib]
|
||||
dep_version_string = (
|
||||
dep_version["version"] if isinstance(dep_version, dict) else dep_version
|
||||
)
|
||||
|
||||
if "rc" in dep_version_string:
|
||||
raise ValueError(
|
||||
f"Dependency {dep_version} has a prerelease version. Please remove this."
|
||||
f"Dependency {lib} has a prerelease version. Please remove this."
|
||||
)
|
||||
|
||||
if isinstance(dep_version, dict) and dep_version.get(
|
||||
"allow-prereleases", False
|
||||
):
|
||||
raise ValueError(
|
||||
f"Dependency {dep_version} has allow-prereleases set to true. Please remove this."
|
||||
f"Dependency {lib} has allow-prereleases set to true. Please remove this."
|
||||
)
|
||||
|
||||
@@ -12,9 +12,6 @@ on:
|
||||
type: string
|
||||
description: "Python version to use"
|
||||
|
||||
env:
|
||||
UV_FROZEN: "true"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
defaults:
|
||||
|
||||
5
.github/workflows/_integration_test.yml
vendored
5
.github/workflows/_integration_test.yml
vendored
@@ -11,9 +11,6 @@ on:
|
||||
type: string
|
||||
description: "Python version to use"
|
||||
|
||||
env:
|
||||
UV_FROZEN: "true"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
defaults:
|
||||
@@ -36,7 +33,7 @@ jobs:
|
||||
- name: Install deps outside pyproject
|
||||
if: ${{ startsWith(inputs.working-directory, 'libs/community/') }}
|
||||
shell: bash
|
||||
run: VIRTUAL_ENV=.venv uv pip install "boto3<2" "google-cloud-aiplatform<2"
|
||||
run: uv pip install "boto3<2" "google-cloud-aiplatform<2"
|
||||
|
||||
- name: Run integration tests
|
||||
shell: bash
|
||||
|
||||
2
.github/workflows/_lint.yml
vendored
2
.github/workflows/_lint.yml
vendored
@@ -18,8 +18,6 @@ env:
|
||||
# This env var allows us to get inline annotations when ruff has complaints.
|
||||
RUFF_OUTPUT_FORMAT: github
|
||||
|
||||
UV_FROZEN: "true"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: "make lint #${{ inputs.python-version }}"
|
||||
|
||||
10
.github/workflows/_release.yml
vendored
10
.github/workflows/_release.yml
vendored
@@ -21,7 +21,6 @@ on:
|
||||
|
||||
env:
|
||||
PYTHON_VERSION: "3.11"
|
||||
UV_FROZEN: "true"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
@@ -216,7 +215,7 @@ jobs:
|
||||
# sometimes a delay in availability on test pypi
|
||||
run: |
|
||||
uv venv
|
||||
VIRTUAL_ENV=.venv uv pip install dist/*.whl
|
||||
uv 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.
|
||||
@@ -237,7 +236,7 @@ jobs:
|
||||
PKG_NAME: ${{ needs.build.outputs.pkg-name }}
|
||||
VERSION: ${{ needs.build.outputs.version }}
|
||||
run: |
|
||||
VIRTUAL_ENV=.venv uv pip install dist/*.whl
|
||||
uv run pip install dist/*.whl
|
||||
|
||||
- name: Run unit tests
|
||||
run: make tests
|
||||
@@ -252,7 +251,7 @@ jobs:
|
||||
working-directory: ${{ inputs.working-directory }}
|
||||
id: min-version
|
||||
run: |
|
||||
VIRTUAL_ENV=.venv uv pip install packaging requests
|
||||
uv run pip install packaging requests
|
||||
python_version="$(uv run python --version | awk '{print $2}')"
|
||||
min_versions="$(uv run python $GITHUB_WORKSPACE/.github/scripts/get_min_versions.py pyproject.toml release $python_version)"
|
||||
echo "min-versions=$min_versions" >> "$GITHUB_OUTPUT"
|
||||
@@ -263,7 +262,7 @@ jobs:
|
||||
env:
|
||||
MIN_VERSIONS: ${{ steps.min-version.outputs.min-versions }}
|
||||
run: |
|
||||
VIRTUAL_ENV=.venv uv pip install --force-reinstall $MIN_VERSIONS --editable .
|
||||
uv run pip install --force-reinstall $MIN_VERSIONS --editable .
|
||||
make tests
|
||||
working-directory: ${{ inputs.working-directory }}
|
||||
|
||||
@@ -309,7 +308,6 @@ jobs:
|
||||
UPSTAGE_API_KEY: ${{ secrets.UPSTAGE_API_KEY }}
|
||||
FIREWORKS_API_KEY: ${{ secrets.FIREWORKS_API_KEY }}
|
||||
XAI_API_KEY: ${{ secrets.XAI_API_KEY }}
|
||||
DEEPSEEK_API_KEY: ${{ secrets.DEEPSEEK_API_KEY }}
|
||||
run: make integration_tests
|
||||
working-directory: ${{ inputs.working-directory }}
|
||||
|
||||
|
||||
7
.github/workflows/_test.yml
vendored
7
.github/workflows/_test.yml
vendored
@@ -12,9 +12,6 @@ on:
|
||||
type: string
|
||||
description: "Python version to use"
|
||||
|
||||
env:
|
||||
UV_FROZEN: "true"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
defaults:
|
||||
@@ -45,7 +42,7 @@ jobs:
|
||||
id: min-version
|
||||
shell: bash
|
||||
run: |
|
||||
VIRTUAL_ENV=.venv uv pip install packaging tomli requests
|
||||
uv run pip install packaging tomli requests
|
||||
python_version="$(uv run python --version | awk '{print $2}')"
|
||||
min_versions="$(uv run python $GITHUB_WORKSPACE/.github/scripts/get_min_versions.py pyproject.toml pull_request $python_version)"
|
||||
echo "min-versions=$min_versions" >> "$GITHUB_OUTPUT"
|
||||
@@ -56,7 +53,7 @@ jobs:
|
||||
env:
|
||||
MIN_VERSIONS: ${{ steps.min-version.outputs.min-versions }}
|
||||
run: |
|
||||
VIRTUAL_ENV=.venv uv pip install $MIN_VERSIONS
|
||||
uv run pip install $MIN_VERSIONS
|
||||
make tests
|
||||
working-directory: ${{ inputs.working-directory }}
|
||||
|
||||
|
||||
14
.github/workflows/_test_doc_imports.yml
vendored
14
.github/workflows/_test_doc_imports.yml
vendored
@@ -9,7 +9,7 @@ on:
|
||||
description: "Python version to use"
|
||||
|
||||
env:
|
||||
UV_FROZEN: "true"
|
||||
POETRY_VERSION: "1.8.4"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
@@ -19,23 +19,25 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Python ${{ inputs.python-version }} + uv
|
||||
uses: "./.github/actions/uv_setup"
|
||||
- name: Set up Python ${{ inputs.python-version }} + Poetry ${{ env.POETRY_VERSION }}
|
||||
uses: "./.github/actions/poetry_setup"
|
||||
with:
|
||||
python-version: ${{ inputs.python-version }}
|
||||
poetry-version: ${{ env.POETRY_VERSION }}
|
||||
cache-key: core
|
||||
|
||||
- name: Install dependencies
|
||||
shell: bash
|
||||
run: uv sync --group test
|
||||
run: poetry install --with test
|
||||
|
||||
- name: Install langchain editable
|
||||
run: |
|
||||
VIRTUAL_ENV=.venv uv pip install langchain-experimental -e libs/core libs/langchain libs/community
|
||||
poetry run pip install langchain-experimental -e libs/core libs/langchain libs/community
|
||||
|
||||
- name: Check doc imports
|
||||
shell: bash
|
||||
run: |
|
||||
uv run python docs/scripts/check_imports.py
|
||||
poetry run python docs/scripts/check_imports.py
|
||||
|
||||
- name: Ensure the test did not create any additional files
|
||||
shell: bash
|
||||
|
||||
5
.github/workflows/_test_pydantic.yml
vendored
5
.github/workflows/_test_pydantic.yml
vendored
@@ -17,9 +17,6 @@ on:
|
||||
type: string
|
||||
description: "Pydantic version to test."
|
||||
|
||||
env:
|
||||
UV_FROZEN: "true"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
defaults:
|
||||
@@ -42,7 +39,7 @@ jobs:
|
||||
|
||||
- name: Overwrite pydantic version
|
||||
shell: bash
|
||||
run: VIRTUAL_ENV=.venv uv pip install pydantic~=${{ inputs.pydantic-version }}
|
||||
run: uv pip install pydantic~=${{ inputs.pydantic-version }}
|
||||
|
||||
- name: Run core tests
|
||||
shell: bash
|
||||
|
||||
3
.github/workflows/_test_release.yml
vendored
3
.github/workflows/_test_release.yml
vendored
@@ -14,8 +14,7 @@ on:
|
||||
description: "Release from a non-master branch (danger!)"
|
||||
|
||||
env:
|
||||
PYTHON_VERSION: "3.11"
|
||||
UV_FROZEN: "true"
|
||||
PYTHON_VERSION: "3.10"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
11
.github/workflows/api_doc_build.yml
vendored
11
.github/workflows/api_doc_build.yml
vendored
@@ -5,6 +5,7 @@ on:
|
||||
schedule:
|
||||
- cron: '0 13 * * *'
|
||||
env:
|
||||
POETRY_VERSION: "1.8.4"
|
||||
PYTHON_VERSION: "3.11"
|
||||
|
||||
jobs:
|
||||
@@ -45,18 +46,20 @@ jobs:
|
||||
fi
|
||||
done
|
||||
|
||||
- name: Setup python ${{ env.PYTHON_VERSION }}
|
||||
uses: actions/setup-python@v5
|
||||
id: setup-python
|
||||
- name: Set up Python ${{ env.PYTHON_VERSION }} + Poetry ${{ env.POETRY_VERSION }}
|
||||
uses: "./langchain/.github/actions/poetry_setup"
|
||||
with:
|
||||
python-version: ${{ env.PYTHON_VERSION }}
|
||||
poetry-version: ${{ env.POETRY_VERSION }}
|
||||
cache-key: api-docs
|
||||
working-directory: langchain
|
||||
|
||||
- name: Install initial py deps
|
||||
working-directory: langchain
|
||||
run: |
|
||||
python -m pip install -U uv
|
||||
python -m uv pip install --upgrade --no-cache-dir pip setuptools pyyaml
|
||||
|
||||
|
||||
- name: Move libs with script
|
||||
run: python langchain/.github/scripts/prep_api_docs_build.py
|
||||
env:
|
||||
|
||||
12
.github/workflows/check_diffs.yml
vendored
12
.github/workflows/check_diffs.yml
vendored
@@ -17,9 +17,6 @@ concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
UV_FROZEN: "true"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
@@ -132,14 +129,15 @@ jobs:
|
||||
with:
|
||||
python-version: ${{ matrix.job-configs.python-version }}
|
||||
|
||||
- name: Install dependencies and run extended tests
|
||||
- name: Install dependencies
|
||||
shell: bash
|
||||
run: |
|
||||
echo "Running extended tests, installing dependencies with uv..."
|
||||
uv venv
|
||||
uv sync --group test
|
||||
VIRTUAL_ENV=.venv uv pip install -r extended_testing_deps.txt
|
||||
VIRTUAL_ENV=.venv make extended_tests
|
||||
uv pip install -r extended_testing_deps.txt
|
||||
|
||||
- name: Run extended tests
|
||||
run: make extended_tests
|
||||
|
||||
- name: Ensure the tests did not create any additional files
|
||||
shell: bash
|
||||
|
||||
15
.github/workflows/run_notebooks.yml
vendored
15
.github/workflows/run_notebooks.yml
vendored
@@ -15,7 +15,7 @@ on:
|
||||
- cron: '0 13 * * *'
|
||||
|
||||
env:
|
||||
UV_FROZEN: "true"
|
||||
POETRY_VERSION: "1.8.4"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
@@ -25,10 +25,13 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Python + uv
|
||||
uses: "./.github/actions/uv_setup"
|
||||
- name: Set up Python + Poetry ${{ env.POETRY_VERSION }}
|
||||
uses: "./.github/actions/poetry_setup"
|
||||
with:
|
||||
python-version: ${{ github.event.inputs.python_version || '3.11' }}
|
||||
poetry-version: ${{ env.POETRY_VERSION }}
|
||||
working-directory: ${{ inputs.working-directory }}
|
||||
cache-key: run-notebooks
|
||||
|
||||
- name: 'Authenticate to Google Cloud'
|
||||
id: 'auth'
|
||||
@@ -45,17 +48,17 @@ jobs:
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
uv sync --group dev --group test
|
||||
poetry install --with dev,test
|
||||
|
||||
- name: Pre-download files
|
||||
run: |
|
||||
uv run python docs/scripts/cache_data.py
|
||||
poetry run python docs/scripts/cache_data.py
|
||||
curl -s https://raw.githubusercontent.com/lerocha/chinook-database/master/ChinookDatabase/DataSources/Chinook_Sqlite.sql | sqlite3 docs/docs/how_to/Chinook.db
|
||||
cp docs/docs/how_to/Chinook.db docs/docs/tutorials/Chinook.db
|
||||
|
||||
- name: Prepare notebooks
|
||||
run: |
|
||||
uv run python docs/scripts/prepare_notebooks_for_ci.py --comment-install-cells --working-directory ${{ github.event.inputs.working-directory || 'all' }}
|
||||
poetry run python docs/scripts/prepare_notebooks_for_ci.py --comment-install-cells --working-directory ${{ github.event.inputs.working-directory || 'all' }}
|
||||
|
||||
- name: Run notebooks
|
||||
env:
|
||||
|
||||
23
.github/workflows/scheduled_test.yml
vendored
23
.github/workflows/scheduled_test.yml
vendored
@@ -14,9 +14,7 @@ on:
|
||||
|
||||
env:
|
||||
POETRY_VERSION: "1.8.4"
|
||||
UV_FROZEN: "true"
|
||||
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"]'
|
||||
POETRY_LIBS: ("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/deepseek", "libs/partners/google-vertexai", "libs/partners/google-genai", "libs/partners/aws"]'
|
||||
|
||||
jobs:
|
||||
compute-matrix:
|
||||
@@ -81,8 +79,7 @@ jobs:
|
||||
mv langchain-google/libs/vertexai langchain/libs/partners/google-vertexai
|
||||
mv langchain-aws/libs/aws langchain/libs/partners/aws
|
||||
|
||||
- name: Set up Python ${{ matrix.python-version }} with poetry
|
||||
if: contains(env.POETRY_LIBS, matrix.working-directory)
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
uses: "./langchain/.github/actions/poetry_setup"
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
@@ -90,12 +87,6 @@ jobs:
|
||||
working-directory: langchain/${{ matrix.working-directory }}
|
||||
cache-key: scheduled
|
||||
|
||||
- name: Set up Python ${{ matrix.python-version }} + uv
|
||||
if: "!contains(env.POETRY_LIBS, matrix.working-directory)"
|
||||
uses: "./langchain/.github/actions/uv_setup"
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
|
||||
- name: 'Authenticate to Google Cloud'
|
||||
id: 'auth'
|
||||
uses: google-github-actions/auth@v2
|
||||
@@ -109,20 +100,12 @@ jobs:
|
||||
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||
aws-region: ${{ secrets.AWS_REGION }}
|
||||
|
||||
- name: Install dependencies (poetry)
|
||||
if: contains(env.POETRY_LIBS, matrix.working-directory)
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
echo "Running scheduled tests, installing dependencies with poetry..."
|
||||
cd langchain/${{ matrix.working-directory }}
|
||||
poetry install --with=test_integration,test
|
||||
|
||||
- name: Install dependencies (uv)
|
||||
if: "!contains(env.POETRY_LIBS, matrix.working-directory)"
|
||||
run: |
|
||||
echo "Running scheduled tests, installing dependencies with uv..."
|
||||
cd langchain/${{ matrix.working-directory }}
|
||||
uv sync --group test --group test_integration
|
||||
|
||||
- name: Run integration tests
|
||||
env:
|
||||
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
|
||||
|
||||
33
Makefile
33
Makefile
@@ -1,8 +1,5 @@
|
||||
.PHONY: all clean help docs_build docs_clean docs_linkcheck api_docs_build api_docs_clean api_docs_linkcheck spell_check spell_fix lint lint_package lint_tests format format_diff
|
||||
|
||||
.EXPORT_ALL_VARIABLES:
|
||||
UV_FROZEN = true
|
||||
|
||||
## help: Show this help info.
|
||||
help: Makefile
|
||||
@printf "\n\033[1mUsage: make <TARGETS> ...\033[0m\n\n\033[1mTargets:\033[0m\n\n"
|
||||
@@ -28,20 +25,20 @@ docs_clean:
|
||||
|
||||
## docs_linkcheck: Run linkchecker on the documentation.
|
||||
docs_linkcheck:
|
||||
uv run --no-group test linkchecker _dist/docs/ --ignore-url node_modules
|
||||
poetry run linkchecker _dist/docs/ --ignore-url node_modules
|
||||
|
||||
## api_docs_build: Build the API Reference documentation.
|
||||
api_docs_build:
|
||||
uv run --no-group test python docs/api_reference/create_api_rst.py
|
||||
cd docs/api_reference && uv run --no-group test make html
|
||||
uv run --no-group test python docs/api_reference/scripts/custom_formatter.py docs/api_reference/_build/html/
|
||||
poetry run python docs/api_reference/create_api_rst.py
|
||||
cd docs/api_reference && poetry run make html
|
||||
poetry run python docs/api_reference/scripts/custom_formatter.py docs/api_reference/_build/html/
|
||||
|
||||
API_PKG ?= text-splitters
|
||||
|
||||
api_docs_quick_preview:
|
||||
uv run --no-group test python docs/api_reference/create_api_rst.py $(API_PKG)
|
||||
cd docs/api_reference && uv run make html
|
||||
uv run --no-group test python docs/api_reference/scripts/custom_formatter.py docs/api_reference/_build/html/
|
||||
poetry run python docs/api_reference/create_api_rst.py $(API_PKG)
|
||||
cd docs/api_reference && poetry run make html
|
||||
poetry run python docs/api_reference/scripts/custom_formatter.py docs/api_reference/_build/html/
|
||||
open docs/api_reference/_build/html/reference.html
|
||||
|
||||
## api_docs_clean: Clean the API Reference documentation build artifacts.
|
||||
@@ -53,15 +50,15 @@ api_docs_clean:
|
||||
|
||||
## api_docs_linkcheck: Run linkchecker on the API Reference documentation.
|
||||
api_docs_linkcheck:
|
||||
uv run --no-group test linkchecker docs/api_reference/_build/html/index.html
|
||||
poetry run linkchecker docs/api_reference/_build/html/index.html
|
||||
|
||||
## spell_check: Run codespell on the project.
|
||||
spell_check:
|
||||
uv run --no-group test codespell --toml pyproject.toml
|
||||
poetry run codespell --toml pyproject.toml
|
||||
|
||||
## spell_fix: Run codespell on the project and fix the errors.
|
||||
spell_fix:
|
||||
uv run --no-group test codespell --toml pyproject.toml -w
|
||||
poetry run codespell --toml pyproject.toml -w
|
||||
|
||||
######################
|
||||
# LINTING AND FORMATTING
|
||||
@@ -69,9 +66,9 @@ spell_fix:
|
||||
|
||||
## lint: Run linting on the project.
|
||||
lint lint_package lint_tests:
|
||||
uv run --group lint ruff check docs cookbook
|
||||
uv run --group lint ruff format docs cookbook cookbook --diff
|
||||
uv run --group lint ruff check --select I docs cookbook
|
||||
poetry run ruff check docs cookbook
|
||||
poetry run ruff format docs cookbook cookbook --diff
|
||||
poetry run ruff check --select I docs cookbook
|
||||
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 && \
|
||||
@@ -80,5 +77,5 @@ lint lint_package lint_tests:
|
||||
|
||||
## format: Format the project files.
|
||||
format format_diff:
|
||||
uv run --group lint ruff format docs cookbook
|
||||
uv run --group lint ruff check --select I --fix docs cookbook
|
||||
poetry run ruff format docs cookbook
|
||||
poetry run ruff check --select I --fix docs cookbook
|
||||
|
||||
@@ -528,12 +528,7 @@ def _get_package_version(package_dir: Path) -> str:
|
||||
"Aborting the build."
|
||||
)
|
||||
exit(1)
|
||||
try:
|
||||
# uses uv
|
||||
return pyproject["project"]["version"]
|
||||
except KeyError:
|
||||
# uses poetry
|
||||
return pyproject["tool"]["poetry"]["version"]
|
||||
return pyproject["tool"]["poetry"]["version"]
|
||||
|
||||
|
||||
def _out_file_path(package_name: str) -> Path:
|
||||
|
||||
@@ -1 +1 @@
|
||||
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
|
||||
@@ -1 +1 @@
|
||||
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
|
||||
@@ -1 +1 @@
|
||||
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
|
||||
@@ -1 +1 @@
|
||||
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
|
||||
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
|
||||
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
|
||||
@@ -1 +1 @@
|
||||
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
|
||||
@@ -1 +1 @@
|
||||
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
|
||||
@@ -1 +1 @@
|
||||
eNqdVWtsHNUVdhpoU2FSUihUahGrVUod8F3P7Mw+zbZarxO/Ym/s3djYKKzuztzZGe/M3Mk89uGIhrokkZIINFFTIqgMdTa7rWOchAQCAUe8qhoRMGobVSZpaEgLgiY84qCUVm16d71ubCW/OtI+Zu6553zn+853Z7iUQbohYXXJuKSaSIecSW4Me7iko40WMsxHigoyRcwX1kVj8b2WLs3cI5qmZgQbGqAmubCGVCi5OKw0ZOgGToRmA/mvyaiSppDEfH5m/SanggwDppDhDD6wyclhUkk1nUGniGQZO+udOpYRubUMpDsf2lDvVDCPZPIgpZmAxUCRVIlEGaaOoOIMClA20EMlEUGeYH+sIGLDtCcWozkAOQ6R3UjlMC+pKfuZ1JCk1Tt4JMjQRGMEg4oqvdpjaYQ0AGUpg4pzu+yDUNNkiYPl9YZBA6vjVczAzGvo2uWxMnJAGlRN+0iUgAi3NazLE9pUB+3y0i76YA4YJpRUmfAAZEjwFLXK+ksLFzTIpUkSUJXELs5tnlgYgw17XyfkorFFKaHOifY+qCte9vDC57qlmpKC7FJk3bXlqotXyzEu2u3yH1qU2MirnL2vQvnRRZuRqecBh0kO+1fUxDw/MlJTpmiP+j2/1pGhkRlAPyuSXaZlDBeIFOjEVKk6DKPRjnkNz9TcUWgmstiTfYivd1AexxqUdLgpt4d8BT3eIMs4Wjrj45Fqlfh1VTgU16FqCESJ1fOqlzjRUtOIH4tcV+/Jst6kmTJ6MoMA5TRsIFBFZY/fD3rmXADamg/PDRfAegqq0lClrD1ZET47lMvynMXzYiarUIEhlpGSyOKEI9Utmo7LZQggoBj2Xh8bmKiuzFM/RnqlAE0Bij6WAzqhQpYUidBZ+a5a0bALHoqiXrg2wMRpRExbYqnKdXxhhI4Uolm59tU0bCAQePn6QfOpGBIS8C9GQxRFC9HQbsV44dqAaopRyhjPzUcDibdnVpKbBAVplnUzEAr+pJvxeb1ulmME5Pb7hCTjY+gXic0ljmQpi6lh3QQG4si5Y+btmXoF5so2CzG0h/GSThsdksrJFo9iVrIZl3swGh2ajmQM+QOcADjIiQjMzZ9dau7vCne2RcZiBGQE47SEdr23ZGkiwQmJpBIa6G9xZ1NCJBHvGWznk7pgxo127FtvxTw8k1VFRWDD3uxQphUTpXyM3+cPUBQDaBflIiYFjNjd0pfLr3Fb/lhfot9Mu30GN9gd7fatH8hBSxc3BuQ1HUJ3humQI76Bge6wIeDuDrNTNtlmvre/i17XHkvyeSiv1RK9am6wI632ZEk30BRDDY0OMpsS4TdUdQggDgFlf9BB97w/Gh18hYOQa/Fh2OhoJUd2VJXzjY5YmUxEfqGCYpKJQl1YRTM/JxxYGYkPyYkmd75zYC3l8WCTNSjezHSqOEp0s1oja1t9vWxTqqd9MN5ihheQ4KM9gKry4KVYf2UKr0L/P1E9fz9YaHgQ1ebeTSUVG6okCMUY0omB7DFOxhZPznUdFSNrQE+43z4SoHgPJ1B0QAhAvxCgQBM5Meez/e94KJRfCiUokxnLcPZhkQk5gyzLOBsdCgz5vcROlTfYT4vlmVRTv11SvGvHsprKtZR8rlzZ2fPqo3+gbpn86N6tAV/dzRu+PRRetvyt3d9rqtMvtH2y4XecnDqKTm5u6Xrv7u/seOMH2y5/OPmyb+Tx2prnXgNPn95Rtyl1Mbrt07N94EenLieWv38cD2aPbgo+8dHFoycfu3Ni13D2WyvPrf6yV/+sdvXbmdF9P1yx6sWJ/Vlr/ea67frKoV5+17hBv6+dSe+ffbbOl+/+29//OX7m8C9u0276sbvm4ce/eFIfWP2N002HjjlCWxzB1y5Yy2pCTz7y9LLwtjr5jZNr25+3z3/33yM7z/q06WnHli0HqG/+ZWppc+8H/9i46tIfl4cLn2eoD3c+NdFWm31n1vXLr+49M7j/9eNfrPzaqUt/umXm7NSI++GnuHNnizcEpyd3dP615dk3D46c1h6cPfHM9FuvTHXvufEnK/68x7N99N2762/f2jMV+k1/APfVts8OT92++8ry2Scuxx849enm86mmdt2On7tvFcA3TXMjv1/xn/T5Yx/Q1NcvRgd6bvV8dal2+wC952OW+n6kcFx67sJU44HSv8QNsd2Few69dKr1RNfMXRUxltZ8tnXjXkCU+S+tood0
|
||||
eNqdVX1sE+cZTxapoKJJ1YrUKuqG65VqWvLad77z2RfXa12bAPlyiPPFgGWv7177jtzde7kPx06F2rLuowFKj34ghJoKEmzkZdBA2PjeAKWb0KZprbY2dGVbUbV+bIWKbG23MPbacUYi+Gv3x9n3Ps/7PL/n93ue991ayCDDlLFWPS5rFjKgYJEP09laMNCAjUzrmbyKLAmLY+3xROeobcjT35QsSzcbvF6oyx6sIw3KHgGr3gztFSRoecl/XUHlMGNJLOamNz3hVpFpwjQy3Q2uDU+4BUxSaRb5cEtIUbC73uU2sIJKC7aJDPeWTWRFxSJSSktp3QIsBqqsySVP0zIQVIkhBRUTbSlICIqkhp1jEjYt59BiVIehICCyH2kCFmUt7fwkPSTr9S4RpRRooSKBoqFyzU6xHyEdQEXOoPzcLuc1qOuKLMCS3bvZxNp4BTqwcjq63VwsoQekUM1yJuMERGSttz1H6NNctMfPe/yvZYFpQVlTCB9AgQRPXi/bTy006FDoJ0FARRonP7f50EIfbDoHWqEQTywKCQ1Bcg5AQ+XYowvXDVuzZBU5hWj77ekqxlvpGA9NewITiwKbOU1wDpQp/9mizcgyckDAJIazjzo0z4+CtLQlOft55qCBTJ30AvpenuyybHPrGJEC/fpXhUpT7I83z2t4ueq+sRiRxTnTKdn1Lop3NUHN5aN8fvJqYAINFOda3do5Hq1k6byjChOdBtTMFFFi1bzqBUGytX4kFqN31PtMSW9STAk9aUSAsjo2EaigcsZ7QcfcNIC1saNzzQWwkYaaPFRO65wpCz84lB0UBVsUpcygSvFDLCMnkS2kJitbdAOX0hBAQDWdUcYXPFSxzFNfJLVSgKYARZ/MAoNQociqTOgsvysjaTpjfoqijt/uYOF+RIa3wFLl5+xCDwOpRLNS7lthWJ7nT9/ZaT4UQ1z44GI0RFG0EA3tU83jtztUQuynzPHsvDeQRWf6IfLRB5mACAXex/j4QBAmRZ+PRwzHpAIslxJTgnCCzLkskCglMXVsWMBEAjl/rJwzXa/CbGnMwgztZzhSacgla4JiiyhhJ2O4VIMZcukGUjAUD0cbQRQKEgKJcv85hdj6tkjr2mgxQUBGMe6X0a5L1TV9fUKqL6mGWbuno7utqzmX7KBWb8br+mJJKt1p9+iJYAS2mP4Bri2JIuyaoJEGdIDhWL+f8nGA9lAe2kODQKRLTvfEsusYoynSRfvWs2vszdkhke7tZJt7u+wB2GrHcfeQKlJDEh5oirc1qauDba1NXXp0TbSbi6uretqTvDAY6Mlls6KtsVJvLkKqgZYU9oZcpDdlwm+4MiGATAgozQfdQM3PR8glljkIexYfhiHXGnJ0xzUlF3IlSmQi8gtVlJAtFG7DGpp+kXBgZ2Qx7FezJh9L+KW1nuaBboM2jP5MB90bibCbGwPxjl4qJa0aWN3S1DowuIAE2scDqsIDR7HBchfegv5/ovppL1g48CCuz91RBQ2bmpxK5RPIIAPkFAUF2yI51w2UJ5p3RNY7k8FUKsDwPo5LUSxPUX7wODkx56P973gYK10KBaiQHssIzlGJCbsbWJZxh1wqDAc5Mk7lm+zpfKkntfRU9Ysrti2tKj812zvODb9DLT/977rv2M81v9fKyZ6VPwQbXh65e9PbiB6e+dtB5x/PzLTs9Xzx2arMV0LKsjOfU9dTjzAf+GvuadzmX3rshfFafH3HlcLeq7Pvwzdnrz159sSWv6z4bOrdd41TW6jkruWTN54d/m1x53Atdr58YqS7eqVgvAKw9tdtU5O9Vixaq+76/ch1/v0dAw9781OPvOq5Pv3R2GVn3f1TtSNM1VNvfbLXaNjx86na/AvMG9/dfqRx4uwD1T96jHvw8dcld/Mvk77nhx8Y/Xj/n0aPzVR/8uF93/jwz3UzXwq2L2v59te+tfP71T/mLi6/fOwPI9eurHz2wKUll16/98lzdVda/vhSNXpo939q95z+4G3hrmtv+LXDTUtXHPx0o+/vv1t5oevqwz/Ys0TL1Eapicmvz9af9NX5j7Dcc3fd21T86kcRfrxugyrFxNGLVy/M/ubUYXXjjUf/WbNv+VDjpn89dengx+cvrP/FzNKbdmbP8WX17z3o4xDauOPckjcfffri7q591sTJG+xudyiFCf03b9ZUnb8xu/2emqqq/wK0XX0A
|
||||
@@ -1 +1 @@
|
||||
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
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
|
||||
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
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
|
||||
eNrtVn1wVNUVTxREQSrDRxUZ4RGa1cK+3beb7G6y6wPSkA80X23YEkdjfPv27u5z3777ePfuV5BWIjINhQ5PPlIm1AoJCQQCIpSxok1Q0xJrDDJlmC0j0trWtiPDlPpRinR63m4WJINTp+O0OpLZP/LuPffc3/md3zn3tHTHkEYkrOTukRSKNEGk8EE2tnRraFkUEbqqK4JoCPs7KsqWdEQ1KbUuRKnqtlqRYolLYUlFfkmwYC1ojVsFVbKoIXWBqmGVl5QAzneVqkIQGd/EJCnp9agmm1Q1/a9fIkLEJwWjgnGpSQNXGhIp4U1UojIifJWgBEtDgqSYAliLCJR/lIBdBiMP8LRkpw/7k/3dIST4IY5VPV6CNLYkiBSqpwou42PuMUATQB2UaCjqs4g4Yg1i2U8i8G1dmrWzfnNfiSgilbJlioj9khLUe4PNkmpm/CggCxR1Zbb1jrnWuT2lWFFQGoveE0ZIZQVZiqGdGiIqUIie6CJUoFHS0gmu0FAu2x1BhAAd+6txDPmZOgQhKYBUTmbxr+4Rr/jcIcqYoJ0yFtP06KkfZYP4YlC/F7BSgM/KSAnSkL6N606woiCGkN4jqjabjWNAUl2QEJCY3l1ZUqfhRHLviA2bIUfvBhuWyiSdyJVAmQasP/Pp8vuCkfCl0d/rR7Py2157fxbv6ZypPzcYFyEFmqDAOY2yBIlANE3qKTYiJFg4wds4Z0FRocvGeSClohz1o/qobxGOADPEw6gakrHg36Wh9HmK9dSvlzN5QQ1H1Tw3kxePNClIzjMzeeCvCfzBopMrLOI4WEKKX8WgAQKLD8IpSI9xJssX7AhhxMo4GAQ20hmPXM54zGZFMaCaLIAgkBDh4wWiJYMCjA01KIjGsRZuQpqGNRMB3UWEJoiOt4Kp9ZOm1qtMrTYLZ+HymBWNzIqsglOmSJwFSxYlqAUtkwS/xSCAdTpcxT6/zxVwsHGtOaYcAoWPVAZNqojFarql6t0KJooUCIyugE5VIKQzJmjA+OJR6TcvgbgoKxDWq1AtSijymxvYcqzFBc2P/CyUFMXmUozDEjKXRKFSNKk5reYDWQwgchUTKdNCIH2ypCAPE5CgaoUI4o2AQDFRmVoMce8GcLJknJNUfU9xkcVmKwIqbDZnbwa04VbDsp6ao2pSDCRpZiKAC3zEQH7+zMKIbLjeDHUslSKGllP5aR8ePyIin2eEDaIIYUJHVoyuwRXldcBZ6CbPZiNA2VroNGqh07hDf2kpMMFwDqYc+Rg7Z3cwtmJ3QYHbbmMqqpdcbkTPZ1wyEYkQMzPyYVy855Mp0vsEVZWlTJ+1GjR4GDEkaARRPkoDbFGvkEkL1EgQEX2HL0kRGd3/OuxOZwcIXU89DDrOaKuJ4v9YAQFBkqMaagqMPL6wB9pzwA6JwrWEjNpZsS/BwkrkirI6F5XVPNADaCE7hhI2phqWVpezVQLkpSTtguccLDDFGkx56gQa4q2eSiixWkVOetIFjzxlCRXaH+HrowowW8xUC9oIs3Y3x8HPYDYVHeWZrZCxT5CvdUGmQfBXt+n/8tqqCoQX1/Heend1ibsKJUAOFCvuQrul0OlmXTaL3e6OFXqYkauZEefMNTGkFtRkih3Kx4eqQJyUB2I5WxZ5feZ0PZBcL1EE70DCUw2ihsbOFzg57qrHaiB3/Kwf3pyT/rtx0/ra2leZSQN9E8bVvrX5X6e++9S6cftm8slS99efowvdJxwz+g4/MXinWLX2ocffbk/e+yfzTMf08MuT+Uk35y+a/bSrEn/rJ2W/KdhzgTt4iXuv/dLYFxbvnDBvjLbOPKb4fOp3Ne88Fv5Z6SF77i3rN3Mrg385cdddR1obBp1Pz3OdfiD34yNm9rR6Cv/2D5PF2tbiJ4cazty7Xa/u2zBUE/so2vtCyeIL/WMf3rfxTH7F3nZFRqfirNi/xXxg/+GZE/52MNm3Y+ubkwe83mmPbHmn/HvVbbOHvL/wvr3gV+Mvnagv3npmSfkMPP9d8g/788dXP9RfGhvccPyOY9MvDU899+L8nCk5E9cO5ObkfPrDjT/j3Ajd1ZA7MaGEKgvGUJqgvMnIOPSd65PhNSdD9bMORZ8Xuf+f2e9/HuaXfrrbnx7rAoD68iPaLYaiShj5rw9+n+PgF/FFipqvD35fjcHv+pD3VRzyZlwZ8rzrj9S8wt26umngtbHrX161UD6uTDl5/qbDiV3t5Z01rY33bUnEj9fsbvia/sG7w+eG57dP6Qk3/vWflfcF8FrHT2/84+B7w10VtfbbD7edfEu5+OJLa7Y5L+4OTLx9eIPjzsI3bpn23PfDNrV1Ox768/t940tySr7TMSfQYhIrxNdmPcPOPTh1+cqbGn9Q8u1dO8es3PRY+cTW2Y5JtuVzXRe3Pbuw7dE1N3zk/cBy2wFX7ocrblUuMDOKXp+Iz7r0eS1Pbjpf88ikZnrPN9pWL2t5v6zYd5t47NDj+dsmvMFWTn9zSv0vQ/ef/X3duA/r7nbRV8cfvePuLW39jqPHoj9+ZfgG35FN07Y+taZxZuPgg2fb58xKfbz57+NOLj/nPQhT378BkGvf4Q==
|
||||
eNrtVt1uG0UUpu/AA4wWYdrKY69/4ri2VlWU/oqkjZRULVCIxrvH9jSzO9uZWcdu1QtKxR1IK/UBgKRNCf0BgRBcILhBQgIewFzwLJzZtUMStWqBgoqUKIqyZ87MfOc735xzbm4NQGkuo0P3eWRAMd/gh759c0vB1QS0uXU3BNOXwcbpkysbieLjD/rGxK1yGaLSOl/jMQSclaTqldfLLOaluB8fj5WMPR515auz8zHrgf3WBR5l9kSJQhxn/wZcs7DDewmzlxYUHqXAN9orGG4EaG+BRb35PuNRoStVyIx3RaNfjtFDeGq02ZHB6IetPrAA47i1fUGDonM9iEw6ru3gI4ctaI2oe9z0k07Jl2G5J0WgQ/wuX5z6lY88mvN9iA09Gfky4FEvfdC7xuMiCaArmIG7+XK6cbR8dHteRhFkWNLtNYCYMsEHcE+BjpFCeO+uNswk+uYmHgW/HqJbIWiNdHyxKAcQkCXAkCJEKkZT/O/fRfiYkHTrzNySksPRwyH1md8Hmh+VbmGSqBF62//z7ju+kBruCelnNKbjD6fBvhgp2prEkG77caVScQnG8BDxGwydCoh6pp9+7GaJfBcpU8j6R0+W3wsW3P9Gf7/8NJXfJ+dfn+L9/aWXNwM8Nv3uIgRFUq2R874hVbdaJ5VGy51t1avk9OLKA5aDUkgH6PROZ2RA35+m0IxiSL9ncSx4rsCyZalN/D5TGoyXmC5tfmsT66MznoHwlKEafMynGaVjGrIhRWBexW3UmvXZittGjfgiCWA56ZyQISZAt0msQEgWfDm9F7MXS81zzeMGwSNoky5HSbEQPBQDRSoSYUoWzwZegDLbRkTUl3KNw+3xpYuLp+gC04ZaWrX2qjWKBFBLQHuJmb5Xbp/BxJ2PxKid4YX2yWGMItHechIhYXVyTg4mhFVbrou/lrBxsu9kelrIDhOPuyCPz9sr5r957cJpkGeXvAvLrcW51gIMUUBGRpjFUr3RorOVUrXaGtTbZHI1mRxOHothfPwcmHWp1rASdWCBo1Q9t+S6lSny5Xz3MrK9zA3gaxm2FzGVKH+v1nDdnYf/jX34bpOEXOsimXzETOsHebmjBg9HrY9fzfzbAWjfc6yDUyR9qc3Eku90pkVyXAjXqU0zDE0JrnIWlGwYdKZbP9aodzrdDu1fOTYTbA6YQpmd3fe0iisKmKFM0wuRUYk2+AQu0VNSrTMVQEAxbCOL85lWinMJViHFr2UC31+VNy3UjQhEOn7nOnEUWIGvGum0iLMeruICxuGgyldRhGhsuPWm66Kpy7hACle7k76La8jwDK7oJNPNvpUbD/J77RNQEq97JVZ8gA+4SEIMAPU+wBoQ5IbJo3IfDSmeEgKVcdbb080TJ8+98RnGILh9RzxO7x9rliqVZsnFv41Pc/zUyHT8M4bTUzKJnxoKREEssbJrNL6Fu7DM2j3TuocrbA2okL0eUp8JLdyp3INKGQYIRR/HKgEs9NZrfilHgc62qke5EldBKakKGjkI2SqWD6+MruXdruU9ruUKxuQ65Mbb5MbXQ7q7ZO3QsRVJHfFu9/PpKkxr76atvftb1Ua10djTrH479ON1p8OM38eqHgswyIvjFJ2sPzit645tQdr+M1ubmZ1tVBtTIw+c1tRWdCL0cYtO1nrwhJ3eg0dNIIRYx5FVx7JnUPS4Yo8R6Jlk6cAs7LP1TShs+X/cGnY7NAuj0G5kgqQiHsdWFVpxaaW5gtWiXmm5tTfRQTCbm4GFXKnWmzW3NlOvoTkjBW3N+rFm0ekmQmSZd57cpvGrvDs4XDFP24P6CWCYNfeMn12dedKN7SmWKRbJCPvQX0RxA3+ePHPIZxx5MSX2ueoCDGPB7Dw9NF7BlmF8rQdD7T8aauNnnfueVxKe79j6n8M/GEwPBtODwfSFHUwDMxtVDwbTg8H0eQ6mzdq+wfSrf3swnXSr3VbCNWFEy65BuQLJMmzjJqbPDOmDiDXpMp8LjhoFtILtrNBTmYKJ7BLBVA/IdEol2dSryeGFhUV9xPpKsqum6xKZsxfudd9z5A6EItlB+ZomiUa9Mg06v1CMCE4wSrCYrGPvQ2A4gORw9gLBELGNgmKiOOkGyDUJpJ+EmA3CIiZG2pIQBUQnYcimr7NoO4/pSIO1xi7a7rfjXrocXc7n0D8AkSIW2A==
|
||||
@@ -1 +1 @@
|
||||
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
|
||||
@@ -3,11 +3,16 @@
|
||||
This guide walks through how to run the repository locally and check in your first code.
|
||||
For a [development container](https://containers.dev/), see the [.devcontainer folder](https://github.com/langchain-ai/langchain/tree/master/.devcontainer).
|
||||
|
||||
## Dependency Management: `uv` and other env/dependency managers
|
||||
## Dependency Management: Poetry and other env/dependency managers
|
||||
|
||||
This project utilizes [uv](https://docs.astral.sh/uv/) v0.5+ as a dependency manager.
|
||||
This project utilizes [Poetry](https://python-poetry.org/) v1.7.1+ as a dependency manager.
|
||||
|
||||
Install `uv`: **[documentation on how to install it](https://docs.astral.sh/uv/getting-started/installation/)**.
|
||||
❗Note: *Before installing Poetry*, if you use `Conda`, create and activate a new Conda env (e.g. `conda create -n langchain python=3.9`)
|
||||
|
||||
Install Poetry: **[documentation on how to install it](https://python-poetry.org/docs/#installation)**.
|
||||
|
||||
❗Note: If you use `Conda` or `Pyenv` as your environment/package manager, after installing Poetry,
|
||||
tell Poetry to use the virtualenv python environment (`poetry config virtualenvs.prefer-active-python true`)
|
||||
|
||||
## Different packages
|
||||
|
||||
@@ -32,7 +37,7 @@ cd libs/community
|
||||
Install langchain-community development requirements (for running langchain, running examples, linting, formatting, tests, and coverage):
|
||||
|
||||
```bash
|
||||
uv sync
|
||||
poetry install --with lint,typing,test,test_integration
|
||||
```
|
||||
|
||||
Then verify dependency installation:
|
||||
@@ -41,6 +46,12 @@ Then verify dependency installation:
|
||||
make test
|
||||
```
|
||||
|
||||
If during installation you receive a `WheelFileValidationError` for `debugpy`, please make sure you are running
|
||||
Poetry v1.6.1+. This bug was present in older versions of Poetry (e.g. 1.4.1) and has been resolved in newer releases.
|
||||
If you are still seeing this bug on v1.6.1+, you may also try disabling "modern installation"
|
||||
(`poetry config installer.modern-installation false`) and re-installing requirements.
|
||||
See [this `debugpy` issue](https://github.com/microsoft/debugpy/issues/1246) for more details.
|
||||
|
||||
## Testing
|
||||
|
||||
**Note:** In `langchain`, `langchain-community`, and `langchain-experimental`, some test dependencies are optional. See the following section about optional dependencies.
|
||||
@@ -68,6 +79,7 @@ If you are only developing `langchain_core` or `langchain_community`, you can si
|
||||
|
||||
```bash
|
||||
cd libs/core
|
||||
poetry install --with test
|
||||
make test
|
||||
```
|
||||
|
||||
@@ -75,6 +87,7 @@ Or:
|
||||
|
||||
```bash
|
||||
cd libs/community
|
||||
poetry install --with test
|
||||
make test
|
||||
```
|
||||
|
||||
@@ -166,7 +179,7 @@ ignore-words-list = 'momento,collison,ned,foor,reworkd,parth,whats,aapply,mysogy
|
||||
|
||||
`langchain-core` and partner packages **do not use** optional dependencies in this way.
|
||||
|
||||
You'll notice that `pyproject.toml` and `uv.lock` are **not** touched when you add optional dependencies below.
|
||||
You'll notice that `pyproject.toml` and `poetry.lock` are **not** touched when you add optional dependencies below.
|
||||
|
||||
If you're adding a new dependency to Langchain, assume that it will be an optional dependency, and
|
||||
that most users won't have it installed.
|
||||
@@ -183,10 +196,18 @@ test makes use of lightweight fixtures to test the logic of the code.
|
||||
|
||||
## Adding a Jupyter Notebook
|
||||
|
||||
If you are adding a Jupyter Notebook example, you'll want to run with `test` dependencies:
|
||||
If you are adding a Jupyter Notebook example, you'll want to install the optional `dev` dependencies.
|
||||
|
||||
To install dev dependencies:
|
||||
|
||||
```bash
|
||||
uv run --group test jupyter notebook
|
||||
poetry install --with dev
|
||||
```
|
||||
|
||||
When you run `uv sync`, the `langchain` package is installed as editable in the virtualenv, so your new logic can be imported into the notebook.
|
||||
Launch a notebook:
|
||||
|
||||
```bash
|
||||
poetry run jupyter notebook
|
||||
```
|
||||
|
||||
When you run `poetry install`, the `langchain` package is installed as editable in the virtualenv, so your new logic can be imported into the notebook.
|
||||
|
||||
@@ -509,7 +509,7 @@
|
||||
"source": [
|
||||
"## API reference\n",
|
||||
"\n",
|
||||
"For detailed documentation of all ChatDatabricks features and configurations head to the API reference: https://api-docs.databricks.com/python/databricks-ai-bridge/latest/databricks_langchain.html#databricks_langchain.ChatDatabricks"
|
||||
"For detailed documentation of all ChatDatabricks features and configurations head to the API reference: https://python.langchain.com/api_reference/databricks/chat_models/langchain_databricks.chat_models.ChatDatabricks.html"
|
||||
]
|
||||
}
|
||||
],
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
"\n",
|
||||
"| Class | Package | Local | Serializable | [JS support](https://js.langchain.com/docs/integrations/chat/deepseek) | Package downloads | Package latest |\n",
|
||||
"| :--- | :--- | :---: | :---: | :---: | :---: | :---: |\n",
|
||||
"| [ChatDeepSeek](https://python.langchain.com/api_reference/deepseek/chat_models/langchain_deepseek.chat_models.ChatDeepSeek.html) | [langchain-deepseek](https://python.langchain.com/api_reference/deepseek/) | ❌ | beta | ✅ |  |  |\n",
|
||||
"| [ChatDeepSeek](https://python.langchain.com/api_reference/deepseek/chat_models/langchain_deepseek.chat_models.ChatDeepSeek.html) | [langchain-deepseek-official](https://python.langchain.com/api_reference/deepseek/) | ❌ | beta | ✅ |  |  |\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",
|
||||
@@ -40,7 +40,7 @@
|
||||
"\n",
|
||||
"## Setup\n",
|
||||
"\n",
|
||||
"To access DeepSeek models you'll need to create a/an DeepSeek account, get an API key, and install the `langchain-deepseek` integration package.\n",
|
||||
"To access DeepSeek models you'll need to create a/an DeepSeek account, get an API key, and install the `langchain-deepseek-official` integration package.\n",
|
||||
"\n",
|
||||
"### Credentials\n",
|
||||
"\n",
|
||||
@@ -87,7 +87,7 @@
|
||||
"source": [
|
||||
"### Installation\n",
|
||||
"\n",
|
||||
"The LangChain DeepSeek integration lives in the `langchain-deepseek` package:"
|
||||
"The LangChain DeepSeek integration lives in the `langchain-deepseek-official` package:"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -97,7 +97,7 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%pip install -qU langchain-deepseek"
|
||||
"%pip install -qU langchain-deepseek-official"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
@@ -55,7 +55,7 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"loader = ReadTheDocsLoader(\"rtdocs\")"
|
||||
"loader = ReadTheDocsLoader(\"rtdocs\", features=\"html.parser\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -135,7 +135,6 @@
|
||||
" compartment_id=\"MY_OCID\",\n",
|
||||
" auth_type=\"SECURITY_TOKEN\",\n",
|
||||
" auth_profile=\"MY_PROFILE\", # replace with your profile name\n",
|
||||
" auth_file_location=\"MY_CONFIG_FILE_LOCATION\", # replace with file location where profile name configs present\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
@@ -160,7 +159,6 @@
|
||||
" service_endpoint=\"https://inference.generativeai.us-chicago-1.oci.oraclecloud.com\",\n",
|
||||
" compartment_id=\"DEDICATED_COMPARTMENT_OCID\",\n",
|
||||
" auth_profile=\"MY_PROFILE\", # replace with your profile name,\n",
|
||||
" auth_file_location=\"MY_CONFIG_FILE_LOCATION\", # replace with file location where profile name configs present\n",
|
||||
" provider=\"MODEL_PROVIDER\", # e.g., \"cohere\" or \"meta\"\n",
|
||||
" context_size=\"MODEL_CONTEXT_SIZE\", # e.g., 128000\n",
|
||||
")"
|
||||
|
||||
@@ -1,107 +0,0 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "raw",
|
||||
"id": "afaf8039",
|
||||
"metadata": {
|
||||
"id": "afaf8039"
|
||||
},
|
||||
"source": [
|
||||
"---\n",
|
||||
"sidebar_label: Nimble\n",
|
||||
"---"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "72ee0c4b-9764-423a-9dbf-95129e185210",
|
||||
"metadata": {
|
||||
"id": "72ee0c4b-9764-423a-9dbf-95129e185210"
|
||||
},
|
||||
"source": [
|
||||
"# Nimble\n",
|
||||
"\n",
|
||||
" [Nimble](https://www.linkedin.com/company/nimbledata) is the first business external data platform, making data decision-making easier than ever, with our award-winning AI-powered data structuring technology Nimble connects business users with the public web knowledge.\n",
|
||||
"We empower businesses with mission-critical real-time external data to unlock advanced business intelligence, price comparison, and other public data for sales and marketing. We translate data into immediate business value.\n",
|
||||
"\n",
|
||||
"If you'd like to learn more about Nimble, visit us at [nimbleway.com](https://www.nimbleway.com/).\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"## Currently we expose the following components\n",
|
||||
"\n",
|
||||
"* **Retriever** - Allow us to query the internet and get parsed textual results utilizing several search engines.\n",
|
||||
"\n",
|
||||
"\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"## Usage"
|
||||
],
|
||||
"metadata": {
|
||||
"id": "AuMFgVFrKbNH"
|
||||
},
|
||||
"id": "AuMFgVFrKbNH"
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"In order to use our provider you have to provide an API key like so"
|
||||
],
|
||||
"metadata": {
|
||||
"id": "sFlPjZX9KdK6"
|
||||
},
|
||||
"id": "sFlPjZX9KdK6"
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"source": [
|
||||
"import getpass\n",
|
||||
"import os\n",
|
||||
"\n",
|
||||
"os.environ[\"NIMBLE_API_KEY\"] = getpass.getpass()"
|
||||
],
|
||||
"metadata": {
|
||||
"id": "eAqSHZ-Z8R3F"
|
||||
},
|
||||
"id": "eAqSHZ-Z8R3F",
|
||||
"execution_count": null,
|
||||
"outputs": []
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"For more information about the Authentication process, see [Nimble APIs Authentication Documentation](https://docs.nimbleway.com/nimble-sdk/web-api/nimble-web-api-quick-start-guide/nimble-apis-authentication)."
|
||||
],
|
||||
"metadata": {
|
||||
"id": "WfwnI_RS8PO5"
|
||||
},
|
||||
"id": "WfwnI_RS8PO5"
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.10.4"
|
||||
},
|
||||
"colab": {
|
||||
"provenance": []
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -103,7 +103,6 @@
|
||||
" compartment_id=\"MY_OCID\",\n",
|
||||
" auth_type=\"SECURITY_TOKEN\",\n",
|
||||
" auth_profile=\"MY_PROFILE\", # replace with your profile name\n",
|
||||
" auth_file_location=\"MY_CONFIG_FILE_LOCATION\", # replace with file location where profile name configs present\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"\n",
|
||||
|
||||
@@ -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-docs.databricks.com/python/databricks-ai-bridge/latest/databricks_langchain.html#databricks_langchain.DatabricksVectorSearch"
|
||||
"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"
|
||||
]
|
||||
}
|
||||
],
|
||||
|
||||
@@ -137,11 +137,6 @@ const config = {
|
||||
disableSwitch: false,
|
||||
respectPrefersColorScheme: true,
|
||||
},
|
||||
announcementBar: {
|
||||
content:
|
||||
'<strong>Join us at <a href="https://interrupt.langchain.com/" target="_blank" rel="noopener noreferrer"> Interrupt: The Agent AI Conference by LangChain</a> on May 13 & 14 in San Francisco!</strong>',
|
||||
backgroundColor: '#d0c9fe'
|
||||
},
|
||||
prism: {
|
||||
theme: {
|
||||
...baseLightCodeBlockTheme,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Read the list of notebooks to skip from the JSON file
|
||||
SKIP_NOTEBOOKS=$(uv run python -c "import json; print('\n'.join(json.load(open('docs/notebooks_no_execution.json'))))")
|
||||
SKIP_NOTEBOOKS=$(python -c "import json; print('\n'.join(json.load(open('docs/notebooks_no_execution.json'))))")
|
||||
|
||||
# Get the working directory or specific notebook file from the input parameter
|
||||
WORKING_DIRECTORY=$1
|
||||
@@ -13,7 +13,7 @@ execute_notebook() {
|
||||
total="$3"
|
||||
echo "Starting execution of $file ($index/$total)"
|
||||
start_time=$(date +%s)
|
||||
if ! output=$(time uv run --group dev --group test jupyter nbconvert --to notebook --execute --ExecutePreprocessor.kernel_name=python3 $file 2>&1); then
|
||||
if ! output=$(time poetry run jupyter nbconvert --to notebook --execute --ExecutePreprocessor.kernel_name=python3 $file 2>&1); then
|
||||
end_time=$(date +%s)
|
||||
execution_time=$((end_time - start_time))
|
||||
echo "Error in $file. Execution time: $execution_time seconds"
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
# modifications should be discarded after the cassettes are generated.
|
||||
#
|
||||
# Usage:
|
||||
# In monorepo env, `uv sync --group dev --group test`
|
||||
# In monorepo env, `poetry install --with dev,test`
|
||||
# `./docs/scripts/update_cassettes.sh path/to/notebook`
|
||||
# e.g., `./docs/scripts/update_cassettes.sh docs/docs/how_to/tool_choice.ipynb`
|
||||
#
|
||||
@@ -41,11 +41,11 @@ delete_cassettes "$WORKING_DIRECTORY"
|
||||
|
||||
# Pre-download tiktoken files
|
||||
echo "Pre-downloading nltk and tiktoken files..."
|
||||
uv run python docs/scripts/cache_data.py
|
||||
poetry run python docs/scripts/cache_data.py
|
||||
|
||||
# Prepare notebooks
|
||||
echo "Preparing notebooks for CI..."
|
||||
uv run python docs/scripts/prepare_notebooks_for_ci.py --comment-install-cells --working-directory "$WORKING_DIRECTORY"
|
||||
poetry run python docs/scripts/prepare_notebooks_for_ci.py --comment-install-cells --working-directory "$WORKING_DIRECTORY"
|
||||
|
||||
# Run notebooks
|
||||
echo "Running notebooks..."
|
||||
|
||||
@@ -121,7 +121,7 @@ export const CustomDropdown = ({ selectedOption, options, onSelect, modelType })
|
||||
* @param {ChatModelTabsProps} props - Component props.
|
||||
*/
|
||||
export default function ChatModelTabs(props) {
|
||||
const [selectedModel, setSelectedModel] = useState("Groq");
|
||||
const [selectedModel, setSelectedModel] = useState("OpenAI");
|
||||
const {
|
||||
openaiParams,
|
||||
anthropicParams,
|
||||
@@ -174,20 +174,13 @@ export default function ChatModelTabs(props) {
|
||||
const llmVarName = customVarName ?? "model";
|
||||
|
||||
const tabItems = [
|
||||
{
|
||||
value: "Groq",
|
||||
label: "Groq",
|
||||
text: `from langchain_groq import ChatGroq\n\n${llmVarName} = ChatGroq(${groqParamsOrDefault})`,
|
||||
apiKeyName: "GROQ_API_KEY",
|
||||
packageName: "langchain-groq",
|
||||
shouldHide: hideGroq,
|
||||
},
|
||||
{
|
||||
value: "OpenAI",
|
||||
label: "OpenAI",
|
||||
text: `from langchain_openai import ChatOpenAI\n\n${llmVarName} = ChatOpenAI(${openAIParamsOrDefault})`,
|
||||
apiKeyName: "OPENAI_API_KEY",
|
||||
packageName: "langchain-openai",
|
||||
default: true,
|
||||
shouldHide: hideOpenai,
|
||||
},
|
||||
{
|
||||
@@ -196,6 +189,7 @@ export default function ChatModelTabs(props) {
|
||||
text: `from langchain_anthropic import ChatAnthropic\n\n${llmVarName} = ChatAnthropic(${anthropicParamsOrDefault})`,
|
||||
apiKeyName: "ANTHROPIC_API_KEY",
|
||||
packageName: "langchain-anthropic",
|
||||
default: false,
|
||||
shouldHide: hideAnthropic,
|
||||
},
|
||||
{
|
||||
@@ -204,6 +198,7 @@ export default function ChatModelTabs(props) {
|
||||
text: `from langchain_openai import AzureChatOpenAI\n\n${llmVarName} = AzureChatOpenAI(${azureParamsOrDefault})`,
|
||||
apiKeyName: "AZURE_OPENAI_API_KEY",
|
||||
packageName: "langchain-openai",
|
||||
default: false,
|
||||
shouldHide: hideAzure,
|
||||
},
|
||||
{
|
||||
@@ -212,6 +207,7 @@ export default function ChatModelTabs(props) {
|
||||
text: `from langchain_google_vertexai import ChatVertexAI\n\n${llmVarName} = ChatVertexAI(${googleParamsOrDefault})`,
|
||||
apiKeyText: "# Ensure your VertexAI credentials are configured",
|
||||
packageName: "langchain-google-vertexai",
|
||||
default: false,
|
||||
shouldHide: hideGoogle,
|
||||
},
|
||||
{
|
||||
@@ -220,6 +216,7 @@ export default function ChatModelTabs(props) {
|
||||
text: `from langchain_aws import ChatBedrock\n\n${llmVarName} = ChatBedrock(${awsBedrockParamsOrDefault})`,
|
||||
apiKeyText: "# Ensure your AWS credentials are configured",
|
||||
packageName: "langchain-aws",
|
||||
default: false,
|
||||
shouldHide: hideAWS,
|
||||
},
|
||||
{
|
||||
@@ -228,6 +225,7 @@ export default function ChatModelTabs(props) {
|
||||
text: `from langchain_cohere import ChatCohere\n\n${llmVarName} = ChatCohere(${cohereParamsOrDefault})`,
|
||||
apiKeyName: "COHERE_API_KEY",
|
||||
packageName: "langchain-cohere",
|
||||
default: false,
|
||||
shouldHide: hideCohere,
|
||||
},
|
||||
{
|
||||
@@ -236,6 +234,7 @@ export default function ChatModelTabs(props) {
|
||||
text: `from langchain_nvidia_ai_endpoints import ChatNVIDIA\n\n${llmVarName} = ChatNVIDIA(${nvidiaParamsOrDefault})`,
|
||||
apiKeyName: "NVIDIA_API_KEY",
|
||||
packageName: "langchain-nvidia-ai-endpoints",
|
||||
default: false,
|
||||
shouldHide: hideNvidia,
|
||||
},
|
||||
{
|
||||
@@ -244,14 +243,25 @@ export default function ChatModelTabs(props) {
|
||||
text: `from langchain_fireworks import ChatFireworks\n\n${llmVarName} = ChatFireworks(${fireworksParamsOrDefault})`,
|
||||
apiKeyName: "FIREWORKS_API_KEY",
|
||||
packageName: "langchain-fireworks",
|
||||
default: false,
|
||||
shouldHide: hideFireworks,
|
||||
},
|
||||
{
|
||||
value: "Groq",
|
||||
label: "Groq",
|
||||
text: `from langchain_groq import ChatGroq\n\n${llmVarName} = ChatGroq(${groqParamsOrDefault})`,
|
||||
apiKeyName: "GROQ_API_KEY",
|
||||
packageName: "langchain-groq",
|
||||
default: false,
|
||||
shouldHide: hideGroq,
|
||||
},
|
||||
{
|
||||
value: "MistralAI",
|
||||
label: "Mistral AI",
|
||||
text: `from langchain_mistralai import ChatMistralAI\n\n${llmVarName} = ChatMistralAI(${mistralParamsOrDefault})`,
|
||||
apiKeyName: "MISTRAL_API_KEY",
|
||||
packageName: "langchain-mistralai",
|
||||
default: false,
|
||||
shouldHide: hideMistral,
|
||||
},
|
||||
{
|
||||
@@ -260,6 +270,7 @@ export default function ChatModelTabs(props) {
|
||||
text: `from langchain_openai import ChatOpenAI\n\n${llmVarName} = ChatOpenAI(${togetherParamsOrDefault})`,
|
||||
apiKeyName: "TOGETHER_API_KEY",
|
||||
packageName: "langchain-openai",
|
||||
default: false,
|
||||
shouldHide: hideTogether,
|
||||
},
|
||||
{
|
||||
@@ -268,6 +279,7 @@ export default function ChatModelTabs(props) {
|
||||
text: `from databricks_langchain import ChatDatabricks\n\nos.environ["DATABRICKS_HOST"] = "https://example.staging.cloud.databricks.com/serving-endpoints"\n\n${llmVarName} = ChatDatabricks(${databricksParamsOrDefault})`,
|
||||
apiKeyName: "DATABRICKS_TOKEN",
|
||||
packageName: "databricks-langchain",
|
||||
default: false,
|
||||
shouldHide: hideDatabricks,
|
||||
},
|
||||
];
|
||||
|
||||
@@ -27,6 +27,7 @@ const FEATURE_TABLES = {
|
||||
"multimodal": true,
|
||||
"local": false,
|
||||
"apiLink": "https://python.langchain.com/api_reference/anthropic/chat_models/langchain_anthropic.chat_models.ChatAnthropic.html"
|
||||
|
||||
},
|
||||
{
|
||||
"name": "ChatMistralAI",
|
||||
@@ -199,21 +200,21 @@ const FEATURE_TABLES = {
|
||||
"link": "upstage",
|
||||
"structured_output": true,
|
||||
"tool_calling": true,
|
||||
"json_mode": false,
|
||||
"json_mode": false,
|
||||
"multimodal": false,
|
||||
"local": false,
|
||||
"apiLink": "https://python.langchain.com/api_reference/upstage/chat_models/langchain_upstage.chat_models.ChatUpstage.html"
|
||||
},
|
||||
{
|
||||
"name": "ChatDatabricks",
|
||||
"package": "databricks-langchain",
|
||||
"package": "langchain-databricks",
|
||||
"link": "databricks",
|
||||
"structured_output": true,
|
||||
"tool_calling": true,
|
||||
"json_mode": false,
|
||||
"json_mode": false,
|
||||
"multimodal": false,
|
||||
"local": false,
|
||||
"apiLink": "https://api-docs.databricks.com/python/databricks-ai-bridge/latest/databricks_langchain.html#databricks_langchain.ChatDatabricks"
|
||||
"apiLink": "https://python.langchain.com/api_reference/upstage/chat_models/langchain_databricks.chat_models.ChatDatabricks.html"
|
||||
},
|
||||
{
|
||||
"name": "ChatWatsonx",
|
||||
@@ -221,7 +222,7 @@ const FEATURE_TABLES = {
|
||||
"link": "ibm_watsonx",
|
||||
"structured_output": true,
|
||||
"tool_calling": true,
|
||||
"json_mode": true,
|
||||
"json_mode": true,
|
||||
"multimodal": false,
|
||||
"local": false,
|
||||
"apiLink": "https://python.langchain.com/api_reference/ibm/chat_models/langchain_ibm.chat_models.ChatWatsonx.html"
|
||||
@@ -388,8 +389,8 @@ const FEATURE_TABLES = {
|
||||
{
|
||||
name: "Databricks",
|
||||
link: "databricks",
|
||||
package: "databricks-langchain",
|
||||
apiLink: "https://api-docs.databricks.com/python/databricks-ai-bridge/latest/databricks_langchain.html#databricks_langchain.DatabricksEmbeddings"
|
||||
package: "langchain-databricks",
|
||||
apiLink: "https://python.langchain.com/api_reference/nomic/embeddings/langchain_databricks.embeddings.DatabricksEmbeddings.html"
|
||||
},
|
||||
{
|
||||
name: "VoyageAI",
|
||||
@@ -619,6 +620,7 @@ const FEATURE_TABLES = {
|
||||
partnerPackage: false,
|
||||
loaderName: "SharePointLoader",
|
||||
apiLink: "https://python.langchain.com/api_reference/community/document_loaders/langchain_community.document_loaders.sharepoint.SharePointLoader.html"
|
||||
|
||||
},
|
||||
{
|
||||
name: "Tencent COS Directory",
|
||||
@@ -752,6 +754,7 @@ const FEATURE_TABLES = {
|
||||
link: "twitter",
|
||||
loaderName: "TwitterTweetLoader",
|
||||
apiLink: "https://python.langchain.com/api_reference/community/document_loaders/langchain_community.document_loaders.twitter.TwitterTweetLoader.html"
|
||||
|
||||
},
|
||||
{
|
||||
name: "Reddit",
|
||||
@@ -1182,7 +1185,7 @@ const FEATURE_TABLES = {
|
||||
multiTenancy: false,
|
||||
local: false,
|
||||
idsInAddDocuments: false,
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
};
|
||||
|
||||
@@ -3,9 +3,6 @@
|
||||
# LINTING AND FORMATTING
|
||||
######################
|
||||
|
||||
.EXPORT_ALL_VARIABLES:
|
||||
UV_FROZEN = true
|
||||
|
||||
# Define a variable for Python and notebook files.
|
||||
PYTHON_FILES=.
|
||||
MYPY_CACHE=.mypy_cache
|
||||
@@ -16,20 +13,20 @@ lint_tests: PYTHON_FILES=tests
|
||||
lint_tests: MYPY_CACHE=.mypy_cache_test
|
||||
|
||||
lint lint_diff lint_package lint_tests:
|
||||
[ "$(PYTHON_FILES)" = "" ] || uv run --group typing --group lint ruff check $(PYTHON_FILES)
|
||||
[ "$(PYTHON_FILES)" = "" ] || uv run --group typing --group lint ruff format $(PYTHON_FILES) --diff
|
||||
[ "$(PYTHON_FILES)" = "" ] || mkdir -p $(MYPY_CACHE) && uv run --group typing --group lint mypy $(PYTHON_FILES) --cache-dir $(MYPY_CACHE)
|
||||
[ "$(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)" = "" ] || uv run --group typing --group lint ruff format $(PYTHON_FILES)
|
||||
[ "$(PYTHON_FILES)" = "" ] || uv run --group typing --group lint ruff check --select I --fix $(PYTHON_FILES)
|
||||
[ "$(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:
|
||||
uv run --group test pytest tests
|
||||
poetry run pytest tests
|
||||
|
||||
# custom integration testing for cli integration flow
|
||||
# currently ignores vectorstores test because lacks implementation
|
||||
@@ -38,7 +35,7 @@ _e2e_test:
|
||||
mkdir .integration_test
|
||||
cd .integration_test && \
|
||||
python3 -m venv .venv && \
|
||||
pip install --upgrade poetry && \
|
||||
$(PYTHON) -m pip install --upgrade poetry && \
|
||||
$(PYTHON) -m pip install -e .. && \
|
||||
$(PYTHON) -m langchain_cli.cli integration new --name parrot-link --name-class ParrotLink && \
|
||||
$(PYTHON) -m langchain_cli.cli integration new --name parrot-link --name-class ParrotLinkB --src=integration_template/chat_models.py --dst=langchain-parrot-link/langchain_parrot_link/chat_models_b.py && \
|
||||
|
||||
2071
libs/cli/poetry.lock
generated
Normal file
2071
libs/cli/poetry.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,52 +1,48 @@
|
||||
[build-system]
|
||||
requires = ["pdm-backend"]
|
||||
build-backend = "pdm.backend"
|
||||
|
||||
[project]
|
||||
authors = [
|
||||
{name = "Erick Friis", email = "erick@langchain.dev"},
|
||||
]
|
||||
license = {text = "MIT"}
|
||||
requires-python = "<4.0,>=3.9"
|
||||
dependencies = [
|
||||
"typer[all]<1.0.0,>=0.9.0",
|
||||
"gitpython<4,>=3",
|
||||
"langserve[all]>=0.0.51",
|
||||
"uvicorn<1.0,>=0.23",
|
||||
"tomlkit>=0.12",
|
||||
"gritql<1.0.0,>=0.2.0",
|
||||
]
|
||||
[tool.poetry]
|
||||
name = "langchain-cli"
|
||||
version = "0.0.35"
|
||||
description = "CLI for interacting with LangChain"
|
||||
authors = ["Erick Friis <erick@langchain.dev>"]
|
||||
readme = "README.md"
|
||||
repository = "https://github.com/langchain-ai/langchain"
|
||||
license = "MIT"
|
||||
|
||||
[project.urls]
|
||||
[tool.poetry.urls]
|
||||
"Source Code" = "https://github.com/langchain-ai/langchain/tree/master/libs/cli"
|
||||
"Release Notes" = "https://github.com/langchain-ai/langchain/releases?q=tag%3A%22langchain-cli%3D%3D0%22&expanded=true"
|
||||
repository = "https://github.com/langchain-ai/langchain"
|
||||
|
||||
[project.scripts]
|
||||
[tool.poetry.dependencies]
|
||||
python = ">=3.9,<4.0"
|
||||
typer = { extras = ["all"], version = "^0.9.0" }
|
||||
gitpython = "^3"
|
||||
langserve = { extras = ["all"], version = ">=0.0.51" }
|
||||
uvicorn = ">=0.23,<1.0"
|
||||
tomlkit = ">=0.12"
|
||||
gritql = "^0.2.0"
|
||||
|
||||
[tool.poetry.scripts]
|
||||
langchain = "langchain_cli.cli:app"
|
||||
langchain-cli = "langchain_cli.cli:app"
|
||||
|
||||
[dependency-groups]
|
||||
dev = [
|
||||
"pytest<8.0.0,>=7.4.2",
|
||||
"pytest-watch<5.0.0,>=4.2.0",
|
||||
]
|
||||
lint = [
|
||||
"ruff<1.0,>=0.5",
|
||||
"mypy<2.0.0,>=1.13.0",
|
||||
]
|
||||
test = [
|
||||
"langchain @ file:///${PROJECT_ROOT}/../langchain",
|
||||
]
|
||||
typing = [
|
||||
"langchain @ file:///${PROJECT_ROOT}/../langchain",
|
||||
]
|
||||
test_integration = []
|
||||
[tool.poetry.group.dev.dependencies]
|
||||
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]
|
||||
|
||||
[tool.poetry.extras]
|
||||
# For langserve
|
||||
serve = []
|
||||
|
||||
[tool.ruff.lint]
|
||||
select = [
|
||||
@@ -61,3 +57,7 @@ exclude = [
|
||||
"langchain_cli/integration_template",
|
||||
"langchain_cli/package_template",
|
||||
]
|
||||
|
||||
[build-system]
|
||||
requires = ["poetry-core"]
|
||||
build-backend = "poetry.core.masonry.api"
|
||||
|
||||
2014
libs/cli/uv.lock
generated
2014
libs/cli/uv.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -7,31 +7,28 @@ all: help
|
||||
TEST_FILE ?= tests/unit_tests/
|
||||
integration_tests: TEST_FILE = tests/integration_tests/
|
||||
|
||||
.EXPORT_ALL_VARIABLES:
|
||||
UV_FROZEN = true
|
||||
|
||||
# Run unit tests and generate a coverage report.
|
||||
coverage:
|
||||
uv run --group test pytest --cov \
|
||||
poetry run pytest --cov \
|
||||
--cov-config=.coveragerc \
|
||||
--cov-report xml \
|
||||
--cov-report term-missing:skip-covered \
|
||||
$(TEST_FILE)
|
||||
|
||||
test tests:
|
||||
uv run --group test pytest -n auto --disable-socket --allow-unix-socket $(TEST_FILE)
|
||||
poetry run pytest -n auto --disable-socket --allow-unix-socket $(TEST_FILE)
|
||||
|
||||
integration_tests:
|
||||
uv run --group test --group test_integration pytest $(TEST_FILE)
|
||||
poetry run pytest $(TEST_FILE)
|
||||
|
||||
test_watch:
|
||||
uv run --group test ptw --disable-socket --allow-unix-socket --snapshot-update --now . -- -vv tests/unit_tests
|
||||
poetry run ptw --disable-socket --allow-unix-socket --snapshot-update --now . -- -vv tests/unit_tests
|
||||
|
||||
check_imports: $(shell find langchain_community -name '*.py')
|
||||
uv run --group test python ./scripts/check_imports.py $^
|
||||
poetry run python ./scripts/check_imports.py $^
|
||||
|
||||
extended_tests:
|
||||
uv run --no-sync --group test pytest --disable-socket --allow-unix-socket --only-extended tests/unit_tests
|
||||
poetry run pytest --disable-socket --allow-unix-socket --only-extended tests/unit_tests
|
||||
|
||||
|
||||
######################
|
||||
@@ -51,19 +48,19 @@ lint lint_diff lint_package lint_tests:
|
||||
./scripts/check_pydantic.sh .
|
||||
./scripts/lint_imports.sh .
|
||||
./scripts/check_pickle.sh .
|
||||
[ "$(PYTHON_FILES)" = "" ] || uv run --group typing --group lint ruff check $(PYTHON_FILES)
|
||||
[ "$(PYTHON_FILES)" = "" ] || uv run --group typing --group lint ruff format $(PYTHON_FILES) --diff
|
||||
[ "$(PYTHON_FILES)" = "" ] || mkdir -p $(MYPY_CACHE) && uv run --group typing --group lint mypy $(PYTHON_FILES) --cache-dir $(MYPY_CACHE)
|
||||
[ "$(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)" = "" ] || uv run --group typing --group lint ruff format $(PYTHON_FILES)
|
||||
[ "$(PYTHON_FILES)" = "" ] || uv run --group typing --group lint ruff check --select I --fix $(PYTHON_FILES)
|
||||
[ "$(PYTHON_FILES)" = "" ] || poetry run ruff format $(PYTHON_FILES)
|
||||
[ "$(PYTHON_FILES)" = "" ] || poetry run ruff check --select I --fix $(PYTHON_FILES)
|
||||
|
||||
spell_check:
|
||||
uv run --group typing --group lint codespell --toml pyproject.toml
|
||||
poetry run codespell --toml pyproject.toml
|
||||
|
||||
spell_fix:
|
||||
uv run --group typing --group lint codespell --toml pyproject.toml -w
|
||||
poetry run codespell --toml pyproject.toml -w
|
||||
|
||||
######################
|
||||
# HELP
|
||||
|
||||
@@ -59,7 +59,7 @@ openapi-pydantic>=0.3.2,<0.4
|
||||
oracle-ads>=2.9.1,<3
|
||||
oracledb>=2.2.0,<3
|
||||
pandas>=2.0.1,<3
|
||||
pdfminer-six==20231228
|
||||
pdfminer-six>=20221105,<20240706
|
||||
pdfplumber>=0.11
|
||||
pgvector>=0.1.6,<0.2
|
||||
playwright>=1.48.0,<2
|
||||
@@ -104,5 +104,3 @@ mlflow[genai]>=2.14.0
|
||||
databricks-sdk>=0.30.0
|
||||
websocket>=0.2.1,<1
|
||||
writer-sdk>=1.2.0
|
||||
yandexcloud==0.144.0
|
||||
unstructured[pdf]>=0.15
|
||||
|
||||
@@ -10,22 +10,6 @@ from langchain_core.messages import AIMessage
|
||||
from langchain_core.outputs import ChatGeneration, LLMResult
|
||||
|
||||
MODEL_COST_PER_1K_TOKENS = {
|
||||
# OpenAI o1 input
|
||||
"o1": 0.015,
|
||||
"o1-2024-12-17": 0.015,
|
||||
"o1-cached": 0.0075,
|
||||
"o1-2024-12-17-cached": 0.0075,
|
||||
# OpenAI o1 output
|
||||
"o1-completion": 0.06,
|
||||
"o1-2024-12-17-completion": 0.06,
|
||||
# OpenAI o3-mini input
|
||||
"o3-mini": 0.0011,
|
||||
"o3-mini-2025-01-31": 0.0011,
|
||||
"o3-mini-cached": 0.00055,
|
||||
"o3-mini-2025-01-31-cached": 0.00055,
|
||||
# OpenAI o3-mini output
|
||||
"o3-mini-completion": 0.0044,
|
||||
"o3-mini-2025-01-31-completion": 0.0044,
|
||||
# OpenAI o1-preview input
|
||||
"o1-preview": 0.015,
|
||||
"o1-preview-cached": 0.0075,
|
||||
|
||||
@@ -11,7 +11,7 @@ logger = logging.getLogger(__name__)
|
||||
@deprecated(
|
||||
since="0.3.3",
|
||||
removal="1.0",
|
||||
alternative_import="databricks_langchain.ChatDatabricks",
|
||||
alternative_import="langchain_databricks.ChatDatabricks",
|
||||
)
|
||||
class ChatDatabricks(ChatMlflow):
|
||||
"""`Databricks` chat models API.
|
||||
|
||||
@@ -539,8 +539,6 @@ class ChatOCIGenAI(BaseChatModel, OCIGenAIBase):
|
||||
The authentication type to use, e.g., API_KEY (default), SECURITY_TOKEN, INSTANCE_PRINCIPAL, RESOURCE_PRINCIPAL.
|
||||
auth_profile: Optional[str]
|
||||
The name of the profile in ~/.oci/config, if not specified , DEFAULT will be used.
|
||||
auth_file_location: Optional[str]
|
||||
Path to the config file, If not specified, ~/.oci/config will be used.
|
||||
provider: str
|
||||
Provider name of the model. Default to None, will try to be derived from the model_id otherwise, requires user input.
|
||||
See full list of supported init args and their descriptions in the params section.
|
||||
|
||||
@@ -8,12 +8,9 @@ import logging
|
||||
import threading
|
||||
import warnings
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
from tempfile import TemporaryDirectory
|
||||
from typing import (
|
||||
TYPE_CHECKING,
|
||||
Any,
|
||||
BinaryIO,
|
||||
Iterable,
|
||||
Iterator,
|
||||
Literal,
|
||||
@@ -37,6 +34,7 @@ from langchain_community.document_loaders.parsers.images import (
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
import pdfminer
|
||||
import pdfplumber
|
||||
import pymupdf
|
||||
import pypdf
|
||||
@@ -275,6 +273,7 @@ class PyPDFParser(BaseBlobParser):
|
||||
# password = None,
|
||||
mode = "single",
|
||||
pages_delimiter = "\n\f",
|
||||
# extract_images = True,
|
||||
# images_parser = TesseractBlobParser(),
|
||||
)
|
||||
|
||||
@@ -465,336 +464,121 @@ class PyPDFParser(BaseBlobParser):
|
||||
|
||||
|
||||
class PDFMinerParser(BaseBlobParser):
|
||||
"""Parse a blob from a PDF using `pdfminer.six` library.
|
||||
"""Parse `PDF` using `PDFMiner`."""
|
||||
|
||||
This class provides methods to parse a blob from a PDF document, supporting various
|
||||
configurations such as handling password-protected PDFs, extracting images, and
|
||||
defining extraction mode.
|
||||
It integrates the 'pdfminer.six' library for PDF processing and offers synchronous
|
||||
blob parsing.
|
||||
|
||||
Examples:
|
||||
Setup:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
pip install -U langchain-community pdfminer.six pillow
|
||||
|
||||
Load a blob from a PDF file:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from langchain_core.documents.base import Blob
|
||||
|
||||
blob = Blob.from_path("./example_data/layout-parser-paper.pdf")
|
||||
|
||||
Instantiate the parser:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from langchain_community.document_loaders.parsers import PDFMinerParser
|
||||
|
||||
parser = PDFMinerParser(
|
||||
# password = None,
|
||||
mode = "single",
|
||||
pages_delimiter = "\n\f",
|
||||
# extract_images = True,
|
||||
# images_to_text = convert_images_to_text_with_tesseract(),
|
||||
)
|
||||
|
||||
Lazily parse the blob:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
docs = []
|
||||
docs_lazy = parser.lazy_parse(blob)
|
||||
|
||||
for doc in docs_lazy:
|
||||
docs.append(doc)
|
||||
print(docs[0].page_content[:100])
|
||||
print(docs[0].metadata)
|
||||
"""
|
||||
|
||||
_warn_concatenate_pages = False
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
extract_images: bool = False,
|
||||
*,
|
||||
password: Optional[str] = None,
|
||||
mode: Literal["single", "page"] = "single",
|
||||
pages_delimiter: str = _DEFAULT_PAGES_DELIMITER,
|
||||
images_parser: Optional[BaseImageBlobParser] = None,
|
||||
images_inner_format: Literal["text", "markdown-img", "html-img"] = "text",
|
||||
concatenate_pages: Optional[bool] = None,
|
||||
):
|
||||
def __init__(self, extract_images: bool = False, *, concatenate_pages: bool = True):
|
||||
"""Initialize a parser based on PDFMiner.
|
||||
|
||||
Args:
|
||||
password: Optional password for opening encrypted PDFs.
|
||||
mode: Extraction mode to use. Either "single" or "page" for page-wise
|
||||
extraction.
|
||||
pages_delimiter: A string delimiter to separate pages in single-mode
|
||||
extraction.
|
||||
extract_images: Whether to extract images from PDF.
|
||||
images_inner_format: The format for the parsed output.
|
||||
- "text" = return the content as is
|
||||
- "markdown-img" = wrap the content into an image markdown link, w/ link
|
||||
pointing to (`![body)(#)`]
|
||||
- "html-img" = wrap the content as the `alt` text of an tag and link to
|
||||
(`<img alt="{body}" src="#"/>`)
|
||||
concatenate_pages: Deprecated. If True, concatenate all PDF pages
|
||||
into one a single document. Otherwise, return one document per page.
|
||||
|
||||
Returns:
|
||||
This method does not directly return data. Use the `parse` or `lazy_parse`
|
||||
methods to retrieve parsed documents with content and metadata.
|
||||
|
||||
Raises:
|
||||
ValueError: If the `mode` is not "single" or "page".
|
||||
|
||||
Warnings:
|
||||
`concatenate_pages` parameter is deprecated. Use `mode='single' or 'page'
|
||||
instead.
|
||||
concatenate_pages: If True, concatenate all PDF pages into one a single
|
||||
document. Otherwise, return one document per page.
|
||||
"""
|
||||
super().__init__()
|
||||
if mode not in ["single", "page"]:
|
||||
raise ValueError("mode must be single or page")
|
||||
if extract_images and not images_parser:
|
||||
images_parser = RapidOCRBlobParser()
|
||||
self.extract_images = extract_images
|
||||
self.images_parser = images_parser
|
||||
self.images_inner_format = images_inner_format
|
||||
self.password = password
|
||||
self.mode = mode
|
||||
self.pages_delimiter = pages_delimiter
|
||||
if concatenate_pages is not None:
|
||||
if not PDFMinerParser._warn_concatenate_pages:
|
||||
PDFMinerParser._warn_concatenate_pages = True
|
||||
logger.warning(
|
||||
"`concatenate_pages` parameter is deprecated. "
|
||||
"Use `mode='single' or 'page'` instead."
|
||||
)
|
||||
self.mode = "single" if concatenate_pages else "page"
|
||||
|
||||
@staticmethod
|
||||
def decode_text(s: Union[bytes, str]) -> str:
|
||||
"""
|
||||
Decodes a PDFDocEncoding string to Unicode.
|
||||
Adds py3 compatibility to pdfminer's version.
|
||||
|
||||
Args:
|
||||
s: The string to decode.
|
||||
|
||||
Returns:
|
||||
str: The decoded Unicode string.
|
||||
"""
|
||||
from pdfminer.utils import PDFDocEncoding
|
||||
|
||||
if isinstance(s, bytes) and s.startswith(b"\xfe\xff"):
|
||||
return str(s[2:], "utf-16be", "ignore")
|
||||
try:
|
||||
ords = (ord(c) if isinstance(c, str) else c for c in s)
|
||||
return "".join(PDFDocEncoding[o] for o in ords)
|
||||
except IndexError:
|
||||
return str(s)
|
||||
|
||||
@staticmethod
|
||||
def resolve_and_decode(obj: Any) -> Any:
|
||||
"""
|
||||
Recursively resolve the metadata values.
|
||||
|
||||
Args:
|
||||
obj: The object to resolve and decode. It can be of any type.
|
||||
|
||||
Returns:
|
||||
The resolved and decoded object.
|
||||
"""
|
||||
from pdfminer.psparser import PSLiteral
|
||||
|
||||
if hasattr(obj, "resolve"):
|
||||
obj = obj.resolve()
|
||||
if isinstance(obj, list):
|
||||
return list(map(PDFMinerParser.resolve_and_decode, obj))
|
||||
elif isinstance(obj, PSLiteral):
|
||||
return PDFMinerParser.decode_text(obj.name)
|
||||
elif isinstance(obj, (str, bytes)):
|
||||
return PDFMinerParser.decode_text(obj)
|
||||
elif isinstance(obj, dict):
|
||||
for k, v in obj.items():
|
||||
obj[k] = PDFMinerParser.resolve_and_decode(v)
|
||||
return obj
|
||||
|
||||
return obj
|
||||
|
||||
def _get_metadata(
|
||||
self,
|
||||
fp: BinaryIO,
|
||||
password: str = "",
|
||||
caching: bool = True,
|
||||
) -> dict[str, Any]:
|
||||
"""
|
||||
Extract metadata from a PDF file.
|
||||
|
||||
Args:
|
||||
fp: The file pointer to the PDF file.
|
||||
password: The password for the PDF file, if encrypted. Defaults to an empty
|
||||
string.
|
||||
caching: Whether to cache the PDF structure. Defaults to True.
|
||||
|
||||
Returns:
|
||||
Metadata of the PDF file.
|
||||
"""
|
||||
from pdfminer.pdfpage import PDFDocument, PDFPage, PDFParser
|
||||
|
||||
# Create a PDF parser object associated with the file object.
|
||||
parser = PDFParser(fp)
|
||||
# Create a PDF document object that stores the document structure.
|
||||
doc = PDFDocument(parser, password=password, caching=caching)
|
||||
metadata = {}
|
||||
|
||||
for info in doc.info:
|
||||
metadata.update(info)
|
||||
for k, v in metadata.items():
|
||||
try:
|
||||
metadata[k] = PDFMinerParser.resolve_and_decode(v)
|
||||
except Exception as e: # pragma: nocover
|
||||
# This metadata value could not be parsed. Instead of failing the PDF
|
||||
# read, treat it as a warning only if `strict_metadata=False`.
|
||||
logger.warning(
|
||||
'[WARNING] Metadata key "%s" could not be parsed due to '
|
||||
"exception: %s",
|
||||
k,
|
||||
str(e),
|
||||
)
|
||||
|
||||
# Count number of pages.
|
||||
metadata["total_pages"] = len(list(PDFPage.create_pages(doc)))
|
||||
|
||||
return metadata
|
||||
self.concatenate_pages = concatenate_pages
|
||||
|
||||
def lazy_parse(self, blob: Blob) -> Iterator[Document]: # type: ignore[valid-type]
|
||||
"""
|
||||
Lazily parse the blob.
|
||||
Insert image, if possible, between two paragraphs.
|
||||
In this way, a paragraph can be continued on the next page.
|
||||
"""Lazily parse the blob."""
|
||||
|
||||
Args:
|
||||
blob: The blob to parse.
|
||||
if not self.extract_images:
|
||||
try:
|
||||
from pdfminer.high_level import extract_text
|
||||
except ImportError:
|
||||
raise ImportError(
|
||||
"`pdfminer` package not found, please install it with "
|
||||
"`pip install pdfminer.six`"
|
||||
)
|
||||
|
||||
Raises:
|
||||
ImportError: If the `pdfminer.six` or `pillow` package is not found.
|
||||
with blob.as_bytes_io() as pdf_file_obj: # type: ignore[attr-defined]
|
||||
if self.concatenate_pages:
|
||||
text = extract_text(pdf_file_obj)
|
||||
metadata = {"source": blob.source} # type: ignore[attr-defined]
|
||||
yield Document(page_content=text, metadata=metadata)
|
||||
else:
|
||||
from pdfminer.pdfpage import PDFPage
|
||||
|
||||
Yield:
|
||||
An iterator over the parsed documents.
|
||||
"""
|
||||
try:
|
||||
import pdfminer
|
||||
from pdfminer.converter import PDFLayoutAnalyzer
|
||||
from pdfminer.layout import (
|
||||
LAParams,
|
||||
LTContainer,
|
||||
LTImage,
|
||||
LTItem,
|
||||
LTPage,
|
||||
LTText,
|
||||
LTTextBox,
|
||||
)
|
||||
pages = PDFPage.get_pages(pdf_file_obj)
|
||||
for i, _ in enumerate(pages):
|
||||
text = extract_text(pdf_file_obj, page_numbers=[i])
|
||||
metadata = {"source": blob.source, "page": str(i)} # type: ignore[attr-defined]
|
||||
yield Document(page_content=text, metadata=metadata)
|
||||
else:
|
||||
import io
|
||||
|
||||
from pdfminer.converter import PDFPageAggregator, TextConverter
|
||||
from pdfminer.layout import LAParams
|
||||
from pdfminer.pdfinterp import PDFPageInterpreter, PDFResourceManager
|
||||
from pdfminer.pdfpage import PDFPage
|
||||
|
||||
if int(pdfminer.__version__) < 20201018:
|
||||
raise ImportError(
|
||||
"This parser is tested with pdfminer.six version 20201018 or "
|
||||
"later. Remove pdfminer, and install pdfminer.six with "
|
||||
"`pip uninstall pdfminer && pip install pdfminer.six`."
|
||||
)
|
||||
except ImportError:
|
||||
raise ImportError(
|
||||
"pdfminer package not found, please install it "
|
||||
"with `pip install pdfminer.six`"
|
||||
)
|
||||
|
||||
with blob.as_bytes_io() as pdf_file_obj, TemporaryDirectory() as tempdir:
|
||||
pages = PDFPage.get_pages(pdf_file_obj, password=self.password or "")
|
||||
rsrcmgr = PDFResourceManager()
|
||||
doc_metadata = _purge_metadata(
|
||||
self._get_metadata(pdf_file_obj, password=self.password or "")
|
||||
)
|
||||
doc_metadata["source"] = blob.source
|
||||
|
||||
class Visitor(PDFLayoutAnalyzer):
|
||||
def __init__(
|
||||
self,
|
||||
rsrcmgr: PDFResourceManager,
|
||||
pageno: int = 1,
|
||||
laparams: Optional[LAParams] = None,
|
||||
) -> None:
|
||||
super().__init__(rsrcmgr, pageno=pageno, laparams=laparams)
|
||||
|
||||
def receive_layout(me, ltpage: LTPage) -> None:
|
||||
def render(item: LTItem) -> None:
|
||||
if isinstance(item, LTContainer):
|
||||
for child in item:
|
||||
render(child)
|
||||
elif isinstance(item, LTText):
|
||||
text_io.write(item.get_text())
|
||||
if isinstance(item, LTTextBox):
|
||||
text_io.write("\n")
|
||||
elif isinstance(item, LTImage):
|
||||
if self.images_parser:
|
||||
from pdfminer.image import ImageWriter
|
||||
|
||||
image_writer = ImageWriter(tempdir)
|
||||
filename = image_writer.export_image(item)
|
||||
blob = Blob.from_path(Path(tempdir) / filename)
|
||||
blob.metadata["source"] = "#"
|
||||
image_text = next(
|
||||
self.images_parser.lazy_parse(blob)
|
||||
).page_content
|
||||
|
||||
text_io.write(
|
||||
_format_inner_image(
|
||||
blob, image_text, self.images_inner_format
|
||||
)
|
||||
)
|
||||
else:
|
||||
pass
|
||||
|
||||
render(ltpage)
|
||||
|
||||
text_io = io.StringIO()
|
||||
visitor_for_all = PDFPageInterpreter(
|
||||
rsrcmgr, Visitor(rsrcmgr, laparams=LAParams())
|
||||
)
|
||||
all_content = []
|
||||
for i, page in enumerate(pages):
|
||||
text_io.truncate(0)
|
||||
text_io.seek(0)
|
||||
visitor_for_all.process_page(page)
|
||||
|
||||
all_text = text_io.getvalue()
|
||||
# For legacy compatibility, net strip()
|
||||
all_text = all_text.strip()
|
||||
if self.mode == "page":
|
||||
with blob.as_bytes_io() as pdf_file_obj: # type: ignore[attr-defined]
|
||||
pages = PDFPage.get_pages(pdf_file_obj)
|
||||
rsrcmgr = PDFResourceManager()
|
||||
device_for_text = TextConverter(rsrcmgr, text_io, laparams=LAParams())
|
||||
device_for_image = PDFPageAggregator(rsrcmgr, laparams=LAParams())
|
||||
interpreter_for_text = PDFPageInterpreter(rsrcmgr, device_for_text)
|
||||
interpreter_for_image = PDFPageInterpreter(rsrcmgr, device_for_image)
|
||||
for i, page in enumerate(pages):
|
||||
interpreter_for_text.process_page(page)
|
||||
interpreter_for_image.process_page(page)
|
||||
content = text_io.getvalue() + self._extract_images_from_page(
|
||||
device_for_image.get_result()
|
||||
)
|
||||
text_io.truncate(0)
|
||||
text_io.seek(0)
|
||||
yield Document(
|
||||
page_content=all_text,
|
||||
metadata=_validate_metadata(doc_metadata | {"page": i}),
|
||||
)
|
||||
else:
|
||||
if all_text.endswith("\f"):
|
||||
all_text = all_text[:-1]
|
||||
all_content.append(all_text)
|
||||
if self.mode == "single":
|
||||
# Add pages_delimiter between pages
|
||||
document_content = self.pages_delimiter.join(all_content)
|
||||
yield Document(
|
||||
page_content=document_content,
|
||||
metadata=_validate_metadata(doc_metadata),
|
||||
metadata = {"source": blob.source, "page": str(i)} # type: ignore[attr-defined]
|
||||
yield Document(page_content=content, metadata=metadata)
|
||||
|
||||
def _extract_images_from_page(self, page: pdfminer.layout.LTPage) -> str:
|
||||
"""Extract images from page and get the text with RapidOCR."""
|
||||
import pdfminer
|
||||
|
||||
def get_image(layout_object: Any) -> Any:
|
||||
if isinstance(layout_object, pdfminer.layout.LTImage):
|
||||
return layout_object
|
||||
if isinstance(layout_object, pdfminer.layout.LTContainer):
|
||||
for child in layout_object:
|
||||
return get_image(child)
|
||||
else:
|
||||
return None
|
||||
|
||||
images = []
|
||||
|
||||
for img in filter(bool, map(get_image, page)):
|
||||
img_filter = img.stream["Filter"]
|
||||
if isinstance(img_filter, list):
|
||||
filter_names = [f.name for f in img_filter]
|
||||
else:
|
||||
filter_names = [img_filter.name]
|
||||
|
||||
without_loss = any(
|
||||
name in _PDF_FILTER_WITHOUT_LOSS for name in filter_names
|
||||
)
|
||||
with_loss = any(name in _PDF_FILTER_WITH_LOSS for name in filter_names)
|
||||
non_matching = {name for name in filter_names} - {
|
||||
*_PDF_FILTER_WITHOUT_LOSS,
|
||||
*_PDF_FILTER_WITH_LOSS,
|
||||
}
|
||||
|
||||
if without_loss and with_loss:
|
||||
warnings.warn(
|
||||
"Image has both lossy and lossless filters. Defaulting to lossless"
|
||||
)
|
||||
|
||||
if non_matching:
|
||||
warnings.warn(f"Unknown PDF Filter(s): {non_matching}")
|
||||
|
||||
if without_loss:
|
||||
images.append(
|
||||
np.frombuffer(img.stream.get_data(), dtype=np.uint8).reshape(
|
||||
img.stream["Height"], img.stream["Width"], -1
|
||||
)
|
||||
)
|
||||
elif with_loss:
|
||||
images.append(img.stream.get_data())
|
||||
|
||||
return extract_from_images_with_rapidocr(images)
|
||||
|
||||
|
||||
class PyMuPDFParser(BaseBlobParser):
|
||||
"""Parse a blob from a PDF using `PyMuPDF` library.
|
||||
@@ -830,6 +614,7 @@ class PyMuPDFParser(BaseBlobParser):
|
||||
# password = None,
|
||||
mode = "single",
|
||||
pages_delimiter = "\n\f",
|
||||
# extract_images = True,
|
||||
# images_parser = TesseractBlobParser(),
|
||||
# extract_tables="markdown",
|
||||
# extract_tables_settings=None,
|
||||
@@ -1051,9 +836,9 @@ class PyMuPDFParser(BaseBlobParser):
|
||||
Returns:
|
||||
dict: The extracted metadata.
|
||||
"""
|
||||
metadata = _purge_metadata(
|
||||
{
|
||||
**{
|
||||
return _purge_metadata(
|
||||
dict(
|
||||
{
|
||||
"producer": "PyMuPDF",
|
||||
"creator": "PyMuPDF",
|
||||
"creationdate": "",
|
||||
@@ -1066,12 +851,8 @@ class PyMuPDFParser(BaseBlobParser):
|
||||
for k in doc.metadata
|
||||
if isinstance(doc.metadata[k], (str, int))
|
||||
},
|
||||
}
|
||||
)
|
||||
)
|
||||
for k in ("modDate", "creationDate"):
|
||||
if k in doc.metadata:
|
||||
metadata[k] = doc.metadata[k]
|
||||
return metadata
|
||||
|
||||
def _extract_images_from_page(
|
||||
self, doc: pymupdf.Document, page: pymupdf.Page
|
||||
|
||||
@@ -473,122 +473,45 @@ class PyPDFDirectoryLoader(BaseLoader):
|
||||
|
||||
|
||||
class PDFMinerLoader(BasePDFLoader):
|
||||
"""Load and parse a PDF file using 'pdfminer.six' library.
|
||||
|
||||
This class provides methods to load and parse PDF documents, supporting various
|
||||
configurations such as handling password-protected files, extracting images, and
|
||||
defining extraction mode. It integrates the `pdfminer.six` library for PDF
|
||||
processing and offers both synchronous and asynchronous document loading.
|
||||
|
||||
Examples:
|
||||
Setup:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
pip install -U langchain-community pdfminer.six
|
||||
|
||||
Instantiate the loader:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from langchain_community.document_loaders import PDFMinerLoader
|
||||
|
||||
loader = PDFMinerLoader(
|
||||
file_path = "./example_data/layout-parser-paper.pdf",
|
||||
# headers = None
|
||||
# password = None,
|
||||
mode = "single",
|
||||
pages_delimiter = "\n\f",
|
||||
# extract_images = True,
|
||||
# images_to_text = convert_images_to_text_with_tesseract(),
|
||||
)
|
||||
|
||||
Lazy load documents:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
docs = []
|
||||
docs_lazy = loader.lazy_load()
|
||||
|
||||
for doc in docs_lazy:
|
||||
docs.append(doc)
|
||||
print(docs[0].page_content[:100])
|
||||
print(docs[0].metadata)
|
||||
|
||||
Load documents asynchronously:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
docs = await loader.aload()
|
||||
print(docs[0].page_content[:100])
|
||||
print(docs[0].metadata)
|
||||
"""
|
||||
"""Load `PDF` files using `PDFMiner`."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
file_path: Union[str, PurePath],
|
||||
*,
|
||||
password: Optional[str] = None,
|
||||
mode: Literal["single", "page"] = "single",
|
||||
pages_delimiter: str = _DEFAULT_PAGES_DELIMITER,
|
||||
extract_images: bool = False,
|
||||
images_parser: Optional[BaseImageBlobParser] = None,
|
||||
images_inner_format: Literal["text", "markdown-img", "html-img"] = "text",
|
||||
headers: Optional[dict] = None,
|
||||
concatenate_pages: Optional[bool] = None,
|
||||
extract_images: bool = False,
|
||||
concatenate_pages: bool = True,
|
||||
) -> None:
|
||||
"""Initialize with a file path.
|
||||
"""Initialize with file path.
|
||||
|
||||
Args:
|
||||
file_path: The path to the PDF file to be loaded.
|
||||
headers: Optional headers to use for GET request to download a file from a
|
||||
web path.
|
||||
password: Optional password for opening encrypted PDFs.
|
||||
mode: The extraction mode, either "single" for the entire document or "page"
|
||||
for page-wise extraction.
|
||||
pages_delimiter: A string delimiter to separate pages in single-mode
|
||||
extraction.
|
||||
extract_images: Whether to extract images from the PDF.
|
||||
images_parser: Optional image blob parser.
|
||||
images_inner_format: The format for the parsed output.
|
||||
- "text" = return the content as is
|
||||
- "markdown-img" = wrap the content into an image markdown link, w/ link
|
||||
pointing to (`![body)(#)`]
|
||||
- "html-img" = wrap the content as the `alt` text of an tag and link to
|
||||
(`<img alt="{body}" src="#"/>`)
|
||||
concatenate_pages: Deprecated. If True, concatenate all PDF pages into one
|
||||
a single document. Otherwise, return one document per page.
|
||||
|
||||
Returns:
|
||||
This method does not directly return data. Use the `load`, `lazy_load` or
|
||||
`aload` methods to retrieve parsed documents with content and metadata.
|
||||
extract_images: Whether to extract images from PDF.
|
||||
concatenate_pages: If True, concatenate all PDF pages into one a single
|
||||
document. Otherwise, return one document per page.
|
||||
"""
|
||||
try:
|
||||
from pdfminer.high_level import extract_text # noqa:F401
|
||||
except ImportError:
|
||||
raise ImportError(
|
||||
"`pdfminer` package not found, please install it with "
|
||||
"`pip install pdfminer.six`"
|
||||
)
|
||||
|
||||
super().__init__(file_path, headers=headers)
|
||||
self.parser = PDFMinerParser(
|
||||
password=password,
|
||||
extract_images=extract_images,
|
||||
images_parser=images_parser,
|
||||
concatenate_pages=concatenate_pages,
|
||||
mode=mode,
|
||||
pages_delimiter=pages_delimiter,
|
||||
images_inner_format=images_inner_format,
|
||||
extract_images=extract_images, concatenate_pages=concatenate_pages
|
||||
)
|
||||
|
||||
def lazy_load(
|
||||
self,
|
||||
) -> Iterator[Document]:
|
||||
"""
|
||||
Lazy load given path as pages.
|
||||
Insert image, if possible, between two paragraphs.
|
||||
In this way, a paragraph can be continued on the next page.
|
||||
"""
|
||||
"""Lazily load documents."""
|
||||
if self.web_path:
|
||||
blob = Blob.from_data( # type: ignore[attr-defined]
|
||||
open(self.file_path, "rb").read(), path=self.web_path
|
||||
)
|
||||
blob = Blob.from_data(open(self.file_path, "rb").read(), path=self.web_path) # type: ignore[attr-defined]
|
||||
else:
|
||||
blob = Blob.from_path(self.file_path) # type: ignore[attr-defined]
|
||||
yield from self.parser.lazy_parse(blob)
|
||||
yield from self.parser.parse(blob)
|
||||
|
||||
|
||||
class PDFMinerPDFasHTMLLoader(BasePDFLoader):
|
||||
|
||||
@@ -16,7 +16,7 @@ def _chunk(texts: List[str], size: int) -> Iterator[List[str]]:
|
||||
@deprecated(
|
||||
since="0.3.3",
|
||||
removal="1.0",
|
||||
alternative_import="databricks_langchain.DatabricksEmbeddings",
|
||||
alternative_import="langchain_databricks.DatabricksEmbeddings",
|
||||
)
|
||||
class DatabricksEmbeddings(MlflowEmbeddings):
|
||||
"""Databricks embeddings.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import importlib
|
||||
import importlib.metadata
|
||||
from typing import Any, Dict, List, Literal, Optional, Sequence, cast
|
||||
from typing import Any, Dict, List, Literal, Optional, cast
|
||||
|
||||
import numpy as np
|
||||
from langchain_core.embeddings import Embeddings
|
||||
@@ -65,14 +65,6 @@ class FastEmbedEmbeddings(BaseModel, Embeddings):
|
||||
Defaults to `None`.
|
||||
"""
|
||||
|
||||
providers: Optional[Sequence[Any]] = None
|
||||
"""List of ONNX execution providers. Use `["CUDAExecutionProvider"]` to enable the
|
||||
use of GPU when generating embeddings. This requires to install `fastembed-gpu`
|
||||
instead of `fastembed`. See https://qdrant.github.io/fastembed/examples/FastEmbed_GPU
|
||||
for more details.
|
||||
Defaults to `None`.
|
||||
"""
|
||||
|
||||
model: Any = None # : :meta private:
|
||||
|
||||
model_config = ConfigDict(extra="allow", protected_namespaces=())
|
||||
@@ -84,12 +76,6 @@ class FastEmbedEmbeddings(BaseModel, Embeddings):
|
||||
max_length = values.get("max_length")
|
||||
cache_dir = values.get("cache_dir")
|
||||
threads = values.get("threads")
|
||||
providers = values.get("providers")
|
||||
pkg_to_install = (
|
||||
"fastembed-gpu"
|
||||
if providers and "CUDAExecutionProvider" in providers
|
||||
else "fastembed"
|
||||
)
|
||||
|
||||
try:
|
||||
fastembed = importlib.import_module("fastembed")
|
||||
@@ -97,13 +83,12 @@ class FastEmbedEmbeddings(BaseModel, Embeddings):
|
||||
except ModuleNotFoundError:
|
||||
raise ImportError(
|
||||
"Could not import 'fastembed' Python package. "
|
||||
f"Please install it with `pip install {pkg_to_install}`."
|
||||
"Please install it with `pip install fastembed`."
|
||||
)
|
||||
|
||||
if importlib.metadata.version(pkg_to_install) < MIN_VERSION:
|
||||
if importlib.metadata.version("fastembed") < MIN_VERSION:
|
||||
raise ImportError(
|
||||
f"FastEmbedEmbeddings requires "
|
||||
f'`pip install -U "{pkg_to_install}>={MIN_VERSION}"`.'
|
||||
'FastEmbedEmbeddings requires `pip install -U "fastembed>=0.2.0"`.'
|
||||
)
|
||||
|
||||
values["model"] = fastembed.TextEmbedding(
|
||||
@@ -111,7 +96,6 @@ class FastEmbedEmbeddings(BaseModel, Embeddings):
|
||||
max_length=max_length,
|
||||
cache_dir=cache_dir,
|
||||
threads=threads,
|
||||
providers=providers,
|
||||
)
|
||||
return values
|
||||
|
||||
|
||||
@@ -29,9 +29,6 @@ class OCIGenAIEmbeddings(BaseModel, Embeddings):
|
||||
Make sure you have the required policies (profile/roles) to
|
||||
access the OCI Generative AI service. If a specific config profile is used,
|
||||
you must pass the name of the profile (~/.oci/config) through auth_profile.
|
||||
If a specific config file location is used, you must pass
|
||||
the file location where profile name configs present
|
||||
through auth_file_location
|
||||
|
||||
To use, you must provide the compartment id
|
||||
along with the endpoint url, and model id
|
||||
@@ -69,11 +66,6 @@ class OCIGenAIEmbeddings(BaseModel, Embeddings):
|
||||
If not specified , DEFAULT will be used
|
||||
"""
|
||||
|
||||
auth_file_location: Optional[str] = "~/.oci/config"
|
||||
"""Path to the config file.
|
||||
If not specified, ~/.oci/config will be used
|
||||
"""
|
||||
|
||||
model_id: Optional[str] = None
|
||||
"""Id of the model to call, e.g., cohere.embed-english-light-v2.0"""
|
||||
|
||||
@@ -116,8 +108,7 @@ class OCIGenAIEmbeddings(BaseModel, Embeddings):
|
||||
|
||||
if values["auth_type"] == OCIAuthType(1).name:
|
||||
client_kwargs["config"] = oci.config.from_file(
|
||||
file_location=values["auth_file_location"],
|
||||
profile_name=values["auth_profile"],
|
||||
profile_name=values["auth_profile"]
|
||||
)
|
||||
client_kwargs.pop("signer", None)
|
||||
elif values["auth_type"] == OCIAuthType(2).name:
|
||||
@@ -133,8 +124,7 @@ class OCIGenAIEmbeddings(BaseModel, Embeddings):
|
||||
return oci.auth.signers.SecurityTokenSigner(st_string, pk)
|
||||
|
||||
client_kwargs["config"] = oci.config.from_file(
|
||||
file_location=values["auth_file_location"],
|
||||
profile_name=values["auth_profile"],
|
||||
profile_name=values["auth_profile"]
|
||||
)
|
||||
client_kwargs["signer"] = make_security_token_signer(
|
||||
oci_config=client_kwargs["config"]
|
||||
@@ -161,11 +151,11 @@ class OCIGenAIEmbeddings(BaseModel, Embeddings):
|
||||
) from ex
|
||||
except Exception as e:
|
||||
raise ValueError(
|
||||
"""Could not authenticate with OCI client.
|
||||
If INSTANCE_PRINCIPAL or RESOURCE_PRINCIPAL is used,
|
||||
please check the specified
|
||||
auth_profile, auth_file_location and auth_type are valid.""",
|
||||
e,
|
||||
"Could not authenticate with OCI client. "
|
||||
"Please check if ~/.oci/config exists. "
|
||||
"If INSTANCE_PRINCIPLE or RESOURCE_PRINCIPLE is used, "
|
||||
"Please check the specified "
|
||||
"auth_profile and auth_type are valid."
|
||||
) from e
|
||||
|
||||
return values
|
||||
|
||||
@@ -266,7 +266,7 @@ def _pickle_fn_to_hex_string(fn: Callable) -> str:
|
||||
@deprecated(
|
||||
since="0.3.3",
|
||||
removal="1.0",
|
||||
alternative_import="databricks_langchain.ChatDatabricks",
|
||||
alternative_import="langchain_databricks.ChatDatabricks",
|
||||
)
|
||||
class Databricks(LLM):
|
||||
"""Databricks serving endpoint or a cluster driver proxy app for LLM.
|
||||
|
||||
@@ -79,11 +79,6 @@ class OCIGenAIBase(BaseModel, ABC):
|
||||
If not specified , DEFAULT will be used
|
||||
"""
|
||||
|
||||
auth_file_location: Optional[str] = "~/.oci/config"
|
||||
"""Path to the config file.
|
||||
If not specified, ~/.oci/config will be used
|
||||
"""
|
||||
|
||||
model_id: Optional[str] = None
|
||||
"""Id of the model to call, e.g., cohere.command"""
|
||||
|
||||
@@ -130,8 +125,7 @@ class OCIGenAIBase(BaseModel, ABC):
|
||||
|
||||
if values["auth_type"] == OCIAuthType(1).name:
|
||||
client_kwargs["config"] = oci.config.from_file(
|
||||
file_location=values["auth_file_location"],
|
||||
profile_name=values["auth_profile"],
|
||||
profile_name=values["auth_profile"]
|
||||
)
|
||||
client_kwargs.pop("signer", None)
|
||||
elif values["auth_type"] == OCIAuthType(2).name:
|
||||
@@ -147,8 +141,7 @@ class OCIGenAIBase(BaseModel, ABC):
|
||||
return oci.auth.signers.SecurityTokenSigner(st_string, pk)
|
||||
|
||||
client_kwargs["config"] = oci.config.from_file(
|
||||
file_location=values["auth_file_location"],
|
||||
profile_name=values["auth_profile"],
|
||||
profile_name=values["auth_profile"]
|
||||
)
|
||||
client_kwargs["signer"] = make_security_token_signer(
|
||||
oci_config=client_kwargs["config"]
|
||||
@@ -178,10 +171,11 @@ class OCIGenAIBase(BaseModel, ABC):
|
||||
) from ex
|
||||
except Exception as e:
|
||||
raise ValueError(
|
||||
"""Could not authenticate with OCI client.
|
||||
"""Could not authenticate with OCI client.
|
||||
Please check if ~/.oci/config exists.
|
||||
If INSTANCE_PRINCIPAL or RESOURCE_PRINCIPAL is used,
|
||||
please check the specified
|
||||
auth_profile, auth_file_location and auth_type are valid.""",
|
||||
auth_profile and auth_type are valid.""",
|
||||
e,
|
||||
) from e
|
||||
|
||||
@@ -229,9 +223,6 @@ class OCIGenAI(LLM, OCIGenAIBase):
|
||||
access the OCI Generative AI service.
|
||||
If a specific config profile is used, you must pass
|
||||
the name of the profile (from ~/.oci/config) through auth_profile.
|
||||
If a specific config file location is used, you must pass
|
||||
the file location where profile name configs present
|
||||
through auth_file_location
|
||||
|
||||
To use, you must provide the compartment id
|
||||
along with the endpoint url, and model id
|
||||
|
||||
@@ -6,10 +6,10 @@ https://learn.microsoft.com/en-us/graph/auth/
|
||||
|
||||
from datetime import datetime as dt
|
||||
from typing import List, Optional, Type
|
||||
from zoneinfo import ZoneInfo
|
||||
|
||||
from langchain_core.callbacks import CallbackManagerForToolRun
|
||||
from pydantic import BaseModel, Field
|
||||
from zoneinfo import ZoneInfo
|
||||
|
||||
from langchain_community.tools.office365.base import O365BaseTool
|
||||
from langchain_community.tools.office365.utils import UTC_FORMAT
|
||||
|
||||
@@ -789,13 +789,6 @@ class AzureCosmosDBNoSqlVectorSearch(VectorStore):
|
||||
elif isinstance(condition.value, list):
|
||||
# e.g., for IN clauses
|
||||
value = f"({', '.join(map(str, condition.value))})"
|
||||
elif isinstance(condition.value, (int, float, bool)):
|
||||
value = str(condition.value)
|
||||
elif condition.value is None:
|
||||
value = "NULL"
|
||||
else:
|
||||
raise ValueError(f"Unsupported value type: {type(condition.value)}")
|
||||
|
||||
clauses.append(f"c.{condition.property} {sql_operator} {value}")
|
||||
return f""" WHERE {' {} '.format(sql_logical_operator).join(clauses)}""".strip()
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ logger = logging.getLogger(__name__)
|
||||
@deprecated(
|
||||
since="0.3.3",
|
||||
removal="1.0",
|
||||
alternative_import="databricks_langchain.DatabricksVectorSearch",
|
||||
alternative_import="langchain_databricks.DatabricksVectorSearch",
|
||||
)
|
||||
class DatabricksVectorSearch(VectorStore):
|
||||
"""`Databricks Vector Search` vector store.
|
||||
|
||||
@@ -168,7 +168,7 @@ class DeepLake(VectorStore):
|
||||
if _DEEPLAKE_INSTALLED is False:
|
||||
raise ImportError(
|
||||
"Could not import deeplake python package. "
|
||||
"Please install it with `pip install deeplake[enterprise]<4.0.0`."
|
||||
"Please install it with `pip install deeplake[enterprise]`."
|
||||
)
|
||||
|
||||
if (
|
||||
|
||||
4847
libs/community/poetry.lock
generated
Normal file
4847
libs/community/poetry.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -2,91 +2,6 @@
|
||||
requires = ["pdm-backend"]
|
||||
build-backend = "pdm.backend"
|
||||
|
||||
[project]
|
||||
authors = []
|
||||
license = {text = "MIT"}
|
||||
requires-python = "<4.0,>=3.9"
|
||||
dependencies = [
|
||||
"langchain-core<1.0.0,>=0.3.34rc1",
|
||||
"langchain<1.0.0,>=0.3.18rc1",
|
||||
"SQLAlchemy<3,>=1.4",
|
||||
"requests<3,>=2",
|
||||
"PyYAML>=5.3",
|
||||
"aiohttp<4.0.0,>=3.8.3",
|
||||
"tenacity!=8.4.0,<10,>=8.1.0",
|
||||
"dataclasses-json<0.7,>=0.5.7",
|
||||
"pydantic-settings<3.0.0,>=2.4.0",
|
||||
"langsmith<0.4,>=0.1.125",
|
||||
"httpx-sse<1.0.0,>=0.4.0",
|
||||
"numpy<2,>=1.26.4; python_version < \"3.12\"",
|
||||
"numpy<3,>=1.26.2; python_version >= \"3.12\"",
|
||||
]
|
||||
name = "langchain-community"
|
||||
version = "0.3.17rc1"
|
||||
description = "Community contributed LangChain integrations."
|
||||
readme = "README.md"
|
||||
|
||||
[project.urls]
|
||||
"Source Code" = "https://github.com/langchain-ai/langchain/tree/master/libs/community"
|
||||
"Release Notes" = "https://github.com/langchain-ai/langchain/releases?q=tag%3A%22langchain-community%3D%3D0%22&expanded=true"
|
||||
repository = "https://github.com/langchain-ai/langchain"
|
||||
|
||||
[dependency-groups]
|
||||
test = [
|
||||
"pytest<8.0.0,>=7.4.4",
|
||||
"pytest-cov<5.0.0,>=4.1.0",
|
||||
"pytest-dotenv<1.0.0,>=0.5.2",
|
||||
"duckdb-engine<1.0.0,>=0.13.6",
|
||||
"pytest-watcher<1.0.0,>=0.2.6",
|
||||
"freezegun<2.0.0,>=1.2.2",
|
||||
"responses<1.0.0,>=0.22.0",
|
||||
"pytest-asyncio<1.0.0,>=0.20.3",
|
||||
"lark<2.0.0,>=1.1.5",
|
||||
"pandas<3.0.0,>=2.0.0",
|
||||
"pytest-mock<4.0.0,>=3.10.0",
|
||||
"pytest-socket<1.0.0,>=0.6.0",
|
||||
"syrupy<5.0.0,>=4.0.2",
|
||||
"requests-mock<2.0.0,>=1.11.0",
|
||||
"pytest-xdist<4.0.0,>=3.6.1",
|
||||
"cffi<1.17.1; python_version < \"3.10\"",
|
||||
"cffi; python_version >= \"3.10\"",
|
||||
"langchain-core @ file:///${PROJECT_ROOT}/../core",
|
||||
"langchain @ file:///${PROJECT_ROOT}/../langchain",
|
||||
"langchain-tests @ file:///${PROJECT_ROOT}/../standard-tests",
|
||||
"toml>=0.10.2",
|
||||
]
|
||||
codespell = [
|
||||
"codespell<3.0.0,>=2.2.0",
|
||||
]
|
||||
test_integration = [
|
||||
"pytest-vcr<2.0.0,>=1.0.2",
|
||||
"vcrpy<7,>=6",
|
||||
]
|
||||
lint = [
|
||||
"ruff<0.6,>=0.5",
|
||||
"cffi<1.17.1; python_version < \"3.10\"",
|
||||
"cffi; python_version >= \"3.10\"",
|
||||
]
|
||||
dev = [
|
||||
"jupyter<2.0.0,>=1.0.0",
|
||||
"setuptools<68.0.0,>=67.6.1",
|
||||
"langchain-core @ file:///${PROJECT_ROOT}/../core",
|
||||
]
|
||||
typing = [
|
||||
"mypy<2.0,>=1.12",
|
||||
"types-pyyaml<7.0.0.0,>=6.0.12.2",
|
||||
"types-requests<3.0.0.0,>=2.28.11.5",
|
||||
"types-toml<1.0.0.0,>=0.10.8.1",
|
||||
"types-pytz<2024.0.0.0,>=2023.3.0.0",
|
||||
"types-chardet<6.0.0.0,>=5.0.4.6",
|
||||
"types-redis<5.0.0.0,>=4.3.21.6",
|
||||
"mypy-protobuf<4.0.0,>=3.0.0",
|
||||
"langchain-core @ file:///${PROJECT_ROOT}/../core",
|
||||
"langchain-text-splitters @ file:///${PROJECT_ROOT}/../text-splitters",
|
||||
"langchain @ file:///${PROJECT_ROOT}/../langchain",
|
||||
]
|
||||
|
||||
|
||||
[tool.ruff]
|
||||
exclude = [
|
||||
"tests/examples/non-utf8-encoding.py",
|
||||
@@ -122,3 +37,143 @@ filterwarnings = [
|
||||
"ignore::langchain_core._api.deprecation.LangChainDeprecationWarning:test",
|
||||
"ignore::langchain_core._api.deprecation.LangChainPendingDeprecationWarning:test",
|
||||
]
|
||||
|
||||
[tool.pdm.dev-dependencies]
|
||||
test = [
|
||||
"pytest<8.0.0,>=7.4.4",
|
||||
"pytest-cov<5.0.0,>=4.1.0",
|
||||
"pytest-dotenv<1.0.0,>=0.5.2",
|
||||
"duckdb-engine<1.0.0,>=0.13.6",
|
||||
"pytest-watcher<1.0.0,>=0.2.6",
|
||||
"freezegun<2.0.0,>=1.2.2",
|
||||
"responses<1.0.0,>=0.22.0",
|
||||
"pytest-asyncio<1.0.0,>=0.20.3",
|
||||
"lark<2.0.0,>=1.1.5",
|
||||
"pandas<3.0.0,>=2.0.0",
|
||||
"pytest-mock<4.0.0,>=3.10.0",
|
||||
"pytest-socket<1.0.0,>=0.6.0",
|
||||
"syrupy<5.0.0,>=4.0.2",
|
||||
"requests-mock<2.0.0,>=1.11.0",
|
||||
"pytest-xdist<4.0.0,>=3.6.1",
|
||||
"cffi<1.17.1; python_version < \"3.10\"",
|
||||
"cffi; python_version >= \"3.10\"",
|
||||
"langchain-core @ file:///${PROJECT_ROOT}/../core",
|
||||
"langchain @ file:///${PROJECT_ROOT}/../langchain",
|
||||
"langchain-tests @ file:///${PROJECT_ROOT}/../standard-tests",
|
||||
]
|
||||
codespell = [
|
||||
"codespell<3.0.0,>=2.2.0",
|
||||
]
|
||||
test_integration = [
|
||||
"pytest-vcr<2.0.0,>=1.0.2",
|
||||
"vcrpy<7,>=6",
|
||||
]
|
||||
lint = [
|
||||
"ruff<1.0,>=0.5",
|
||||
"cffi<1.17.1; python_version < \"3.10\"",
|
||||
"cffi; python_version >= \"3.10\"",
|
||||
]
|
||||
dev = [
|
||||
"jupyter<2.0.0,>=1.0.0",
|
||||
"setuptools<68.0.0,>=67.6.1",
|
||||
"langchain-core @ file:///${PROJECT_ROOT}/../core",
|
||||
]
|
||||
typing = [
|
||||
"mypy<2.0,>=1.12",
|
||||
"types-pyyaml<7.0.0.0,>=6.0.12.2",
|
||||
"types-requests<3.0.0.0,>=2.28.11.5",
|
||||
"types-toml<1.0.0.0,>=0.10.8.1",
|
||||
"types-pytz<2024.0.0.0,>=2023.3.0.0",
|
||||
"types-chardet<6.0.0.0,>=5.0.4.6",
|
||||
"types-redis<5.0.0.0,>=4.3.21.6",
|
||||
"mypy-protobuf<4.0.0,>=3.0.0",
|
||||
"langchain-core @ file:///${PROJECT_ROOT}/../core",
|
||||
"langchain-text-splitters @ file:///${PROJECT_ROOT}/../text-splitters",
|
||||
"langchain @ file:///${PROJECT_ROOT}/../langchain",
|
||||
]
|
||||
|
||||
[tool.pdm.build]
|
||||
includes = []
|
||||
|
||||
[project]
|
||||
authors = []
|
||||
license = {text = "MIT"}
|
||||
requires-python = "<4.0,>=3.9"
|
||||
dependencies = [
|
||||
"langchain-core<1.0.0,>=0.3.32",
|
||||
"langchain<1.0.0,>=0.3.16",
|
||||
"SQLAlchemy<3,>=1.4",
|
||||
"requests<3,>=2",
|
||||
"PyYAML>=5.3",
|
||||
"aiohttp<4.0.0,>=3.8.3",
|
||||
"tenacity!=8.4.0,<10,>=8.1.0",
|
||||
"dataclasses-json<0.7,>=0.5.7",
|
||||
"pydantic-settings<3.0.0,>=2.4.0",
|
||||
"langsmith<0.4,>=0.1.125",
|
||||
"httpx-sse<1.0.0,>=0.4.0",
|
||||
"numpy<2,>=1.22.4; python_version < \"3.12\"",
|
||||
"numpy<3,>=1.26.2; python_version >= \"3.12\"",
|
||||
]
|
||||
name = "langchain-community"
|
||||
version = "0.3.16"
|
||||
description = "Community contributed LangChain integrations."
|
||||
readme = "README.md"
|
||||
|
||||
[project.urls]
|
||||
"Source Code" = "https://github.com/langchain-ai/langchain/tree/master/libs/community"
|
||||
"Release Notes" = "https://github.com/langchain-ai/langchain/releases?q=tag%3A%22langchain-community%3D%3D0%22&expanded=true"
|
||||
repository = "https://github.com/langchain-ai/langchain"
|
||||
|
||||
[dependency-groups]
|
||||
test = [
|
||||
"pytest<8.0.0,>=7.4.4",
|
||||
"pytest-cov<5.0.0,>=4.1.0",
|
||||
"pytest-dotenv<1.0.0,>=0.5.2",
|
||||
"duckdb-engine<1.0.0,>=0.13.6",
|
||||
"pytest-watcher<1.0.0,>=0.2.6",
|
||||
"freezegun<2.0.0,>=1.2.2",
|
||||
"responses<1.0.0,>=0.22.0",
|
||||
"pytest-asyncio<1.0.0,>=0.20.3",
|
||||
"lark<2.0.0,>=1.1.5",
|
||||
"pandas<3.0.0,>=2.0.0",
|
||||
"pytest-mock<4.0.0,>=3.10.0",
|
||||
"pytest-socket<1.0.0,>=0.6.0",
|
||||
"syrupy<5.0.0,>=4.0.2",
|
||||
"requests-mock<2.0.0,>=1.11.0",
|
||||
"pytest-xdist<4.0.0,>=3.6.1",
|
||||
"cffi<1.17.1; python_version < \"3.10\"",
|
||||
"cffi; python_version >= \"3.10\"",
|
||||
"langchain-core @ file:///${PROJECT_ROOT}/../core",
|
||||
"langchain @ file:///${PROJECT_ROOT}/../langchain",
|
||||
"langchain-tests @ file:///${PROJECT_ROOT}/../standard-tests",
|
||||
]
|
||||
codespell = [
|
||||
"codespell<3.0.0,>=2.2.0",
|
||||
]
|
||||
test_integration = [
|
||||
"pytest-vcr<2.0.0,>=1.0.2",
|
||||
"vcrpy<7,>=6",
|
||||
]
|
||||
lint = [
|
||||
"ruff<1.0,>=0.5",
|
||||
"cffi<1.17.1; python_version < \"3.10\"",
|
||||
"cffi; python_version >= \"3.10\"",
|
||||
]
|
||||
dev = [
|
||||
"jupyter<2.0.0,>=1.0.0",
|
||||
"setuptools<68.0.0,>=67.6.1",
|
||||
"langchain-core @ file:///${PROJECT_ROOT}/../core",
|
||||
]
|
||||
typing = [
|
||||
"mypy<2.0,>=1.12",
|
||||
"types-pyyaml<7.0.0.0,>=6.0.12.2",
|
||||
"types-requests<3.0.0.0,>=2.28.11.5",
|
||||
"types-toml<1.0.0.0,>=0.10.8.1",
|
||||
"types-pytz<2024.0.0.0,>=2023.3.0.0",
|
||||
"types-chardet<6.0.0.0,>=5.0.4.6",
|
||||
"types-redis<5.0.0.0,>=4.3.21.6",
|
||||
"mypy-protobuf<4.0.0,>=3.0.0",
|
||||
"langchain-core @ file:///${PROJECT_ROOT}/../core",
|
||||
"langchain-text-splitters @ file:///${PROJECT_ROOT}/../text-splitters",
|
||||
"langchain @ file:///${PROJECT_ROOT}/../langchain",
|
||||
]
|
||||
|
||||
@@ -11,6 +11,7 @@ from langchain_community.document_loaders.base import BaseBlobParser
|
||||
from langchain_community.document_loaders.blob_loaders import Blob
|
||||
from langchain_community.document_loaders.parsers import (
|
||||
BaseImageBlobParser,
|
||||
PDFMinerParser,
|
||||
PDFPlumberParser,
|
||||
PyPDFium2Parser,
|
||||
)
|
||||
@@ -96,6 +97,12 @@ def _assert_with_duplicate_parser(parser: BaseBlobParser, dedupe: bool = False)
|
||||
assert "11000000 SSeerriieess" == docs[0].page_content.split("\n")[0]
|
||||
|
||||
|
||||
def test_pdfminer_parser() -> None:
|
||||
"""Test PDFMiner parser."""
|
||||
# Does not follow defaults to split by page.
|
||||
_assert_with_parser(PDFMinerParser(), splits_by_page=False)
|
||||
|
||||
|
||||
def test_pypdfium2_parser() -> None:
|
||||
"""Test PyPDFium2 parser."""
|
||||
# Does not follow defaults to split by page.
|
||||
@@ -109,6 +116,11 @@ def test_pdfplumber_parser() -> None:
|
||||
_assert_with_duplicate_parser(PDFPlumberParser(dedupe=True), dedupe=True)
|
||||
|
||||
|
||||
def test_extract_images_text_from_pdf_pdfminerparser() -> None:
|
||||
"""Test extract image from pdf and recognize text with rapid ocr - PDFMinerParser"""
|
||||
_assert_with_parser(PDFMinerParser(extract_images=True))
|
||||
|
||||
|
||||
def test_extract_images_text_from_pdf_pypdfium2parser() -> None:
|
||||
"""Test extract image from pdf and recognize text with rapid ocr - PyPDFium2Parser""" # noqa: E501
|
||||
_assert_with_parser(PyPDFium2Parser(extract_images=True))
|
||||
@@ -126,7 +138,6 @@ class EmptyImageBlobParser(BaseImageBlobParser):
|
||||
@pytest.mark.parametrize(
|
||||
"parser_factory,params",
|
||||
[
|
||||
("PDFMinerParser", {}),
|
||||
("PyMuPDFParser", {}),
|
||||
("PyPDFParser", {"extraction_mode": "plain"}),
|
||||
("PyPDFParser", {"extraction_mode": "layout"}),
|
||||
@@ -155,7 +166,6 @@ def test_mode_and_extract_images_variations(
|
||||
@pytest.mark.parametrize(
|
||||
"parser_factory,params",
|
||||
[
|
||||
("PDFMinerParser", {}),
|
||||
("PyMuPDFParser", {}),
|
||||
("PyPDFParser", {"extraction_mode": "plain"}),
|
||||
("PyPDFParser", {"extraction_mode": "layout"}),
|
||||
|
||||
@@ -8,6 +8,7 @@ import langchain_community.document_loaders as pdf_loaders
|
||||
from langchain_community.document_loaders import (
|
||||
AmazonTextractPDFLoader,
|
||||
MathpixPDFLoader,
|
||||
PDFMinerLoader,
|
||||
PDFMinerPDFasHTMLLoader,
|
||||
PyPDFium2Loader,
|
||||
UnstructuredPDFLoader,
|
||||
@@ -41,6 +42,34 @@ def test_unstructured_pdf_loader_default_mode() -> None:
|
||||
assert len(docs) == 1
|
||||
|
||||
|
||||
def test_pdfminer_loader() -> None:
|
||||
"""Test PDFMiner loader."""
|
||||
file_path = Path(__file__).parent.parent / "examples/hello.pdf"
|
||||
loader = PDFMinerLoader(file_path)
|
||||
docs = loader.load()
|
||||
|
||||
assert len(docs) == 1
|
||||
|
||||
file_path = Path(__file__).parent.parent / "examples/layout-parser-paper.pdf"
|
||||
loader = PDFMinerLoader(file_path)
|
||||
|
||||
docs = loader.load()
|
||||
assert len(docs) == 1
|
||||
|
||||
# Verify that concatenating pages parameter works
|
||||
file_path = Path(__file__).parent.parent / "examples/hello.pdf"
|
||||
loader = PDFMinerLoader(file_path, concatenate_pages=True)
|
||||
docs = loader.load()
|
||||
|
||||
assert len(docs) == 1
|
||||
|
||||
file_path = Path(__file__).parent.parent / "examples/layout-parser-paper.pdf"
|
||||
loader = PDFMinerLoader(file_path, concatenate_pages=False)
|
||||
|
||||
docs = loader.load()
|
||||
assert len(docs) == 16
|
||||
|
||||
|
||||
def test_pdfminer_pdf_as_html_loader() -> None:
|
||||
"""Test PDFMinerPDFasHTMLLoader."""
|
||||
file_path = Path(__file__).parent.parent / "examples/hello.pdf"
|
||||
@@ -182,7 +211,6 @@ def test_amazontextract_loader_failures() -> None:
|
||||
@pytest.mark.parametrize(
|
||||
"parser_factory,params",
|
||||
[
|
||||
("PDFMinerLoader", {}),
|
||||
("PyMuPDFLoader", {}),
|
||||
("PyPDFLoader", {}),
|
||||
],
|
||||
@@ -206,8 +234,6 @@ def test_standard_parameters(
|
||||
images_parser=None,
|
||||
images_inner_format="text",
|
||||
password=None,
|
||||
extract_tables=None,
|
||||
extract_tables_settings=None,
|
||||
)
|
||||
docs = loader.load()
|
||||
assert len(docs) == 16
|
||||
|
||||
@@ -82,7 +82,7 @@ class MockResponse:
|
||||
def raise_for_status(self) -> None:
|
||||
"""Mocked raise for status."""
|
||||
if 400 <= self.status_code < 600:
|
||||
raise HTTPError() # type: ignore[call-arg]
|
||||
raise HTTPError()
|
||||
|
||||
def json(self) -> Dict:
|
||||
"""Returns mocked json data."""
|
||||
|
||||
@@ -50,7 +50,6 @@ def test_yandexgpt_invalid_model_params() -> None:
|
||||
[dict(), dict(disable_request_logging=True), dict(disable_request_logging=False)],
|
||||
)
|
||||
@mock.patch.dict(os.environ, {}, clear=True)
|
||||
@pytest.mark.requires("yandexcloud") # TODO: remove this
|
||||
def test_completion_call(api_key_or_token: dict, disable_logging: dict) -> None:
|
||||
absent_yandex_module_stub = MagicMock()
|
||||
grpc_mock = MagicMock()
|
||||
|
||||
@@ -10,6 +10,7 @@ import langchain_community.document_loaders.parsers as pdf_parsers
|
||||
from langchain_community.document_loaders.base import BaseBlobParser
|
||||
from langchain_community.document_loaders.blob_loaders import Blob
|
||||
from langchain_community.document_loaders.parsers.pdf import (
|
||||
PDFMinerParser,
|
||||
PyPDFium2Parser,
|
||||
_merge_text_and_extras,
|
||||
)
|
||||
@@ -74,6 +75,13 @@ def _assert_with_parser(parser: BaseBlobParser, *, splits_by_page: bool = True)
|
||||
assert int(metadata["page"]) == 0
|
||||
|
||||
|
||||
@pytest.mark.requires("pdfminer")
|
||||
def test_pdfminer_parser() -> None:
|
||||
"""Test PDFMiner parser."""
|
||||
# Does not follow defaults to split by page.
|
||||
_assert_with_parser(PDFMinerParser(), splits_by_page=False)
|
||||
|
||||
|
||||
@pytest.mark.requires("pypdfium2")
|
||||
def test_pypdfium2_parser() -> None:
|
||||
"""Test PyPDFium2 parser."""
|
||||
@@ -84,7 +92,6 @@ def test_pypdfium2_parser() -> None:
|
||||
@pytest.mark.parametrize(
|
||||
"parser_factory,require,params",
|
||||
[
|
||||
("PDFMinerParser", "pdfminer", {"splits_by_page": False}),
|
||||
("PyMuPDFParser", "pymupdf", {}),
|
||||
("PyPDFParser", "pypdf", {}),
|
||||
],
|
||||
|
||||
@@ -50,12 +50,11 @@ async def test_load_mocked_with_filters(expected_documents: List[Document]) -> N
|
||||
mock_collection.find = mock_find
|
||||
mock_collection.count_documents = mock_count_documents
|
||||
|
||||
with (
|
||||
patch("motor.motor_asyncio.AsyncIOMotorClient", return_value=MagicMock()),
|
||||
patch(
|
||||
"langchain_community.document_loaders.mongodb.MongodbLoader.aload",
|
||||
new=mock_async_load,
|
||||
),
|
||||
with patch(
|
||||
"motor.motor_asyncio.AsyncIOMotorClient", return_value=MagicMock()
|
||||
), patch(
|
||||
"langchain_community.document_loaders.mongodb.MongodbLoader.aload",
|
||||
new=mock_async_load,
|
||||
):
|
||||
loader = MongodbLoader(
|
||||
"mongodb://localhost:27017",
|
||||
|
||||
@@ -63,7 +63,7 @@ class MockResponse:
|
||||
def raise_for_status(self) -> None:
|
||||
"""Mocked raise for status."""
|
||||
if 400 <= self.status_code < 600:
|
||||
raise HTTPError() # type: ignore[call-arg]
|
||||
raise HTTPError()
|
||||
|
||||
def json(self) -> Dict:
|
||||
"""Returns mocked json data."""
|
||||
|
||||
@@ -50,7 +50,6 @@ def test_yandexgpt_invalid_model_params() -> None:
|
||||
[dict(), dict(disable_request_logging=True), dict(disable_request_logging=False)],
|
||||
)
|
||||
@mock.patch.dict(os.environ, {}, clear=True)
|
||||
@pytest.mark.requires("yandexcloud") # TODO: remove this
|
||||
def test_completion_call(api_key_or_token: dict, disable_logging: dict) -> None:
|
||||
absent_yandex_module_stub = MagicMock()
|
||||
grpc_mock = MagicMock()
|
||||
|
||||
@@ -30,8 +30,7 @@ from tests.unit_tests.llms.fake_llm import FakeLLM
|
||||
def get_sqlite_cache() -> SQLAlchemyCache:
|
||||
return SQLAlchemyCache(
|
||||
engine=create_engine(
|
||||
"sqlite://",
|
||||
creator=lambda: sqlite3.connect("file::memory:?cache=shared", uri=True),
|
||||
"sqlite://", creator=lambda: sqlite3.connect("file::memory:?cache=shared")
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@ from typing import Any, Dict, Mapping
|
||||
|
||||
import pytest
|
||||
import toml
|
||||
from packaging.requirements import Requirement
|
||||
|
||||
HERE = Path(__file__).parent
|
||||
|
||||
@@ -13,21 +12,30 @@ PYPROJECT_TOML = HERE / "../../pyproject.toml"
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def uv_conf() -> Dict[str, Any]:
|
||||
def poetry_conf() -> Dict[str, Any]:
|
||||
"""Load the pyproject.toml file."""
|
||||
with open(PYPROJECT_TOML) as f:
|
||||
return toml.load(f)
|
||||
return toml.load(f)["tool"]["poetry"]
|
||||
|
||||
|
||||
def test_required_dependencies(uv_conf: Mapping[str, Any]) -> None:
|
||||
def test_required_dependencies(poetry_conf: Mapping[str, Any]) -> None:
|
||||
"""A test that checks if a new non-optional dependency is being introduced.
|
||||
|
||||
If this test is triggered, it means that a contributor is trying to introduce a new
|
||||
required dependency. This should be avoided in most situations.
|
||||
"""
|
||||
# Get the dependencies from the [tool.poetry.dependencies] section
|
||||
dependencies = uv_conf["project"]["dependencies"]
|
||||
required_dependencies = set(Requirement(dep).name for dep in dependencies)
|
||||
dependencies = poetry_conf["dependencies"]
|
||||
|
||||
is_required = {
|
||||
package_name: isinstance(requirements, str)
|
||||
or isinstance(requirements, list)
|
||||
or not requirements.get("optional", False)
|
||||
for package_name, requirements in dependencies.items()
|
||||
}
|
||||
required_dependencies = [
|
||||
package_name for package_name, required in is_required.items() if required
|
||||
]
|
||||
|
||||
assert sorted(required_dependencies) == sorted(
|
||||
[
|
||||
@@ -39,6 +47,7 @@ def test_required_dependencies(uv_conf: Mapping[str, Any]) -> None:
|
||||
"langchain-core",
|
||||
"langsmith",
|
||||
"numpy",
|
||||
"python",
|
||||
"requests",
|
||||
"pydantic-settings",
|
||||
"tenacity",
|
||||
@@ -46,8 +55,16 @@ def test_required_dependencies(uv_conf: Mapping[str, Any]) -> None:
|
||||
]
|
||||
)
|
||||
|
||||
unrequired_dependencies = [
|
||||
package_name for package_name, required in is_required.items() if not required
|
||||
]
|
||||
in_extras = [
|
||||
dep for group in poetry_conf.get("extras", {}).values() for dep in group
|
||||
]
|
||||
assert set(unrequired_dependencies) == set(in_extras)
|
||||
|
||||
def test_test_group_dependencies(uv_conf: Mapping[str, Any]) -> None:
|
||||
|
||||
def test_test_group_dependencies(poetry_conf: Mapping[str, Any]) -> None:
|
||||
"""Check if someone is attempting to add additional test dependencies.
|
||||
|
||||
Only dependencies associated with test running infrastructure should be added
|
||||
@@ -56,10 +73,9 @@ def test_test_group_dependencies(uv_conf: Mapping[str, Any]) -> None:
|
||||
Examples of dependencies that should NOT be included: boto3, azure, postgres, etc.
|
||||
"""
|
||||
|
||||
dependencies = uv_conf["dependency-groups"]["test"]
|
||||
test_group_deps = set(Requirement(dep).name for dep in dependencies)
|
||||
test_group_deps = sorted(poetry_conf["group"]["test"]["dependencies"])
|
||||
|
||||
assert sorted(test_group_deps) == sorted(
|
||||
assert test_group_deps == sorted(
|
||||
[
|
||||
"duckdb-engine",
|
||||
"freezegun",
|
||||
@@ -78,7 +94,6 @@ def test_test_group_dependencies(uv_conf: Mapping[str, Any]) -> None:
|
||||
"pytest-xdist",
|
||||
"responses",
|
||||
"syrupy",
|
||||
"toml",
|
||||
"requests-mock",
|
||||
# TODO: Hack to get around cffi 1.17.1 not working with py3.9, remove when
|
||||
# fix is released.
|
||||
|
||||
@@ -44,12 +44,11 @@ def test_huggingface_tts_constructor() -> None:
|
||||
def test_huggingface_tts_run_with_requests_mock() -> None:
|
||||
os.environ["HUGGINGFACE_API_KEY"] = "foo"
|
||||
|
||||
with (
|
||||
tempfile.TemporaryDirectory() as tmp_dir,
|
||||
patch("uuid.uuid4") as mock_uuid,
|
||||
patch("requests.post") as mock_inference,
|
||||
patch("builtins.open", mock_open()) as mock_file,
|
||||
):
|
||||
with tempfile.TemporaryDirectory() as tmp_dir, patch(
|
||||
"uuid.uuid4"
|
||||
) as mock_uuid, patch("requests.post") as mock_inference, patch(
|
||||
"builtins.open", mock_open()
|
||||
) as mock_file:
|
||||
input_query = "Dummy input"
|
||||
|
||||
mock_uuid_value = uuid.UUID("00000000-0000-0000-0000-000000000000")
|
||||
|
||||
@@ -7,8 +7,8 @@ import pytest
|
||||
from langchain_community.agent_toolkits import PlayWrightBrowserToolkit
|
||||
|
||||
|
||||
@pytest.mark.requires("bs4")
|
||||
@pytest.mark.requires("playwright")
|
||||
@pytest.mark.requires("bs4")
|
||||
def test_playwright_tools_schemas() -> None:
|
||||
"""Test calling 'tool_call_schema' for every tool to check to init issues."""
|
||||
|
||||
|
||||
@@ -220,10 +220,9 @@ def test_ids_used_correctly() -> None:
|
||||
]
|
||||
ids_provided = [i.metadata.get("id") for i in documents]
|
||||
|
||||
with (
|
||||
patch.object(SearchClient, "upload_documents", mock_upload_documents),
|
||||
patch.object(SearchIndexClient, "get_index", mock_default_index),
|
||||
):
|
||||
with patch.object(
|
||||
SearchClient, "upload_documents", mock_upload_documents
|
||||
), patch.object(SearchIndexClient, "get_index", mock_default_index):
|
||||
vector_store = create_vector_store()
|
||||
ids_used_at_upload = vector_store.add_documents(documents, ids=ids_provided)
|
||||
assert len(ids_provided) == len(ids_used_at_upload)
|
||||
|
||||
96
libs/community/uv.lock
generated
96
libs/community/uv.lock
generated
@@ -257,14 +257,15 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "beautifulsoup4"
|
||||
version = "4.12.3"
|
||||
version = "4.13.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "soupsieve" },
|
||||
{ name = "typing-extensions" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/b3/ca/824b1195773ce6166d388573fc106ce56d4a805bd7427b624e063596ec58/beautifulsoup4-4.12.3.tar.gz", hash = "sha256:74e3d1928edc070d21748185c46e3fb33490f22f52a3addee9aee0f4f7781051", size = 581181 }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/58/f3/d90227cc52f7b8fcd0f2af804f56e55edf8dd07036b681a2809e3245318b/beautifulsoup4-4.13.1.tar.gz", hash = "sha256:741c8b6903a1e4ae8ba32b9c9ae7510dab7a197fdbadcf9fcdeb0891ef5ec66a", size = 618295 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/b1/fe/e8c672695b37eecc5cbf43e1d0638d88d66ba3a44c4d321c796f4e59167f/beautifulsoup4-4.12.3-py3-none-any.whl", hash = "sha256:b80878c9f40111313e55da8ba20bdba06d8fa3969fc68304167741bbf9e082ed", size = 147925 },
|
||||
{ url = "https://files.pythonhosted.org/packages/18/75/899bf9b6270b2ce5e8f01b8da121b29e4b88256feb2cf6c6418d4cc42130/beautifulsoup4-4.13.1-py3-none-any.whl", hash = "sha256:72465267014897bb10ca749bb632bde6c2d20f3254afd5458544bd74e6c2e6d8", size = 185056 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1473,7 +1474,7 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "langchain"
|
||||
version = "0.3.18rc1"
|
||||
version = "0.3.17"
|
||||
source = { directory = "../langchain" }
|
||||
dependencies = [
|
||||
{ name = "aiohttp" },
|
||||
@@ -1494,24 +1495,10 @@ dependencies = [
|
||||
requires-dist = [
|
||||
{ name = "aiohttp", specifier = ">=3.8.3,<4.0.0" },
|
||||
{ name = "async-timeout", marker = "python_full_version < '3.11'", specifier = ">=4.0.0,<5.0.0" },
|
||||
{ name = "langchain-anthropic", marker = "extra == 'anthropic'" },
|
||||
{ name = "langchain-aws", marker = "extra == 'aws'" },
|
||||
{ name = "langchain-cohere", marker = "extra == 'cohere'" },
|
||||
{ name = "langchain-community", marker = "extra == 'community'" },
|
||||
{ name = "langchain-core", specifier = ">=0.3.33,<1.0.0" },
|
||||
{ name = "langchain-deepseek", marker = "extra == 'deepseek'" },
|
||||
{ name = "langchain-fireworks", marker = "extra == 'fireworks'" },
|
||||
{ name = "langchain-google-genai", marker = "extra == 'google-genai'" },
|
||||
{ name = "langchain-google-vertexai", marker = "extra == 'google-vertexai'" },
|
||||
{ name = "langchain-groq", marker = "extra == 'groq'" },
|
||||
{ name = "langchain-huggingface", marker = "extra == 'huggingface'" },
|
||||
{ name = "langchain-mistralai", marker = "extra == 'mistralai'" },
|
||||
{ name = "langchain-ollama", marker = "extra == 'ollama'" },
|
||||
{ name = "langchain-openai", marker = "extra == 'openai'" },
|
||||
{ name = "langchain-text-splitters", specifier = ">=0.3.3,<1.0.0" },
|
||||
{ name = "langchain-together", marker = "extra == 'together'" },
|
||||
{ name = "langsmith", specifier = ">=0.1.17,<0.4" },
|
||||
{ name = "numpy", marker = "python_full_version < '3.12'", specifier = ">=1.26.4,<2" },
|
||||
{ name = "numpy", marker = "python_full_version < '3.12'", specifier = ">=1.22.4,<2" },
|
||||
{ name = "numpy", marker = "python_full_version >= '3.12'", specifier = ">=1.26.2,<3" },
|
||||
{ name = "pydantic", specifier = ">=2.7.4,<3.0.0" },
|
||||
{ name = "pyyaml", specifier = ">=5.3" },
|
||||
@@ -1544,7 +1531,6 @@ test = [
|
||||
{ name = "langchain-tests", directory = "../standard-tests" },
|
||||
{ name = "langchain-text-splitters", directory = "../text-splitters" },
|
||||
{ name = "lark", specifier = ">=1.1.5,<2.0.0" },
|
||||
{ name = "packaging", specifier = ">=24.2" },
|
||||
{ name = "pandas", specifier = ">=2.0.0,<3.0.0" },
|
||||
{ name = "pytest", specifier = ">=8,<9" },
|
||||
{ name = "pytest-asyncio", specifier = ">=0.23.2,<1.0.0" },
|
||||
@@ -1557,7 +1543,6 @@ test = [
|
||||
{ name = "requests-mock", specifier = ">=1.11.0,<2.0.0" },
|
||||
{ name = "responses", specifier = ">=0.22.0,<1.0.0" },
|
||||
{ name = "syrupy", specifier = ">=4.0.2,<5.0.0" },
|
||||
{ name = "toml", specifier = ">=0.10.2" },
|
||||
]
|
||||
test-integration = [
|
||||
{ name = "cassio", specifier = ">=0.1.0,<1.0.0" },
|
||||
@@ -1566,7 +1551,6 @@ test-integration = [
|
||||
{ name = "langchainhub", specifier = ">=0.1.16,<1.0.0" },
|
||||
{ name = "pytest-vcr", specifier = ">=1.0.2,<2.0.0" },
|
||||
{ name = "python-dotenv", specifier = ">=1.0.0,<2.0.0" },
|
||||
{ name = "urllib3", marker = "python_full_version < '3.10'", specifier = "<2" },
|
||||
{ name = "wrapt", specifier = ">=1.15.0,<2.0.0" },
|
||||
]
|
||||
typing = [
|
||||
@@ -1584,7 +1568,7 @@ typing = [
|
||||
|
||||
[[package]]
|
||||
name = "langchain-community"
|
||||
version = "0.3.17rc1"
|
||||
version = "0.3.16"
|
||||
source = { editable = "." }
|
||||
dependencies = [
|
||||
{ name = "aiohttp" },
|
||||
@@ -1637,7 +1621,6 @@ test = [
|
||||
{ name = "requests-mock" },
|
||||
{ name = "responses" },
|
||||
{ name = "syrupy" },
|
||||
{ name = "toml" },
|
||||
]
|
||||
test-integration = [
|
||||
{ name = "pytest-vcr" },
|
||||
@@ -1662,10 +1645,10 @@ requires-dist = [
|
||||
{ name = "aiohttp", specifier = ">=3.8.3,<4.0.0" },
|
||||
{ name = "dataclasses-json", specifier = ">=0.5.7,<0.7" },
|
||||
{ name = "httpx-sse", specifier = ">=0.4.0,<1.0.0" },
|
||||
{ name = "langchain", specifier = ">=0.3.18rc1,<1.0.0" },
|
||||
{ name = "langchain-core", specifier = ">=0.3.34rc1,<1.0.0" },
|
||||
{ name = "langchain", specifier = ">=0.3.16,<1.0.0" },
|
||||
{ name = "langchain-core", specifier = ">=0.3.32,<1.0.0" },
|
||||
{ name = "langsmith", specifier = ">=0.1.125,<0.4" },
|
||||
{ name = "numpy", marker = "python_full_version < '3.12'", specifier = ">=1.26.4,<2" },
|
||||
{ name = "numpy", marker = "python_full_version < '3.12'", specifier = ">=1.22.4,<2" },
|
||||
{ name = "numpy", marker = "python_full_version >= '3.12'", specifier = ">=1.26.2,<3" },
|
||||
{ name = "pydantic-settings", specifier = ">=2.4.0,<3.0.0" },
|
||||
{ name = "pyyaml", specifier = ">=5.3" },
|
||||
@@ -1684,7 +1667,7 @@ dev = [
|
||||
lint = [
|
||||
{ name = "cffi", marker = "python_full_version < '3.10'", specifier = "<1.17.1" },
|
||||
{ name = "cffi", marker = "python_full_version >= '3.10'" },
|
||||
{ name = "ruff", specifier = ">=0.5,<0.6" },
|
||||
{ name = "ruff", specifier = ">=0.5,<1.0" },
|
||||
]
|
||||
test = [
|
||||
{ name = "cffi", marker = "python_full_version < '3.10'", specifier = "<1.17.1" },
|
||||
@@ -1707,7 +1690,6 @@ test = [
|
||||
{ name = "requests-mock", specifier = ">=1.11.0,<2.0.0" },
|
||||
{ name = "responses", specifier = ">=0.22.0,<1.0.0" },
|
||||
{ name = "syrupy", specifier = ">=4.0.2,<5.0.0" },
|
||||
{ name = "toml", specifier = ">=0.10.2" },
|
||||
]
|
||||
test-integration = [
|
||||
{ name = "pytest-vcr", specifier = ">=1.0.2,<2.0.0" },
|
||||
@@ -1729,7 +1711,7 @@ typing = [
|
||||
|
||||
[[package]]
|
||||
name = "langchain-core"
|
||||
version = "0.3.34rc1"
|
||||
version = "0.3.33"
|
||||
source = { directory = "../core" }
|
||||
dependencies = [
|
||||
{ name = "jsonpatch" },
|
||||
@@ -1814,14 +1796,14 @@ requires-dist = [
|
||||
|
||||
[[package]]
|
||||
name = "langchain-text-splitters"
|
||||
version = "0.3.6rc1"
|
||||
version = "0.3.5"
|
||||
source = { directory = "../text-splitters" }
|
||||
dependencies = [
|
||||
{ name = "langchain-core" },
|
||||
]
|
||||
|
||||
[package.metadata]
|
||||
requires-dist = [{ name = "langchain-core", specifier = ">=0.3.34rc1,<1.0.0" }]
|
||||
requires-dist = [{ name = "langchain-core", specifier = ">=0.3.29,<1.0.0" }]
|
||||
|
||||
[package.metadata.requires-dev]
|
||||
dev = [
|
||||
@@ -1845,8 +1827,7 @@ test = [
|
||||
test-integration = [
|
||||
{ name = "nltk", specifier = ">=3.9.1,<4.0.0" },
|
||||
{ name = "sentence-transformers", marker = "python_full_version < '3.13'", specifier = ">=2.6.0" },
|
||||
{ name = "spacy", marker = "python_full_version < '3.10'", specifier = ">=3.0.0,<3.8.4" },
|
||||
{ name = "spacy", marker = "python_full_version < '3.13'", specifier = ">=3.0.0,<4.0.0" },
|
||||
{ name = "spacy", marker = "python_full_version < '3.13'" },
|
||||
{ name = "transformers", specifier = ">=4.47.0,<5.0.0" },
|
||||
]
|
||||
typing = [
|
||||
@@ -3385,27 +3366,27 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "ruff"
|
||||
version = "0.5.7"
|
||||
version = "0.9.4"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/bf/2b/69e5e412f9d390adbdbcbf4f64d6914fa61b44b08839a6584655014fc524/ruff-0.5.7.tar.gz", hash = "sha256:8dfc0a458797f5d9fb622dd0efc52d796f23f0a1493a9527f4e49a550ae9a7e5", size = 2449817 }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/c0/17/529e78f49fc6f8076f50d985edd9a2cf011d1dbadb1cdeacc1d12afc1d26/ruff-0.9.4.tar.gz", hash = "sha256:6907ee3529244bb0ed066683e075f09285b38dd5b4039370df6ff06041ca19e7", size = 3599458 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/6b/eb/06e06aaf96af30a68e83b357b037008c54a2ddcbad4f989535007c700394/ruff-0.5.7-py3-none-linux_armv6l.whl", hash = "sha256:548992d342fc404ee2e15a242cdbea4f8e39a52f2e7752d0e4cbe88d2d2f416a", size = 9570571 },
|
||||
{ url = "https://files.pythonhosted.org/packages/a4/10/1be32aeaab8728f78f673e7a47dd813222364479b2d6573dbcf0085e83ea/ruff-0.5.7-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:00cc8872331055ee017c4f1071a8a31ca0809ccc0657da1d154a1d2abac5c0be", size = 8685138 },
|
||||
{ url = "https://files.pythonhosted.org/packages/3d/1d/c218ce83beb4394ba04d05e9aa2ae6ce9fba8405688fe878b0fdb40ce855/ruff-0.5.7-py3-none-macosx_11_0_arm64.whl", hash = "sha256:eaf3d86a1fdac1aec8a3417a63587d93f906c678bb9ed0b796da7b59c1114a1e", size = 8266785 },
|
||||
{ url = "https://files.pythonhosted.org/packages/26/79/7f49509bd844476235b40425756def366b227a9714191c91f02fb2178635/ruff-0.5.7-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a01c34400097b06cf8a6e61b35d6d456d5bd1ae6961542de18ec81eaf33b4cb8", size = 9983964 },
|
||||
{ url = "https://files.pythonhosted.org/packages/bf/b1/939836b70bf9fcd5e5cd3ea67fdb8abb9eac7631351d32f26544034a35e4/ruff-0.5.7-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fcc8054f1a717e2213500edaddcf1dbb0abad40d98e1bd9d0ad364f75c763eea", size = 9359490 },
|
||||
{ url = "https://files.pythonhosted.org/packages/32/7d/b3db19207de105daad0c8b704b2c6f2a011f9c07017bd58d8d6e7b8eba19/ruff-0.5.7-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7f70284e73f36558ef51602254451e50dd6cc479f8b6f8413a95fcb5db4a55fc", size = 10170833 },
|
||||
{ url = "https://files.pythonhosted.org/packages/a2/45/eae9da55f3357a1ac04220230b8b07800bf516e6dd7e1ad20a2ff3b03b1b/ruff-0.5.7-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:a78ad870ae3c460394fc95437d43deb5c04b5c29297815a2a1de028903f19692", size = 10896360 },
|
||||
{ url = "https://files.pythonhosted.org/packages/99/67/4388b36d145675f4c51ebec561fcd4298a0e2550c81e629116f83ce45a39/ruff-0.5.7-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9ccd078c66a8e419475174bfe60a69adb36ce04f8d4e91b006f1329d5cd44bcf", size = 10477094 },
|
||||
{ url = "https://files.pythonhosted.org/packages/e1/9c/f5e6ed1751dc187a4ecf19a4970dd30a521c0ee66b7941c16e292a4043fb/ruff-0.5.7-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7e31c9bad4ebf8fdb77b59cae75814440731060a09a0e0077d559a556453acbb", size = 11480896 },
|
||||
{ url = "https://files.pythonhosted.org/packages/c8/3b/2b683be597bbd02046678fc3fc1c199c641512b20212073b58f173822bb3/ruff-0.5.7-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d796327eed8e168164346b769dd9a27a70e0298d667b4ecee6877ce8095ec8e", size = 10179702 },
|
||||
{ url = "https://files.pythonhosted.org/packages/f1/38/c2d94054dc4b3d1ea4c2ba3439b2a7095f08d1c8184bc41e6abe2a688be7/ruff-0.5.7-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:4a09ea2c3f7778cc635e7f6edf57d566a8ee8f485f3c4454db7771efb692c499", size = 9982855 },
|
||||
{ url = "https://files.pythonhosted.org/packages/7d/e7/1433db2da505ffa8912dcf5b28a8743012ee780cbc20ad0bf114787385d9/ruff-0.5.7-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:a36d8dcf55b3a3bc353270d544fb170d75d2dff41eba5df57b4e0b67a95bb64e", size = 9433156 },
|
||||
{ url = "https://files.pythonhosted.org/packages/e0/36/4fa43250e67741edeea3d366f59a1dc993d4d89ad493a36cbaa9889895f2/ruff-0.5.7-py3-none-musllinux_1_2_i686.whl", hash = "sha256:9369c218f789eefbd1b8d82a8cf25017b523ac47d96b2f531eba73770971c9e5", size = 9782971 },
|
||||
{ url = "https://files.pythonhosted.org/packages/80/0e/8c276103d518e5cf9202f70630aaa494abf6fc71c04d87c08b6d3cd07a4b/ruff-0.5.7-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:b88ca3db7eb377eb24fb7c82840546fb7acef75af4a74bd36e9ceb37a890257e", size = 10247775 },
|
||||
{ url = "https://files.pythonhosted.org/packages/cb/b9/673096d61276f39291b729dddde23c831a5833d98048349835782688a0ec/ruff-0.5.7-py3-none-win32.whl", hash = "sha256:33d61fc0e902198a3e55719f4be6b375b28f860b09c281e4bdbf783c0566576a", size = 7841772 },
|
||||
{ url = "https://files.pythonhosted.org/packages/67/1c/4520c98bfc06b9c73cd1457686d4d3935d40046b1ddea08403e5a6deff51/ruff-0.5.7-py3-none-win_amd64.whl", hash = "sha256:083bbcbe6fadb93cd86709037acc510f86eed5a314203079df174c40bbbca6b3", size = 8699779 },
|
||||
{ url = "https://files.pythonhosted.org/packages/38/23/b3763a237d2523d40a31fe2d1a301191fe392dd48d3014977d079cf8c0bd/ruff-0.5.7-py3-none-win_arm64.whl", hash = "sha256:2dca26154ff9571995107221d0aeaad0e75a77b5a682d6236cf89a58c70b76f4", size = 8091891 },
|
||||
{ url = "https://files.pythonhosted.org/packages/b6/f8/3fafb7804d82e0699a122101b5bee5f0d6e17c3a806dcbc527bb7d3f5b7a/ruff-0.9.4-py3-none-linux_armv6l.whl", hash = "sha256:64e73d25b954f71ff100bb70f39f1ee09e880728efb4250c632ceed4e4cdf706", size = 11668400 },
|
||||
{ url = "https://files.pythonhosted.org/packages/2e/a6/2efa772d335da48a70ab2c6bb41a096c8517ca43c086ea672d51079e3d1f/ruff-0.9.4-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:6ce6743ed64d9afab4fafeaea70d3631b4d4b28b592db21a5c2d1f0ef52934bf", size = 11628395 },
|
||||
{ url = "https://files.pythonhosted.org/packages/dc/d7/cd822437561082f1c9d7225cc0d0fbb4bad117ad7ac3c41cd5d7f0fa948c/ruff-0.9.4-py3-none-macosx_11_0_arm64.whl", hash = "sha256:54499fb08408e32b57360f6f9de7157a5fec24ad79cb3f42ef2c3f3f728dfe2b", size = 11090052 },
|
||||
{ url = "https://files.pythonhosted.org/packages/9e/67/3660d58e893d470abb9a13f679223368ff1684a4ef40f254a0157f51b448/ruff-0.9.4-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:37c892540108314a6f01f105040b5106aeb829fa5fb0561d2dcaf71485021137", size = 11882221 },
|
||||
{ url = "https://files.pythonhosted.org/packages/79/d1/757559995c8ba5f14dfec4459ef2dd3fcea82ac43bc4e7c7bf47484180c0/ruff-0.9.4-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:de9edf2ce4b9ddf43fd93e20ef635a900e25f622f87ed6e3047a664d0e8f810e", size = 11424862 },
|
||||
{ url = "https://files.pythonhosted.org/packages/c0/96/7915a7c6877bb734caa6a2af424045baf6419f685632469643dbd8eb2958/ruff-0.9.4-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:87c90c32357c74f11deb7fbb065126d91771b207bf9bfaaee01277ca59b574ec", size = 12626735 },
|
||||
{ url = "https://files.pythonhosted.org/packages/0e/cc/dadb9b35473d7cb17c7ffe4737b4377aeec519a446ee8514123ff4a26091/ruff-0.9.4-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:56acd6c694da3695a7461cc55775f3a409c3815ac467279dfa126061d84b314b", size = 13255976 },
|
||||
{ url = "https://files.pythonhosted.org/packages/5f/c3/ad2dd59d3cabbc12df308cced780f9c14367f0321e7800ca0fe52849da4c/ruff-0.9.4-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e0c93e7d47ed951b9394cf352d6695b31498e68fd5782d6cbc282425655f687a", size = 12752262 },
|
||||
{ url = "https://files.pythonhosted.org/packages/c7/17/5f1971e54bd71604da6788efd84d66d789362b1105e17e5ccc53bba0289b/ruff-0.9.4-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1d4c8772670aecf037d1bf7a07c39106574d143b26cfe5ed1787d2f31e800214", size = 14401648 },
|
||||
{ url = "https://files.pythonhosted.org/packages/30/24/6200b13ea611b83260501b6955b764bb320e23b2b75884c60ee7d3f0b68e/ruff-0.9.4-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bfc5f1d7afeda8d5d37660eeca6d389b142d7f2b5a1ab659d9214ebd0e025231", size = 12414702 },
|
||||
{ url = "https://files.pythonhosted.org/packages/34/cb/f5d50d0c4ecdcc7670e348bd0b11878154bc4617f3fdd1e8ad5297c0d0ba/ruff-0.9.4-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:faa935fc00ae854d8b638c16a5f1ce881bc3f67446957dd6f2af440a5fc8526b", size = 11859608 },
|
||||
{ url = "https://files.pythonhosted.org/packages/d6/f4/9c8499ae8426da48363bbb78d081b817b0f64a9305f9b7f87eab2a8fb2c1/ruff-0.9.4-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:a6c634fc6f5a0ceae1ab3e13c58183978185d131a29c425e4eaa9f40afe1e6d6", size = 11485702 },
|
||||
{ url = "https://files.pythonhosted.org/packages/18/59/30490e483e804ccaa8147dd78c52e44ff96e1c30b5a95d69a63163cdb15b/ruff-0.9.4-py3-none-musllinux_1_2_i686.whl", hash = "sha256:433dedf6ddfdec7f1ac7575ec1eb9844fa60c4c8c2f8887a070672b8d353d34c", size = 12067782 },
|
||||
{ url = "https://files.pythonhosted.org/packages/3d/8c/893fa9551760b2f8eb2a351b603e96f15af167ceaf27e27ad873570bc04c/ruff-0.9.4-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:d612dbd0f3a919a8cc1d12037168bfa536862066808960e0cc901404b77968f0", size = 12483087 },
|
||||
{ url = "https://files.pythonhosted.org/packages/23/15/f6751c07c21ca10e3f4a51ea495ca975ad936d780c347d9808bcedbd7182/ruff-0.9.4-py3-none-win32.whl", hash = "sha256:db1192ddda2200671f9ef61d9597fcef89d934f5d1705e571a93a67fb13a4402", size = 9852302 },
|
||||
{ url = "https://files.pythonhosted.org/packages/12/41/2d2d2c6a72e62566f730e49254f602dfed23019c33b5b21ea8f8917315a1/ruff-0.9.4-py3-none-win_amd64.whl", hash = "sha256:05bebf4cdbe3ef75430d26c375773978950bbf4ee3c95ccb5448940dc092408e", size = 10850051 },
|
||||
{ url = "https://files.pythonhosted.org/packages/c6/e6/3d6ec3bc3d254e7f005c543a661a41c3e788976d0e52a1ada195bd664344/ruff-0.9.4-py3-none-win_arm64.whl", hash = "sha256:585792f1e81509e38ac5123492f8875fbc36f3ede8185af0a26df348e5154f41", size = 10078251 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3567,15 +3548,6 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/e6/34/ebdc18bae6aa14fbee1a08b63c015c72b64868ff7dae68808ab500c492e2/tinycss2-1.4.0-py3-none-any.whl", hash = "sha256:3a49cf47b7675da0b15d0c6e1df8df4ebd96e9394bb905a5775adb0d884c5289", size = 26610 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.10.2"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/be/ba/1f744cdc819428fc6b5084ec34d9b30660f6f9daaf70eead706e3203ec3c/toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f", size = 22253 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/44/6f/7120676b6d73228c96e17f1f794d8ab046fc910d781c8d151120c3f1569e/toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b", size = 16588 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tomli"
|
||||
version = "2.2.1"
|
||||
|
||||
@@ -6,9 +6,6 @@ all: help
|
||||
# Define a variable for the test file path.
|
||||
TEST_FILE ?= tests/unit_tests/
|
||||
|
||||
.EXPORT_ALL_VARIABLES:
|
||||
UV_FROZEN = true
|
||||
|
||||
test tests:
|
||||
env \
|
||||
-u LANGCHAIN_TRACING_V2 \
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user