Skip to content

Commit d172984

Browse files
authored
infra: migrate to uv (langchain-ai#29566)
1 parent 9da06e6 commit d172984

File tree

168 files changed

+56261
-62294
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

168 files changed

+56261
-62294
lines changed

.github/actions/uv_setup/action.yml

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# TODO: https://docs.astral.sh/uv/guides/integration/github/#caching
2+
3+
name: uv-install
4+
description: Set up Python and uv
5+
6+
inputs:
7+
python-version:
8+
description: Python version, supporting MAJOR.MINOR only
9+
required: true
10+
11+
env:
12+
UV_VERSION: "0.5.25"
13+
14+
runs:
15+
using: composite
16+
steps:
17+
- name: Install uv and set the python version
18+
uses: astral-sh/setup-uv@v5
19+
with:
20+
version: ${{ env.UV_VERSION }}
21+
python-version: ${{ inputs.python-version }}

.github/scripts/check_diff.py

+18-13
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
from pathlib import Path
88
import tomllib
99

10+
from packaging.requirements import Requirement
11+
1012
from get_min_versions import get_min_version_from_toml
1113

1214

@@ -37,6 +39,8 @@
3739

3840
PY_312_MAX_PACKAGES = [
3941
"libs/partners/huggingface", # https://github.com/pytorch/pytorch/issues/130249
42+
"libs/partners/pinecone",
43+
"libs/partners/voyageai",
4044
]
4145

4246

@@ -61,15 +65,17 @@ def dependents_graph() -> dict:
6165

6266
# load regular and test deps from pyproject.toml
6367
with open(path, "rb") as f:
64-
pyproject = tomllib.load(f)["tool"]["poetry"]
68+
pyproject = tomllib.load(f)
6569

6670
pkg_dir = "libs" + "/".join(path.split("libs")[1].split("/")[:-1])
6771
for dep in [
68-
*pyproject["dependencies"].keys(),
69-
*pyproject["group"]["test"]["dependencies"].keys(),
72+
*pyproject["project"]["dependencies"],
73+
*pyproject["dependency-groups"]["test"],
7074
]:
75+
requirement = Requirement(dep)
76+
package_name = requirement.name
7177
if "langchain" in dep:
72-
dependents[dep].add(pkg_dir)
78+
dependents[package_name].add(pkg_dir)
7379
continue
7480

7581
# load extended deps from extended_testing_deps.txt
@@ -120,8 +126,7 @@ def _get_configs_for_single_dir(job: str, dir_: str) -> List[Dict[str, str]]:
120126
py_versions = ["3.9", "3.10", "3.11", "3.12", "3.13"]
121127
# custom logic for specific directories
122128
elif dir_ == "libs/partners/milvus":
123-
# milvus poetry doesn't allow 3.12 because they
124-
# declare deps in funny way
129+
# milvus doesn't allow 3.12 because they declare deps in funny way
125130
py_versions = ["3.9", "3.11"]
126131

127132
elif dir_ in PY_312_MAX_PACKAGES:
@@ -148,17 +153,17 @@ def _get_configs_for_single_dir(job: str, dir_: str) -> List[Dict[str, str]]:
148153
def _get_pydantic_test_configs(
149154
dir_: str, *, python_version: str = "3.11"
150155
) -> List[Dict[str, str]]:
151-
with open("./libs/core/poetry.lock", "rb") as f:
152-
core_poetry_lock_data = tomllib.load(f)
153-
for package in core_poetry_lock_data["package"]:
156+
with open("./libs/core/uv.lock", "rb") as f:
157+
core_uv_lock_data = tomllib.load(f)
158+
for package in core_uv_lock_data["package"]:
154159
if package["name"] == "pydantic":
155160
core_max_pydantic_minor = package["version"].split(".")[1]
156161
break
157162

158-
with open(f"./{dir_}/poetry.lock", "rb") as f:
159-
dir_poetry_lock_data = tomllib.load(f)
163+
with open(f"./{dir_}/uv.lock", "rb") as f:
164+
dir_uv_lock_data = tomllib.load(f)
160165

161-
for package in dir_poetry_lock_data["package"]:
166+
for package in dir_uv_lock_data["package"]:
162167
if package["name"] == "pydantic":
163168
dir_max_pydantic_minor = package["version"].split(".")[1]
164169
break
@@ -304,7 +309,7 @@ def _get_configs_for_multi_dirs(
304309
f"Unknown lib: {file}. check_diff.py likely needs "
305310
"an update for this new library!"
306311
)
307-
elif file.startswith("docs/") or file in ["pyproject.toml", "poetry.lock"]: # docs or root poetry files
312+
elif file.startswith("docs/") or file in ["pyproject.toml", "uv.lock"]: # docs or root uv files
308313
docs_edited = True
309314
dirs_to_run["lint"].add(".")
310315

.github/scripts/check_prerelease_dependencies.py

+5-6
Original file line numberDiff line numberDiff line change
@@ -10,26 +10,25 @@
1010
toml_data = tomllib.load(file)
1111

1212
# see if we're releasing an rc
13-
version = toml_data["tool"]["poetry"]["version"]
13+
version = toml_data["project"]["version"]
1414
releasing_rc = "rc" in version or "dev" in version
1515

1616
# if not, iterate through dependencies and make sure none allow prereleases
1717
if not releasing_rc:
18-
dependencies = toml_data["tool"]["poetry"]["dependencies"]
19-
for lib in dependencies:
20-
dep_version = dependencies[lib]
18+
dependencies = toml_data["project"]["dependencies"]
19+
for dep_version in dependencies:
2120
dep_version_string = (
2221
dep_version["version"] if isinstance(dep_version, dict) else dep_version
2322
)
2423

2524
if "rc" in dep_version_string:
2625
raise ValueError(
27-
f"Dependency {lib} has a prerelease version. Please remove this."
26+
f"Dependency {dep_version} has a prerelease version. Please remove this."
2827
)
2928

3029
if isinstance(dep_version, dict) and dep_version.get(
3130
"allow-prereleases", False
3231
):
3332
raise ValueError(
34-
f"Dependency {lib} has allow-prereleases set to true. Please remove this."
33+
f"Dependency {dep_version} has allow-prereleases set to true. Please remove this."
3534
)

.github/scripts/get_min_versions.py

+28-13
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
from collections import defaultdict
12
import sys
23
from typing import Optional
34

@@ -7,6 +8,7 @@
78
# for python 3.10 and below, which doesnt have stdlib tomllib
89
import tomli as tomllib
910

11+
from packaging.requirements import Requirement
1012
from packaging.specifiers import SpecifierSet
1113
from packaging.version import Version
1214

@@ -94,6 +96,23 @@ def get_minimum_version(package_name: str, spec_string: str) -> Optional[str]:
9496
return str(min(valid_versions)) if valid_versions else None
9597

9698

99+
def _check_python_version_from_requirement(
100+
requirement: Requirement, python_version: str
101+
) -> bool:
102+
if not requirement.marker:
103+
return True
104+
else:
105+
marker_str = str(requirement.marker)
106+
if "python_version" or "python_full_version" in marker_str:
107+
python_version_str = "".join(
108+
char
109+
for char in marker_str
110+
if char.isdigit() or char in (".", "<", ">", "=", ",")
111+
)
112+
return check_python_version(python_version, python_version_str)
113+
return True
114+
115+
97116
def get_min_version_from_toml(
98117
toml_path: str,
99118
versions_for: str,
@@ -105,8 +124,10 @@ def get_min_version_from_toml(
105124
with open(toml_path, "rb") as file:
106125
toml_data = tomllib.load(file)
107126

108-
# Get the dependencies from tool.poetry.dependencies
109-
dependencies = toml_data["tool"]["poetry"]["dependencies"]
127+
dependencies = defaultdict(list)
128+
for dep in toml_data["project"]["dependencies"]:
129+
requirement = Requirement(dep)
130+
dependencies[requirement.name].append(requirement)
110131

111132
# Initialize a dictionary to store the minimum versions
112133
min_versions = {}
@@ -121,17 +142,11 @@ def get_min_version_from_toml(
121142
if lib in dependencies:
122143
if include and lib not in include:
123144
continue
124-
# Get the version string
125-
version_string = dependencies[lib]
126-
127-
if isinstance(version_string, dict):
128-
version_string = version_string["version"]
129-
if isinstance(version_string, list):
130-
version_string = [
131-
vs
132-
for vs in version_string
133-
if check_python_version(python_version, vs["python"])
134-
][0]["version"]
145+
requirements = dependencies[lib]
146+
for requirement in requirements:
147+
if _check_python_version_from_requirement(requirement, python_version):
148+
version_string = str(requirement.specifier)
149+
break
135150

136151
# Use parse_version to get the minimum supported version from version_string
137152
min_version = get_minimum_version(lib, version_string)

.github/workflows/_compile_integration_test.yml

+6-9
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ on:
1313
description: "Python version to use"
1414

1515
env:
16-
POETRY_VERSION: "1.8.4"
16+
UV_FROZEN: "true"
1717

1818
jobs:
1919
build:
@@ -22,25 +22,22 @@ jobs:
2222
working-directory: ${{ inputs.working-directory }}
2323
runs-on: ubuntu-latest
2424
timeout-minutes: 20
25-
name: "poetry run pytest -m compile tests/integration_tests #${{ inputs.python-version }}"
25+
name: "uv run pytest -m compile tests/integration_tests #${{ inputs.python-version }}"
2626
steps:
2727
- uses: actions/checkout@v4
2828

29-
- name: Set up Python ${{ inputs.python-version }} + Poetry ${{ env.POETRY_VERSION }}
30-
uses: "./.github/actions/poetry_setup"
29+
- name: Set up Python ${{ inputs.python-version }} + uv
30+
uses: "./.github/actions/uv_setup"
3131
with:
3232
python-version: ${{ inputs.python-version }}
33-
poetry-version: ${{ env.POETRY_VERSION }}
34-
working-directory: ${{ inputs.working-directory }}
35-
cache-key: compile-integration
3633

3734
- name: Install integration dependencies
3835
shell: bash
39-
run: poetry install --with=test_integration,test
36+
run: uv sync --group test --group test_integration
4037

4138
- name: Check integration tests compile
4239
shell: bash
43-
run: poetry run pytest -m compile tests/integration_tests
40+
run: uv run pytest -m compile tests/integration_tests
4441

4542
- name: Ensure the tests did not create any additional files
4643
shell: bash

.github/workflows/_integration_test.yml

+5-8
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ on:
1212
description: "Python version to use"
1313

1414
env:
15-
POETRY_VERSION: "1.8.4"
15+
UV_FROZEN: "true"
1616

1717
jobs:
1818
build:
@@ -24,22 +24,19 @@ jobs:
2424
steps:
2525
- uses: actions/checkout@v4
2626

27-
- name: Set up Python ${{ inputs.python-version }} + Poetry ${{ env.POETRY_VERSION }}
28-
uses: "./.github/actions/poetry_setup"
27+
- name: Set up Python ${{ inputs.python-version }} + uv
28+
uses: "./.github/actions/uv_setup"
2929
with:
3030
python-version: ${{ inputs.python-version }}
31-
poetry-version: ${{ env.POETRY_VERSION }}
32-
working-directory: ${{ inputs.working-directory }}
33-
cache-key: core
3431

3532
- name: Install dependencies
3633
shell: bash
37-
run: poetry install --with test,test_integration
34+
run: uv sync --group test --group test_integration
3835

3936
- name: Install deps outside pyproject
4037
if: ${{ startsWith(inputs.working-directory, 'libs/community/') }}
4138
shell: bash
42-
run: poetry run pip install "boto3<2" "google-cloud-aiplatform<2"
39+
run: VIRTUAL_ENV=.venv uv pip install "boto3<2" "google-cloud-aiplatform<2"
4340

4441
- name: Run integration tests
4542
shell: bash

.github/workflows/_lint.yml

+7-40
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,13 @@ on:
1313
description: "Python version to use"
1414

1515
env:
16-
POETRY_VERSION: "1.8.4"
1716
WORKDIR: ${{ inputs.working-directory == '' && '.' || inputs.working-directory }}
1817

1918
# This env var allows us to get inline annotations when ruff has complaints.
2019
RUFF_OUTPUT_FORMAT: github
2120

21+
UV_FROZEN: "true"
22+
2223
jobs:
2324
build:
2425
name: "make lint #${{ inputs.python-version }}"
@@ -27,25 +28,10 @@ jobs:
2728
steps:
2829
- uses: actions/checkout@v4
2930

30-
- name: Set up Python ${{ inputs.python-version }} + Poetry ${{ env.POETRY_VERSION }}
31-
uses: "./.github/actions/poetry_setup"
31+
- name: Set up Python ${{ inputs.python-version }} + uv
32+
uses: "./.github/actions/uv_setup"
3233
with:
3334
python-version: ${{ inputs.python-version }}
34-
poetry-version: ${{ env.POETRY_VERSION }}
35-
working-directory: ${{ inputs.working-directory }}
36-
cache-key: lint-with-extras
37-
38-
- name: Check Poetry File
39-
shell: bash
40-
working-directory: ${{ inputs.working-directory }}
41-
run: |
42-
poetry check
43-
44-
- name: Check lock file
45-
shell: bash
46-
working-directory: ${{ inputs.working-directory }}
47-
run: |
48-
poetry lock --check
4935

5036
- name: Install dependencies
5137
# Also installs dev/lint/test/typing dependencies, to ensure we have
@@ -58,17 +44,7 @@ jobs:
5844
# It doesn't matter how you change it, any change will cause a cache-bust.
5945
working-directory: ${{ inputs.working-directory }}
6046
run: |
61-
poetry install --with lint,typing
62-
63-
- name: Get .mypy_cache to speed up mypy
64-
uses: actions/cache@v4
65-
env:
66-
SEGMENT_DOWNLOAD_TIMEOUT_MIN: "2"
67-
with:
68-
path: |
69-
${{ env.WORKDIR }}/.mypy_cache
70-
key: mypy-lint-${{ runner.os }}-${{ runner.arch }}-py${{ inputs.python-version }}-${{ inputs.working-directory }}-${{ hashFiles(format('{0}/poetry.lock', inputs.working-directory)) }}
71-
47+
uv sync --group lint --group typing
7248
7349
- name: Analysing the code with our lint
7450
working-directory: ${{ inputs.working-directory }}
@@ -87,21 +63,12 @@ jobs:
8763
if: ${{ ! startsWith(inputs.working-directory, 'libs/partners/') }}
8864
working-directory: ${{ inputs.working-directory }}
8965
run: |
90-
poetry install --with test
66+
uv sync --group test
9167
- name: Install unit+integration test dependencies
9268
if: ${{ startsWith(inputs.working-directory, 'libs/partners/') }}
9369
working-directory: ${{ inputs.working-directory }}
9470
run: |
95-
poetry install --with test,test_integration
96-
97-
- name: Get .mypy_cache_test to speed up mypy
98-
uses: actions/cache@v4
99-
env:
100-
SEGMENT_DOWNLOAD_TIMEOUT_MIN: "2"
101-
with:
102-
path: |
103-
${{ env.WORKDIR }}/.mypy_cache_test
104-
key: mypy-test-${{ runner.os }}-${{ runner.arch }}-py${{ inputs.python-version }}-${{ inputs.working-directory }}-${{ hashFiles(format('{0}/poetry.lock', inputs.working-directory)) }}
71+
uv sync --group test --group test_integration
10572
10673
- name: Analysing the code with our lint
10774
working-directory: ${{ inputs.working-directory }}

0 commit comments

Comments
 (0)