Sydney Runkle
90b0047270
release(langchain): 1.2.16 ( #37085 )
2026-04-29 17:00:34 -04:00
open-swe[bot]
ba897ffa7e
chore(docs): update x handle references ( #37081 )
...
## Description
Updates package metadata and README badges so LangChain social links
point to the new `@langchain_oss` X handle. This was completed with
AI-agent assistance.
## Test Plan
- [ ] Validate README badges and package metadata links point to
`https://x.com/langchain_oss `
_Opened collaboratively by Mason Daugherty and open-swe._
---------
Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com >
Co-authored-by: Mason Daugherty <61371264+mdrxy@users.noreply.github.com >
2026-04-29 13:56:09 -04:00
Sydney Runkle
3b945d02d9
perf(langchain): stop inlining agent state into tool-dispatch Sends ( #36960 )
...
## Summary
Stop inlining the full agent state into every tool-dispatch `Send` in
`create_agent`. Dispatch with the bare list form `Send("tools",
[tool_call])` and let `ToolNode` hydrate `ToolRuntime.state` from graph
channels at tool-execution time.
**Depends on**
[langchain-ai/langgraph#7594 ](https://github.com/langchain-ai/langgraph/pull/7594 )
which teaches `ToolNode` to read channel state via `CONFIG_KEY_READ`
when given a bare tool-call list. `uv.lock` pins that branch for CI
while the langgraph PR is in flight — this pin will be reverted to a
published `langgraph` version before merge.
## What was happening
Before this change, every pending tool call produced a `Send` whose
payload was:
```python
ToolCallWithContext(
__type="tool_call_with_context",
tool_call=tool_call,
state=state, # ← the FULL agent state dict, including messages list
)
```
For any agent that runs many turns, `state["messages"]` grows linearly
with the conversation. Every super-step that dispatches tools serializes
that whole list into every `Send`, and those Sends live forever in the
checkpointer's `__pregel_tasks` writes. The result is **O(N²)
`__pregel_tasks` storage** across a run.
## What changed
- `libs/langchain_v1/langchain/agents/factory.py`:
- `_make_model_to_tools_edge` now returns `Send("tools", [tool_call])` —
no inlined state.
- Drops the `ToolCallWithContext` import.
- `libs/langchain_v1/pyproject.toml` + `libs/langchain_v1/uv.lock`:
- Temporary `[tool.uv.sources]` pin on `langgraph`,
`langgraph-prebuilt`, `langgraph-checkpoint` to the companion PR branch
so CI exercises both changes end-to-end. Revert after langgraph release.
## Why it's safe
- Same snapshot semantics as before. `Send` is emitted at the end of the
model super-step and consumed at the start of the tools super-step;
channels by that point reflect every write from the model super-step
(including the new AIMessage). Parallel tool tasks all see the same
values since sibling writes don't land until end-of-super-step.
- Legacy `ToolCallWithContext` input path is preserved in `ToolNode` —
no-op for any external caller still constructing it by hand.
## Test plan
- [x] `tests/unit_tests/agents/` — **738 passed, 2 skipped, 1 xfailed**
- [x] `ruff check .` / `ruff format .` — clean
- [x] `mypy langchain/agents/factory.py` — clean
- [x] Before/after benchmark (below)
## Benchmark
Script runs `create_agent` with a mock `GenericFakeChatModel` and two
tools (`write_file`, `edit_file`). Each of the N turns dispatches 2 tool
calls. After the run, the `InMemorySaver` is inspected for bytes stored
under `__pregel_tasks` — the channel that carries the tool-dispatch
`Send` payloads.
| N | TASKS before | TASKS after | ratio |
|---:|---:|---:|---:|
| 5 | 87.6 KB | **4.7 KB** | **18.6× smaller** |
| 10 | 335 KB | **9.4 KB** | **35.7× smaller** |
| 25 | 2.05 MB | **23.7 KB** | **86.5× smaller** |
| 50 | 8.14 MB | **47.6 KB** | **171× smaller** |
| 100 | 32.5 MB | **95.3 KB** | **341× smaller** |
| 200 | 130 MB | **192 KB** | **677× smaller** |
| 500 | 815 MB | **482 KB** | **1,691× smaller** |
**Growth shape:**
- **Before:** per-Send bytes scale with current `messages` length (full
state is inlined), so total TASKS across N turns = Σ(2 × k) for k=1..N ≈
O(N²).
- **After:** per-Send bytes are constant — just the `tool_call` dict.
Total TASKS is O(#dispatches), completely independent of conversation
length. In this bench with ~2 dispatches/turn: **940–964 bytes per turn
across N=5..500, essentially flat.**
An agent that makes 100 tool calls in a single turn pays the same TASKS
cost as one that makes 100 across 50 turns — which is the semantically
correct behavior.
Note: the `messages` channel is unchanged by this PR — it's still the
dominant storage term (growing O(N²) via `add_messages`). TASKS was a
second, compounding cost sitting on top of it; at N=100 it added 40% on
top of `messages`, at N=500 it added 67%. After the fix, TASKS is a
rounding error regardless of N.
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-04-27 13:32:28 -04:00
Mason Daugherty
56d6e89be0
hotfix: bump min core versions ( #36996 )
2026-04-24 15:23:28 -04:00
Mason Daugherty
7e81d09f2a
chore(deps): bump pytest to 9.0.3 ( #36801 )
...
CVE-2025-71176 (medium severity)
All are dev-only (test dependency group) — no impact on published
packages.
### Why syrupy was also bumped
syrupy 4.x (`<5.0.0`) constrains pytest to `<9.0.0`, blocking the CVE
fix. Widening to `<6.0.0` allows syrupy 5.x which supports pytest 9.x.
2026-04-15 21:46:40 -06:00
Eugene Yurtsev
f0c5a28fa0
perf(langchain): add benchmark command ( #36641 )
...
add benchmark in Makefile
2026-04-09 16:05:17 -04:00
Sydney Runkle
dd637313c9
release: langchain v1.2.15 ( #36496 )
2026-04-03 10:22:54 -04:00
Eugene Yurtsev
90087ce6bf
release(langchain): 1.2.14 ( #36396 )
...
Release 1.2.14
2026-03-31 09:47:35 -04:00
John Kennedy
0f4f3f74c8
chore: pygments>=2.20.0 across all packages (CVE-2026-4539) ( #36385 )
...
## Summary
Bumps `pygments` to `>=2.20.0` across all 21 affected packages to
address [CVE-2026-4539](https://github.com/advisories/GHSA-XXXX ) — ReDoS
via inefficient GUID regex in Pygments.
- **Severity:** Low
- **Fixed in:** 2.20.0 (was 2.19.2)
- **Change:** Added `pygments>=2.20.0` to `constraint-dependencies` in
`[tool.uv]` for each package, then ran `uv lock --upgrade-package
pygments` to regenerate lock files.
Closes Dependabot alerts #3435–#3455.
## Release Note
Patch deps
### Test Plan
- [x] CI Green 🙏
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-03-30 23:26:59 -04:00
Mason Daugherty
d1e5bd6274
release(langchain): 1.2.13 ( #36111 )
2026-03-19 13:12:37 -04:00
Sydney Runkle
2a137bf491
release(langchain_v1): 1.2.12 ( #35770 )
2026-03-11 22:18:08 +00:00
Sydney Runkle
057c484ba2
release(langchain_v1): 1.2.11 ( #35723 )
2026-03-10 19:38:33 +00:00
Christophe Bornet
6a6ef8caad
style: fix some ruff noqa ( #35321 )
2026-02-19 13:19:30 -05:00
Christophe Bornet
b97c629f9a
style: bump ruff version to 0.15 ( #35042 )
2026-02-12 19:34:02 -05:00
ccurme
74dffca3d8
release(langchain): 1.2.10 ( #35137 )
2026-02-10 09:53:54 -05:00
dependabot[bot]
7e4536cf85
chore(deps): bump the langchain-deps group across 3 directories with 11 updates ( #35121 )
...
Updates the requirements on [ruff](https://github.com/astral-sh/ruff ),
[setuptools](https://github.com/pypa/setuptools ),
[pytest](https://github.com/pytest-dev/pytest ),
[syrupy](https://github.com/syrupy-project/syrupy ),
[pytest-asyncio](https://github.com/pytest-dev/pytest-asyncio ),
[packaging](https://github.com/pypa/packaging ),
[pytest-cov](https://github.com/pytest-dev/pytest-cov ),
[wrapt](https://github.com/GrahamDumpleton/wrapt ),
[mypy-protobuf](https://github.com/nipunn1313/mypy-protobuf ),
[types-pytz](https://github.com/typeshed-internal/stub_uploader ) and
[aiosqlite](https://github.com/omnilib/aiosqlite ) to permit the latest
version.
Updates `ruff` to 0.15.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/astral-sh/ruff/releases ">ruff's
releases</a>.</em></p>
<blockquote>
<h2>0.15.0</h2>
<h2>Release Notes</h2>
<p>Released on 2026-02-03.</p>
<p>Check out the <a href="https://astral.sh/blog/ruff-v0.15.0 ">blog
post</a> for a migration guide and overview of the changes!</p>
<h3>Breaking changes</h3>
<ul>
<li>
<p>Ruff now formats your code according to the 2026 style guide. See the
formatter section below or in the blog post for a detailed list of
changes.</p>
</li>
<li>
<p>The linter now supports block suppression comments. For example, to
suppress <code>N803</code> for all parameters in this function:</p>
<pre lang="python"><code># ruff: disable[N803]
def foo(
legacyArg1,
legacyArg2,
legacyArg3,
legacyArg4,
): ...
# ruff: enable[N803]
</code></pre>
<p>See the <a
href="https://docs.astral.sh/ruff/linter/#block-level ">documentation</a>
for more details.</p>
</li>
<li>
<p>The <code>ruff:alpine</code> Docker image is now based on Alpine 3.23
(up from 3.21).</p>
</li>
<li>
<p>The <code>ruff:debian</code> and <code>ruff:debian-slim</code> Docker
images are now based on Debian 13 "Trixie" instead of Debian
12 "Bookworm."</p>
</li>
<li>
<p>Binaries for the <code>ppc64</code> (64-bit big-endian PowerPC)
architecture are no longer included in our releases. It should still be
possible to build Ruff manually for this platform, if needed.</p>
</li>
<li>
<p>Ruff now resolves all <code>extend</code>ed configuration files
before falling back on a default Python version.</p>
</li>
</ul>
<h3>Stabilization</h3>
<p>The following rules have been stabilized and are no longer in
preview:</p>
<ul>
<li><a
href="https://docs.astral.sh/ruff/rules/blocking-http-call-httpx-in-async-function "><code>blocking-http-call-httpx-in-async-function</code></a>
(<code>ASYNC212</code>)</li>
<li><a
href="https://docs.astral.sh/ruff/rules/blocking-path-method-in-async-function "><code>blocking-path-method-in-async-function</code></a>
(<code>ASYNC240</code>)</li>
<li><a
href="https://docs.astral.sh/ruff/rules/blocking-input-in-async-function "><code>blocking-input-in-async-function</code></a>
(<code>ASYNC250</code>)</li>
<li><a
href="https://docs.astral.sh/ruff/rules/map-without-explicit-strict "><code>map-without-explicit-strict</code></a>
(<code>B912</code>)</li>
<li><a
href="https://docs.astral.sh/ruff/rules/if-exp-instead-of-or-operator "><code>if-exp-instead-of-or-operator</code></a>
(<code>FURB110</code>)</li>
<li><a
href="https://docs.astral.sh/ruff/rules/single-item-membership-test "><code>single-item-membership-test</code></a>
(<code>FURB171</code>)</li>
<li><a
href="https://docs.astral.sh/ruff/rules/missing-maxsplit-arg "><code>missing-maxsplit-arg</code></a>
(<code>PLC0207</code>)</li>
<li><a
href="https://docs.astral.sh/ruff/rules/unnecessary-lambda "><code>unnecessary-lambda</code></a>
(<code>PLW0108</code>)</li>
<li><a
href="https://docs.astral.sh/ruff/rules/unnecessary-empty-iterable-within-deque-call "><code>unnecessary-empty-iterable-within-deque-call</code></a>
(<code>RUF037</code>)</li>
<li><a
href="https://docs.astral.sh/ruff/rules/in-empty-collection "><code>in-empty-collection</code></a>
(<code>RUF060</code>)</li>
<li><a
href="https://docs.astral.sh/ruff/rules/legacy-form-pytest-raises "><code>legacy-form-pytest-raises</code></a>
(<code>RUF061</code>)</li>
<li><a
href="https://docs.astral.sh/ruff/rules/non-octal-permissions "><code>non-octal-permissions</code></a>
(<code>RUF064</code>)</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md ">ruff's
changelog</a>.</em></p>
<blockquote>
<h2>0.15.0</h2>
<p>Released on 2026-02-03.</p>
<p>Check out the <a href="https://astral.sh/blog/ruff-v0.15.0 ">blog
post</a> for a migration
guide and overview of the changes!</p>
<h3>Breaking changes</h3>
<ul>
<li>
<p>Ruff now formats your code according to the 2026 style guide. See the
formatter section below or in the blog post for a detailed list of
changes.</p>
</li>
<li>
<p>The linter now supports block suppression comments. For example, to
suppress <code>N803</code> for all parameters in this function:</p>
<pre lang="python"><code># ruff: disable[N803]
def foo(
legacyArg1,
legacyArg2,
legacyArg3,
legacyArg4,
): ...
# ruff: enable[N803]
</code></pre>
<p>See the <a
href="https://docs.astral.sh/ruff/linter/#block-level ">documentation</a>
for more details.</p>
</li>
<li>
<p>The <code>ruff:alpine</code> Docker image is now based on Alpine 3.23
(up from 3.21).</p>
</li>
<li>
<p>The <code>ruff:debian</code> and <code>ruff:debian-slim</code> Docker
images are now based on Debian 13 "Trixie" instead of Debian
12 "Bookworm."</p>
</li>
<li>
<p>Binaries for the <code>ppc64</code> (64-bit big-endian PowerPC)
architecture are no longer included in our releases. It should still be
possible to build Ruff manually for this platform, if needed.</p>
</li>
<li>
<p>Ruff now resolves all <code>extend</code>ed configuration files
before falling back on a default Python version.</p>
</li>
</ul>
<h3>Stabilization</h3>
<p>The following rules have been stabilized and are no longer in
preview:</p>
<ul>
<li><a
href="https://docs.astral.sh/ruff/rules/blocking-http-call-httpx-in-async-function "><code>blocking-http-call-httpx-in-async-function</code></a>
(<code>ASYNC212</code>)</li>
<li><a
href="https://docs.astral.sh/ruff/rules/blocking-path-method-in-async-function "><code>blocking-path-method-in-async-function</code></a>
(<code>ASYNC240</code>)</li>
<li><a
href="https://docs.astral.sh/ruff/rules/blocking-input-in-async-function "><code>blocking-input-in-async-function</code></a>
(<code>ASYNC250</code>)</li>
<li><a
href="https://docs.astral.sh/ruff/rules/map-without-explicit-strict "><code>map-without-explicit-strict</code></a>
(<code>B912</code>)</li>
<li><a
href="https://docs.astral.sh/ruff/rules/if-exp-instead-of-or-operator "><code>if-exp-instead-of-or-operator</code></a>
(<code>FURB110</code>)</li>
<li><a
href="https://docs.astral.sh/ruff/rules/single-item-membership-test "><code>single-item-membership-test</code></a>
(<code>FURB171</code>)</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="ce5f7b6127 "><code>ce5f7b6</code></a>
Bump 0.15.0 (<a
href="https://redirect.github.com/astral-sh/ruff/issues/23055 ">#23055</a>)</li>
<li><a
href="b4e40f539c "><code>b4e40f5</code></a>
[ty] Fix <code>__contains__</code> to respect descriptors (<a
href="https://redirect.github.com/astral-sh/ruff/issues/23056 ">#23056</a>)</li>
<li><a
href="848cb72dc1 "><code>848cb72</code></a>
[ty] Fix narrowing of nonlocal variables with conditional assignments
(<a
href="https://redirect.github.com/astral-sh/ruff/issues/22966 ">#22966</a>)</li>
<li><a
href="da7f33af22 "><code>da7f33a</code></a>
[ty] Add a diagnostic for <code>Final</code> without assignment (<a
href="https://redirect.github.com/astral-sh/ruff/issues/23001 ">#23001</a>)</li>
<li><a
href="e65f9a6b03 "><code>e65f9a6</code></a>
Document markdown formatting feature (<a
href="https://redirect.github.com/astral-sh/ruff/issues/22990 ">#22990</a>)</li>
<li><a
href="c0c1b985c9 "><code>c0c1b98</code></a>
Format markdown code blocks with line-by-line regex parse (<a
href="https://redirect.github.com/astral-sh/ruff/issues/22996 ">#22996</a>)</li>
<li><a
href="9f8f3e196b "><code>9f8f3e1</code></a>
Allow positional-only params with defaults in method overrides (<a
href="https://redirect.github.com/astral-sh/ruff/issues/23037 ">#23037</a>)</li>
<li><a
href="ef83810e11 "><code>ef83810</code></a>
[ty] ecosystem-analyzer: Support bare git repositories (<a
href="https://redirect.github.com/astral-sh/ruff/issues/23054 ">#23054</a>)</li>
<li><a
href="54dfee4cb8 "><code>54dfee4</code></a>
Customize where the <code>fix_title</code> sub-diagnostic appears (<a
href="https://redirect.github.com/astral-sh/ruff/issues/23044 ">#23044</a>)</li>
<li><a
href="b53460799b "><code>b534607</code></a>
2026 Ruff Formatter Style (<a
href="https://redirect.github.com/astral-sh/ruff/issues/22735 ">#22735</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/astral-sh/ruff/compare/0.14.11...0.15.0 ">compare
view</a></li>
</ul>
</details>
<br />
Updates `setuptools` to 82.0.0
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/pypa/setuptools/blob/main/NEWS.rst ">setuptools's
changelog</a>.</em></p>
<blockquote>
<h1>v82.0.0</h1>
<h2>Deprecations and Removals</h2>
<ul>
<li><code>pkg_resources</code> has been removed from Setuptools. Most
common uses of <code>pkg_resources</code> have been superseded by the
<code>importlib.resources
<https://docs.python.org/3/library/importlib.resources.html> ;</code>_
and <code>importlib.metadata
<https://docs.python.org/3/library/importlib.metadata.html> ;</code>_
projects. Projects and environments relying on
<code>pkg_resources</code> for namespace packages or other behavior
should depend on older versions of <code>setuptools</code>. (<a
href="https://redirect.github.com/pypa/setuptools/issues/3085 ">#3085</a>)</li>
</ul>
<h1>v81.0.0</h1>
<h2>Deprecations and Removals</h2>
<ul>
<li>Removed support for the --dry-run parameter to setup.py. This one
feature by its nature threads through lots of core and ancillary
functionality, adding complexity and friction. Removal of this parameter
will help decouple the compiler functionality from distutils and thus
the eventual full integration of distutils. These changes do affect some
class and function signatures, so any derivative functionality may
require some compatibility shims to support their expected interface.
Please report any issues to the Setuptools project for investigation.
(<a
href="https://redirect.github.com/pypa/setuptools/issues/4872 ">#4872</a>)</li>
</ul>
<h1>v80.10.2</h1>
<h2>Bugfixes</h2>
<ul>
<li>Update vendored dependencies. (<a
href="https://redirect.github.com/pypa/setuptools/issues/5159 ">#5159</a>)</li>
</ul>
<h2>Misc</h2>
<ul>
<li><a
href="https://redirect.github.com/pypa/setuptools/issues/5115 ">#5115</a>,
<a
href="https://redirect.github.com/pypa/setuptools/issues/5128 ">#5128</a></li>
</ul>
<h1>v80.10.1</h1>
<h2>Misc</h2>
<ul>
<li><a
href="https://redirect.github.com/pypa/setuptools/issues/5152 ">#5152</a></li>
</ul>
<h1>v80.10.0</h1>
<h2>Features</h2>
<ul>
<li>Remove post-release tags on setuptools' own build. (<a
href="https://redirect.github.com/pypa/setuptools/issues/4530 ">#4530</a>)</li>
<li>Refreshed vendored dependencies. (<a
href="https://redirect.github.com/pypa/setuptools/issues/5139 ">#5139</a>)</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="03f3615362 "><code>03f3615</code></a>
Bump version: 81.0.0 → 82.0.0</li>
<li><a
href="530d11498a "><code>530d114</code></a>
Merge pull request <a
href="https://redirect.github.com/pypa/setuptools/issues/5007 ">#5007</a>
from pypa/feature/remove-more-pkg_resources</li>
<li><a
href="11efe9f552 "><code>11efe9f</code></a>
Merge branch 'maint/75.3'</li>
<li><a
href="118f129dd0 "><code>118f129</code></a>
Bump version: 75.3.3 → 75.3.4</li>
<li><a
href="90561ffde1 "><code>90561ff</code></a>
Merge pull request <a
href="https://redirect.github.com/pypa/setuptools/issues/5150 ">#5150</a>
from UladzimirTrehubenka/backport_cve_47273</li>
<li><a
href="4595034db8 "><code>4595034</code></a>
Add news fragment.</li>
<li><a
href="fc008006fc "><code>fc00800</code></a>
Merge pull request <a
href="https://redirect.github.com/pypa/setuptools/issues/5171 ">#5171</a>
from cclauss/ruff-v0.15.0</li>
<li><a
href="127e561362 "><code>127e561</code></a>
Remove tests reliant on pkg_resources, rather than xfailing them.</li>
<li><a
href="64bc21e10b "><code>64bc21e</code></a>
Reference the superseding libraries.</li>
<li><a
href="cf1ff459ea "><code>cf1ff45</code></a>
Merge branch 'main' into debt/pbr-without-pkg_resources</li>
<li>Additional commits viewable in <a
href="https://github.com/pypa/setuptools/compare/v67.6.1...v82.0.0 ">compare
view</a></li>
</ul>
</details>
<br />
Updates `pytest` to 9.0.2
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/pytest-dev/pytest/releases ">pytest's
releases</a>.</em></p>
<blockquote>
<h2>9.0.2</h2>
<h1>pytest 9.0.2 (2025-12-06)</h1>
<h2>Bug fixes</h2>
<ul>
<li>
<p><a
href="https://redirect.github.com/pytest-dev/pytest/issues/13896 ">#13896</a>:
The terminal progress feature added in pytest 9.0.0 has been disabled by
default, except on Windows, due to compatibility issues with some
terminal emulators.</p>
<p>You may enable it again by passing <code>-p terminalprogress</code>.
We may enable it by default again once compatibility improves in the
future.</p>
<p>Additionally, when the environment variable <code>TERM</code> is
<code>dumb</code>, the escape codes are no longer emitted, even if the
plugin is enabled.</p>
</li>
<li>
<p><a
href="https://redirect.github.com/pytest-dev/pytest/issues/13904 ">#13904</a>:
Fixed the TOML type of the <code>tmp_path_retention_count</code>
settings in the API reference from number to string.</p>
</li>
<li>
<p><a
href="https://redirect.github.com/pytest-dev/pytest/issues/13946 ">#13946</a>:
The private <code>config.inicfg</code> attribute was changed in a
breaking manner in pytest 9.0.0.
Due to its usage in the ecosystem, it is now restored to working order
using a compatibility shim.
It will be deprecated in pytest 9.1 and removed in pytest 10.</p>
</li>
<li>
<p><a
href="https://redirect.github.com/pytest-dev/pytest/issues/13965 ">#13965</a>:
Fixed quadratic-time behavior when handling <code>unittest</code>
subtests in Python 3.10.</p>
</li>
</ul>
<h2>Improved documentation</h2>
<ul>
<li><a
href="https://redirect.github.com/pytest-dev/pytest/issues/4492 ">#4492</a>:
The API Reference now contains cross-reference-able documentation of
<code>pytest's command-line flags
<command-line-flags></code>.</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="3d10b5148e "><code>3d10b51</code></a>
Prepare release version 9.0.2</li>
<li><a
href="188750b725 "><code>188750b</code></a>
Merge pull request <a
href="https://redirect.github.com/pytest-dev/pytest/issues/14030 ">#14030</a>
from pytest-dev/patchback/backports/9.0.x/1e4b01d1f...</li>
<li><a
href="b7d7bef90c "><code>b7d7bef</code></a>
Merge pull request <a
href="https://redirect.github.com/pytest-dev/pytest/issues/14014 ">#14014</a>
from bluetech/compat-note</li>
<li><a
href="bd08e85ac7 "><code>bd08e85</code></a>
Merge pull request <a
href="https://redirect.github.com/pytest-dev/pytest/issues/14013 ">#14013</a>
from pytest-dev/patchback/backports/9.0.x/922b60377...</li>
<li><a
href="bc78386299 "><code>bc78386</code></a>
Add CLI options reference documentation (<a
href="https://redirect.github.com/pytest-dev/pytest/issues/13930 ">#13930</a>)</li>
<li><a
href="5a4e398ce8 "><code>5a4e398</code></a>
Fix docs typo (<a
href="https://redirect.github.com/pytest-dev/pytest/issues/14005 ">#14005</a>)
(<a
href="https://redirect.github.com/pytest-dev/pytest/issues/14008 ">#14008</a>)</li>
<li><a
href="d7ae6df394 "><code>d7ae6df</code></a>
Merge pull request <a
href="https://redirect.github.com/pytest-dev/pytest/issues/14006 ">#14006</a>
from pytest-dev/maintenance/update-plugin-list-tmpl...</li>
<li><a
href="556f6a22e1 "><code>556f6a2</code></a>
pre-commit: fix rst-lint after new release (<a
href="https://redirect.github.com/pytest-dev/pytest/issues/13999 ">#13999</a>)
(<a
href="https://redirect.github.com/pytest-dev/pytest/issues/14001 ">#14001</a>)</li>
<li><a
href="c60fbe63a2 "><code>c60fbe6</code></a>
Fix quadratic-time behavior when handling <code>unittest</code> subtests
in Python 3.10 ...</li>
<li><a
href="73d9b01118 "><code>73d9b01</code></a>
Merge pull request <a
href="https://redirect.github.com/pytest-dev/pytest/issues/13995 ">#13995</a>
from nicoddemus/patchback/backports/9.0.x/1b5200c0f...</li>
<li>Additional commits viewable in <a
href="https://github.com/pytest-dev/pytest/compare/8.0.0...9.0.2 ">compare
view</a></li>
</ul>
</details>
<br />
Updates `syrupy` to 5.1.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/syrupy-project/syrupy/releases ">syrupy's
releases</a>.</em></p>
<blockquote>
<h2>v5.1.0</h2>
<h1><a
href="https://github.com/syrupy-project/syrupy/compare/v5.0.0...v5.1.0 ">5.1.0</a>
(2026-01-25)</h1>
<h3>Features</h3>
<ul>
<li>add serializer plugin system; plugins for data models (<a
href="https://redirect.github.com/syrupy-project/syrupy/issues/1062 ">#1062</a>)
(<a
href="df9bc8f6b3 ">df9bc8f</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/syrupy-project/syrupy/blob/main/CHANGELOG.md ">syrupy's
changelog</a>.</em></p>
<blockquote>
<h1><a
href="https://github.com/syrupy-project/syrupy/compare/v5.0.0...v5.1.0 ">5.1.0</a>
(2026-01-25)</h1>
<h3>Features</h3>
<ul>
<li>add serializer plugin system; plugins for data models (<a
href="https://redirect.github.com/syrupy-project/syrupy/issues/1062 ">#1062</a>)
(<a
href="df9bc8f6b3 ">df9bc8f</a>)</li>
</ul>
<h1><a
href="https://github.com/syrupy-project/syrupy/compare/v4.9.1...v5.0.0 ">5.0.0</a>
(2025-09-28)</h1>
<ul>
<li>Switch to MIT license (<a
href="https://redirect.github.com/syrupy-project/syrupy/issues/945 ">#945</a>)
(<a
href="d74d340f88 ">d74d340</a>)</li>
</ul>
<h3>Bug Fixes</h3>
<ul>
<li>Block terminal summary for xdist workers. (<a
href="https://redirect.github.com/syrupy-project/syrupy/issues/978 ">#978</a>)
(<a
href="33a848df7c ">33a848d</a>)</li>
<li>ensure syrupy's pytest_assertrepr_compare hook is called first. (<a
href="https://redirect.github.com/syrupy-project/syrupy/issues/984 ">#984</a>)
(<a
href="eb0024d339 ">eb0024d</a>)</li>
</ul>
<h3>Code Refactoring</h3>
<ul>
<li>remove incorrect private underscore prefix from public methods (<a
href="8cfc9059d3 ">8cfc905</a>)</li>
</ul>
<h3>Features</h3>
<ul>
<li>add --snapshot-dirname option, close <a
href="https://redirect.github.com/syrupy-project/syrupy/issues/810 ">#810</a>
(<a
href="27135c7c86 ">27135c7</a>)</li>
<li>drop support for py3.8, raise min. pytest to v8 (<a
href="https://redirect.github.com/syrupy-project/syrupy/issues/904 ">#904</a>)
(<a
href="a879ff15ad ">a879ff1</a>)</li>
<li>update min. python version to 3.10 (<a
href="https://redirect.github.com/syrupy-project/syrupy/issues/1024 ">#1024</a>)
(<a
href="16b4113cd5 ">16b4113</a>)</li>
</ul>
<h3>BREAKING CHANGES</h3>
<ul>
<li>The following methods have been renamed:</li>
</ul>
<p>SnapshotCollectionStorage</p>
<ul>
<li>_read_snapshot_collection -> read_snapshot_collection</li>
<li>_read_snapshot_data_from_location ->
read_snapshot_data_from_location</li>
<li>_write_snapshot_collection -> write_snapshot_collection</li>
<li>_get_file_basename -> get_file_basename</li>
<li>_file_extension -> file_extension</li>
</ul>
<p>AmberDataSerializer</p>
<ul>
<li>_snapshot_sort_key -> snapshot_sort_key</li>
</ul>
<p>Renamed constants to improve clarity:</p>
<p>constants</p>
<ul>
<li>SNAPSHOT_EMPTY_FOSSIL_KEY -> SNAPSHOT_EMPTY_COLLECTION_KEY</li>
<li>SNAPSHOT_UNKNOWN_FOSSIL_KEY ->
SNAPSHOT_UNKNOWN_COLLECTION_KEY</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="7096efdee6 "><code>7096efd</code></a>
chore(release): 5.1.0 [skip ci]</li>
<li><a
href="07aa00dd48 "><code>07aa00d</code></a>
chore(deps): update dependency attrs to v25 (<a
href="https://redirect.github.com/syrupy-project/syrupy/issues/1063 ">#1063</a>)</li>
<li><a
href="1f29ae061e "><code>1f29ae0</code></a>
docs: add bwrob as a contributor for code (<a
href="https://redirect.github.com/syrupy-project/syrupy/issues/1064 ">#1064</a>)</li>
<li><a
href="df9bc8f6b3 "><code>df9bc8f</code></a>
feat: add serializer plugin system; plugins for data models (<a
href="https://redirect.github.com/syrupy-project/syrupy/issues/1062 ">#1062</a>)</li>
<li><a
href="841257deaf "><code>841257d</code></a>
chore(deps): update dependency coverage to v7.13.1 (<a
href="https://redirect.github.com/syrupy-project/syrupy/issues/1061 ">#1061</a>)</li>
<li><a
href="2d8dfa7f7b "><code>2d8dfa7</code></a>
chore(deps): update codecov/codecov-action action to v5.5.2 (<a
href="https://redirect.github.com/syrupy-project/syrupy/issues/1056 ">#1056</a>)</li>
<li><a
href="f5f9ef7702 "><code>f5f9ef7</code></a>
chore(deps): update dependency debugpy to v1.8.18 (<a
href="https://redirect.github.com/syrupy-project/syrupy/issues/1057 ">#1057</a>)</li>
<li><a
href="eaeb6ae11f "><code>eaeb6ae</code></a>
chore(deps): update dependency pytest to v9.0.2 (<a
href="https://redirect.github.com/syrupy-project/syrupy/issues/1055 ">#1055</a>)</li>
<li><a
href="263b23b768 "><code>263b23b</code></a>
chore(deps): update python docker tag to v3.14.1 (<a
href="https://redirect.github.com/syrupy-project/syrupy/issues/1054 ">#1054</a>)</li>
<li><a
href="a0dd77b023 "><code>a0dd77b</code></a>
chore(deps): update actions/checkout action to v6.0.1 (<a
href="https://redirect.github.com/syrupy-project/syrupy/issues/1053 ">#1053</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/syrupy-project/syrupy/compare/v4.0.2...v5.1.0 ">compare
view</a></li>
</ul>
</details>
<br />
Updates `pytest-asyncio` to 1.3.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/pytest-dev/pytest-asyncio/releases ">pytest-asyncio's
releases</a>.</em></p>
<blockquote>
<h2>pytest-asyncio 1.3.0</h2>
<h1><a
href="https://github.com/pytest-dev/pytest-asyncio/tree/1.3.0 ">1.3.0</a>
- 2025-11-10</h1>
<h2>Removed</h2>
<ul>
<li>Support for Python 3.9 (<a
href="https://redirect.github.com/pytest-dev/pytest-asyncio/issues/1278 ">#1278</a>)</li>
</ul>
<h2>Added</h2>
<ul>
<li>Support for pytest 9 (<a
href="https://redirect.github.com/pytest-dev/pytest-asyncio/issues/1279 ">#1279</a>)</li>
</ul>
<h2>Notes for Downstream Packagers</h2>
<ul>
<li>Tested Python versions include free threaded Python 3.14t (<a
href="https://redirect.github.com/pytest-dev/pytest-asyncio/issues/1274 ">#1274</a>)</li>
<li>Tests are run in the same pytest process, instead of spawning a
subprocess with <code>pytest.Pytester.runpytest_subprocess</code>. This
prevents the test suite from accidentally using a system installation of
pytest-asyncio, which could result in test errors. (<a
href="https://redirect.github.com/pytest-dev/pytest-asyncio/issues/1275 ">#1275</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="2e9695fcf8 "><code>2e9695f</code></a>
docs: Compile changelog for v1.3.0</li>
<li><a
href="dd0e9ba3fa "><code>dd0e9ba</code></a>
docs: Reference correct issue in news fragment.</li>
<li><a
href="4c31abe5bf "><code>4c31abe</code></a>
Build(deps): Bump nh3 from 0.3.1 to 0.3.2</li>
<li><a
href="13e94770d7 "><code>13e9477</code></a>
Link to migration guides from changelog</li>
<li><a
href="4d2cf3c36f "><code>4d2cf3c</code></a>
tests: handle Python 3.14 DefaultEventLoopPolicy deprecation
warnings</li>
<li><a
href="ee3549b6ef "><code>ee3549b</code></a>
test: Remove obsolete test for the event_loop fixture.</li>
<li><a
href="7a67c82c5a "><code>7a67c82</code></a>
tests: Fix failing test by preventing warning conversion to error.</li>
<li><a
href="a17b689a75 "><code>a17b689</code></a>
test: add pytest config to isolated test directories</li>
<li><a
href="18afc9df5a "><code>18afc9d</code></a>
fix(tests): replace runpytest_subprocess with runpytest</li>
<li><a
href="cdc6bd1de7 "><code>cdc6bd1</code></a>
Add support for pytest 9 and drop Python 3.9 support</li>
<li>Additional commits viewable in <a
href="https://github.com/pytest-dev/pytest-asyncio/compare/v0.21.1...v1.3.0 ">compare
view</a></li>
</ul>
</details>
<br />
Updates `packaging` to 26.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/pypa/packaging/releases ">packaging's
releases</a>.</em></p>
<blockquote>
<h2>26.0</h2>
<p>Read about the performance improvements here: <a
href="https://iscinumpy.dev/post/packaging-faster ">https://iscinumpy.dev/post/packaging-faster </a>.</p>
<h2>What's Changed</h2>
<p>Features:</p>
<ul>
<li>PEP 751: support pylock by <a
href="https://github.com/sbidoul "><code>@sbidoul</code></a> in <a
href="https://redirect.github.com/pypa/packaging/pull/900 ">pypa/packaging#900</a></li>
<li>PEP 794: import name metadata by <a
href="https://github.com/brettcannon "><code>@brettcannon</code></a> in
<a
href="https://redirect.github.com/pypa/packaging/pull/948 ">pypa/packaging#948</a></li>
<li>Support writing metadata by <a
href="https://github.com/henryiii "><code>@henryiii</code></a> in <a
href="https://redirect.github.com/pypa/packaging/pull/846 ">pypa/packaging#846</a></li>
<li>Support <code>__replace__</code> for <code>Version</code> by <a
href="https://github.com/henryiii "><code>@henryiii</code></a> in <a
href="https://redirect.github.com/pypa/packaging/pull/1003 ">pypa/packaging#1003</a></li>
<li>Support positional pattern matching for <code>Version</code> and
<code>Specifier</code> by <a
href="https://github.com/henryiii "><code>@henryiii</code></a> in <a
href="https://redirect.github.com/pypa/packaging/pull/1004 ">pypa/packaging#1004</a></li>
</ul>
<p>Behavior adaptations:</p>
<ul>
<li>PEP 440 handling of prereleases for <code>Specifier.contains</code>,
<code>SpecifierSet.contains</code>, and <code>SpecifierSet.filter</code>
by <a
href="https://github.com/notatallshaw "><code>@notatallshaw</code></a>
in <a
href="https://redirect.github.com/pypa/packaging/pull/897 ">pypa/packaging#897</a></li>
<li>Handle PEP 440 edge case in <code>SpecifierSet.filter</code> by <a
href="https://github.com/notatallshaw "><code>@notatallshaw</code></a>
in <a
href="https://redirect.github.com/pypa/packaging/pull/942 ">pypa/packaging#942</a></li>
<li>Adjust arbitrary equality intersection preservation in
<code>SpecifierSet</code> by <a
href="https://github.com/notatallshaw "><code>@notatallshaw</code></a>
in <a
href="https://redirect.github.com/pypa/packaging/pull/951 ">pypa/packaging#951</a></li>
<li>Return <code>False</code> instead of raising for
<code>.contains</code> with invalid version by <a
href="https://github.com/Liam-DeVoe "><code>@Liam-DeVoe</code></a> in <a
href="https://redirect.github.com/pypa/packaging/pull/932 ">pypa/packaging#932</a></li>
<li>Support arbitrary equality on arbitrary strings for
<code>Specifier</code> and <code>SpecifierSet</code>'s
<code>filter</code> and <code>contains</code> method. by <a
href="https://github.com/notatallshaw "><code>@notatallshaw</code></a>
in <a
href="https://redirect.github.com/pypa/packaging/pull/954 ">pypa/packaging#954</a></li>
<li>Only try to parse as <code>Version</code> on certain marker keys,
return <code>False</code> on unequal ordered comparsions by <a
href="https://github.com/JP-Ellis "><code>@JP-Ellis</code></a> in <a
href="https://redirect.github.com/pypa/packaging/pull/939 ">pypa/packaging#939</a></li>
</ul>
<p>Fixes:</p>
<ul>
<li>Update <code>_hash</code> when unpickling <code>Tag()</code> by <a
href="https://github.com/dholth "><code>@dholth</code></a> in <a
href="https://redirect.github.com/pypa/packaging/pull/860 ">pypa/packaging#860</a></li>
<li>Correct comment and simplify implicit prerelease handling in
<code>Specifier.prereleases</code> by <a
href="https://github.com/notatallshaw "><code>@notatallshaw</code></a>
in <a
href="https://redirect.github.com/pypa/packaging/pull/896 ">pypa/packaging#896</a></li>
<li>Use explicit <code>_GLibCVersion</code> <code>NamedTuple</code> in
<code>_manylinux</code> by <a
href="https://github.com/cthoyt "><code>@cthoyt</code></a> in <a
href="https://redirect.github.com/pypa/packaging/pull/868 ">pypa/packaging#868</a></li>
<li>Detect invalid license expressions containing <code>()</code> by <a
href="https://github.com/bwoodsend "><code>@bwoodsend</code></a> in <a
href="https://redirect.github.com/pypa/packaging/pull/879 ">pypa/packaging#879</a></li>
<li>Correct regex for metadata <code>'name'</code> format by <a
href="https://github.com/di "><code>@di</code></a> in <a
href="https://redirect.github.com/pypa/packaging/pull/925 ">pypa/packaging#925</a></li>
<li>Improve the message around expecting a semicolon by <a
href="https://github.com/pradyunsg "><code>@pradyunsg</code></a> in <a
href="https://redirect.github.com/pypa/packaging/pull/833 ">pypa/packaging#833</a></li>
<li>Support nested parens in license expressions by <a
href="https://github.com/Liam-DeVoe "><code>@Liam-DeVoe</code></a> in <a
href="https://redirect.github.com/pypa/packaging/pull/931 ">pypa/packaging#931</a></li>
<li>Add space before at symbol in <code>Requirements</code> string by <a
href="https://github.com/henryiii "><code>@henryiii</code></a> in <a
href="https://redirect.github.com/pypa/packaging/pull/953 ">pypa/packaging#953</a></li>
<li>A root logger use found by ruff LOG, use <code>packaging</code>
logger instead by <a
href="https://github.com/henryiii "><code>@henryiii</code></a> in <a
href="https://redirect.github.com/pypa/packaging/pull/965 ">pypa/packaging#965</a></li>
<li>Better support for subclassing <code>Marker</code> and
<code>Requirement</code> by <a
href="https://github.com/henryiii "><code>@henryiii</code></a> in <a
href="https://redirect.github.com/pypa/packaging/pull/1022 ">pypa/packaging#1022</a></li>
<li>Normalize all extras, not just if it comes first by <a
href="https://github.com/henryiii "><code>@henryiii</code></a> in <a
href="https://redirect.github.com/pypa/packaging/pull/1024 ">pypa/packaging#1024</a></li>
<li>Don't produce a broken repr if <code>Marker</code> fails to
construct by <a
href="https://github.com/henryiii "><code>@henryiii</code></a> in <a
href="https://redirect.github.com/pypa/packaging/pull/1033 ">pypa/packaging#1033</a></li>
</ul>
<p>Performance:</p>
<ul>
<li>Avoid recompiling regexes in the tokenizer for a 3x speedup by <a
href="https://github.com/hauntsaninja "><code>@hauntsaninja</code></a>
in <a
href="https://redirect.github.com/pypa/packaging/pull/1019 ">pypa/packaging#1019</a></li>
<li>Improve performance in <code>_manylinux.py</code> by <a
href="https://github.com/cthoyt "><code>@cthoyt</code></a> in <a
href="https://redirect.github.com/pypa/packaging/pull/869 ">pypa/packaging#869</a></li>
<li>Minor cleanups to <code>Version</code> by <a
href="https://github.com/bearomorphism "><code>@bearomorphism</code></a>
in <a
href="https://redirect.github.com/pypa/packaging/pull/913 ">pypa/packaging#913</a></li>
<li>Skip redundant creation of <code>Version</code>s in specifier
comparison by <a
href="https://github.com/notatallshaw "><code>@notatallshaw</code></a>
in <a
href="https://redirect.github.com/pypa/packaging/pull/986 ">pypa/packaging#986</a></li>
<li>Cache <code>Specifier</code>'s Version by <a
href="https://github.com/notatallshaw "><code>@notatallshaw</code></a>
in <a
href="https://redirect.github.com/pypa/packaging/pull/985 ">pypa/packaging#985</a></li>
<li>Make <code>Version</code> a little faster by <a
href="https://github.com/henryiii "><code>@henryiii</code></a> in <a
href="https://redirect.github.com/pypa/packaging/pull/987 ">pypa/packaging#987</a></li>
<li>Minor <code>Version</code> regex cleanup by <a
href="https://github.com/henryiii "><code>@henryiii</code></a> in <a
href="https://redirect.github.com/pypa/packaging/pull/990 ">pypa/packaging#990</a></li>
<li>Faster regex on Python 3.11.5+ by <a
href="https://github.com/henryiii "><code>@henryiii</code></a> in <a
href="https://redirect.github.com/pypa/packaging/pull/988 ">pypa/packaging#988</a>
and <a
href="https://redirect.github.com/pypa/packaging/pull/1055 ">pypa/packaging#1055</a></li>
<li>Lazily calculate <code>_key</code> in <code>Version</code> by <a
href="https://github.com/notatallshaw "><code>@notatallshaw</code></a>
in <a
href="https://redirect.github.com/pypa/packaging/pull/989 ">pypa/packaging#989</a>
and regression for <code>packaging_legacy</code> fixed by <a
href="https://github.com/henryiii "><code>@henryiii</code></a> in <a
href="https://redirect.github.com/pypa/packaging/pull/1048 ">pypa/packaging#1048</a></li>
<li>Faster <code>canonicalize_version</code> by <a
href="https://github.com/henryiii "><code>@henryiii</code></a> in <a
href="https://redirect.github.com/pypa/packaging/pull/993 ">pypa/packaging#993</a></li>
<li>Use <code>fullmatch</code> in a couple more places by <a
href="https://github.com/henryiii "><code>@henryiii</code></a> in <a
href="https://redirect.github.com/pypa/packaging/pull/992 ">pypa/packaging#992</a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/pypa/packaging/blob/main/CHANGELOG.rst ">packaging's
changelog</a>.</em></p>
<blockquote>
<p>26.0 - 2026-01-20</p>
<pre><code>
Features:
<ul>
<li>PEP 751: support pylock (:pull:<code>900</code>)</li>
<li>PEP 794: import name metadata (:pull:<code>948</code>)</li>
<li>Support for writing metadata to a file (:pull:<code>846</code>)</li>
<li>Support <code>__replace__</code> on Version
(:pull:<code>1003</code>)</li>
<li>Support positional pattern matching for <code>Version</code> and
<code>SpecifierSet</code> (:pull:<code>1004</code>)</li>
</ul>
<p>Behavior adaptations:</p>
<ul>
<li>PEP 440 handling of prereleases for <code>Specifier.contains</code>,
<code>SpecifierSet.contains</code>, and <code>SpecifierSet.filter</code>
(:pull:<code>897</code>)</li>
<li>Handle PEP 440 edge case in <code>SpecifierSet.filter</code>
(:pull:<code>942</code>)</li>
<li>Adjust arbitrary equality intersection preservation in
<code>SpecifierSet</code> (:pull:<code>951</code>)</li>
<li>Return <code>False</code> instead of raising for
<code>.contains</code> with invalid version
(:pull:<code>932</code>)</li>
<li>Support arbitrary equality on arbitrary strings for
<code>Specifier</code> and <code>SpecifierSet</code>'s
<code>filter</code> and <code>contains</code> method.
(:pull:<code>954</code>)</li>
<li>Only try to parse as <code>Version</code> on certain marker keys,
return <code>False</code> on unequal ordered comparisons
(:pull:<code>939</code>)</li>
</ul>
<p>Fixes:</p>
<ul>
<li>Update <code>_hash</code> when unpickling <code>Tag()</code>
(:pull:<code>860</code>)</li>
<li>Correct comment and simplify implicit prerelease handling in
<code>Specifier.prereleases</code> (:pull:<code>896</code>)</li>
<li>Use explicit <code>_GLibCVersion</code> <code>NamedTuple</code> in
<code>_manylinux</code> (:pull:<code>868</code>)</li>
<li>Detect invalid license expressions containing <code>()</code>
(:pull:<code>879</code>)</li>
<li>Correct regex for metadata <code>'name'</code> format
(:pull:<code>925</code>)</li>
<li>Improve the message around expecting a semicolon
(:pull:<code>833</code>)</li>
<li>Support nested parens in license expressions
(:pull:<code>931</code>)</li>
<li>Add space before at symbol in <code>Requirements</code> string
(:pull:<code>953</code>)</li>
<li>A root logger use found, use a <code>packaging</code> logger instead
(:pull:<code>965</code>)</li>
<li>Better support for subclassing <code>Marker</code> and
<code>Requirement</code> (:pull:<code>1022</code>)</li>
<li>Normalize all extras, not just if it comes first
(:pull:<code>1024</code>)</li>
<li>Don't produce a broken repr if <code>Marker</code> fails to
construct (:pull:<code>1033</code>)</li>
</ul>
<p>Performance:</p>
<ul>
<li>Avoid recompiling regexes in the tokenizer for a 3x speedup
(:pull:<code>1019</code>)</li>
<li>Improve performance in <code>_manylinux.py</code>
(:pull:<code>869</code>)</li>
<li>Minor cleanups to <code>Version</code> (:pull:<code>913</code>)</li>
<li>Skip redundant creation of <code>Version</code>'s in specifier
comparison (:pull:<code>986</code>)</li>
<li>Cache the <code>Specifier</code>'s <code>Version</code>
(:pull:<code>985</code>)</li>
<li>Make <code>Version</code> a little faster
(:pull:<code>987</code>)</li>
<li>Minor <code>Version</code> regex cleanup
(:pull:<code>990</code>)</li>
<li>Faster regex on Python 3.11.5+ for <code>Version</code>
(:pull:<code>988</code>, :pull:<code>1055</code>)</li>
<li>Lazily calculate <code>_key</code> in <code>Version</code>
(:pull:<code>989</code>, :pull:<code>1048</code>)</li>
<li>Faster <code>canonicalize_version</code>
(:pull:<code>993</code>)</li>
<li>Use <code>re.fullmatch</code> in a couple more places
(:pull:<code>992</code>, :pull:<code>1029</code>)</li>
<li>Use <code>map</code> instead of generator
(:pull:<code>996</code>)</li>
<li>Deprecate <code>._version</code> (<code>_Version</code>, a
<code>NamedTuple</code>) (:pull:<code>995</code>,
:pull:<code>1062</code>)<br />
</tr></table><br />
</code></pre></li>
</ul>
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="3b77a26f5a "><code>3b77a26</code></a>
Bump for release</li>
<li><a
href="31371cce59 "><code>31371cc</code></a>
docs: prepare for 26.0 final (<a
href="https://redirect.github.com/pypa/packaging/issues/1063 ">#1063</a>)</li>
<li><a
href="9627a8821f "><code>9627a88</code></a>
perf: dual replace (<a
href="https://redirect.github.com/pypa/packaging/issues/1064 ">#1064</a>)</li>
<li><a
href="d5398b8bc1 "><code>d5398b8</code></a>
fix: restore ._version as a compat shim (<a
href="https://redirect.github.com/pypa/packaging/issues/1062 ">#1062</a>)</li>
<li><a
href="3a7b600a12 "><code>3a7b600</code></a>
Bump for development</li>
<li><a
href="d4eefdccf9 "><code>d4eefdc</code></a>
Bump for release</li>
<li><a
href="46189124fb "><code>4618912</code></a>
docs: prepare for 26.0rc3 (<a
href="https://redirect.github.com/pypa/packaging/issues/1060 ">#1060</a>)</li>
<li><a
href="0cf1b41b4b "><code>0cf1b41</code></a>
ci: test on first public release of CPythons (<a
href="https://redirect.github.com/pypa/packaging/issues/1056 ">#1056</a>)</li>
<li><a
href="716beb1c0a "><code>716beb1</code></a>
perf: 10% faster stripping zeros (<a
href="https://redirect.github.com/pypa/packaging/issues/1058 ">#1058</a>)</li>
<li><a
href="350a230670 "><code>350a230</code></a>
fix: support CPython 3.11.0-3.11.4 and older PyPy3.11 (<a
href="https://redirect.github.com/pypa/packaging/issues/1055 ">#1055</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/pypa/packaging/compare/24.2...26.0 ">compare
view</a></li>
</ul>
</details>
<br />
Updates `ruff` to 0.15.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/astral-sh/ruff/releases ">ruff's
releases</a>.</em></p>
<blockquote>
<h2>0.15.0</h2>
<h2>Release Notes</h2>
<p>Released on 2026-02-03.</p>
<p>Check out the <a href="https://astral.sh/blog/ruff-v0.15.0 ">blog
post</a> for a migration guide and overview of the changes!</p>
<h3>Breaking changes</h3>
<ul>
<li>
<p>Ruff now formats your code according to the 2026 style guide. See the
formatter section below or in the blog post for a detailed list of
changes.</p>
</li>
<li>
<p>The linter now supports block suppression comments. For example, to
suppress <code>N803</code> for all parameters in this function:</p>
<pre lang="python"><code># ruff: disable[N803]
def foo(
legacyArg1,
legacyArg2,
legacyArg3,
legacyArg4,
): ...
# ruff: enable[N803]
</code></pre>
<p>See the <a
href="https://docs.astral.sh/ruff/linter/#block-level ">documentation</a>
for more details.</p>
</li>
<li>
<p>The <code>ruff:alpine</code> Docker image is now based on Alpine 3.23
(up from 3.21).</p>
</li>
<li>
<p>The <code>ruff:debian</code> and <code>ruff:debian-slim</code> Docker
images are now based on Debian 13 "Trixie" instead of Debian
12 "Bookworm."</p>
</li>
<li>
<p>Binaries for the <code>ppc64</code> (64-bit big-endian PowerPC)
architecture are no longer included in our releases. It should still be
possible to build Ruff manually for this platform, if needed.</p>
</li>
<li>
<p>Ruff now resolves all <code>extend</code>ed configuration files
before falling back on a default Python version.</p>
</li>
</ul>
<h3>Stabilization</h3>
<p>The following rules have been stabilized and are no longer in
preview:</p>
<ul>
<li><a
href="https://docs.astral.sh/ruff/rules/blocking-http-call-httpx-in-async-function "><code>blocking-http-call-httpx-in-async-function</code></a>
(<code>ASYNC212</code>)</li>
<li><a
href="https://docs.astral.sh/ruff/rules/blocking-path-method-in-async-function "><code>blocking-path-method-in-async-function</code></a>
(<code>ASYNC240</code>)</li>
<li><a
href="https://docs.astral.sh/ruff/rules/blocking-input-in-async-function "><code>blocking-input-in-async-function</code></a>
(<code>ASYNC250</code>)</li>
<li><a
href="https://docs.astral.sh/ruff/rules/map-without-explicit-strict "><code>map-without-explicit-strict</code></a>
(<code>B912</code>)</li>
<li><a
href="https://docs.astral.sh/ruff/rules/if-exp-instead-of-or-operator "><code>if-exp-instead-of-or-operator</code></a>
(<code>FURB110</code>)</li>
<li><a
href="https://docs.astral.sh/ruff/rules/single-item-membership-test "><code>single-item-membership-test</code></a>
(<code>FURB171</code>)</li>
<li><a
href="https://docs.astral.sh/ruff/rules/missing-maxsplit-arg "><code>missing-maxsplit-arg</code></a>
(<code>PLC0207</code>)</li>
<li><a
href="https://docs.astral.sh/ruff/rules/unnecessary-lambda "><code>unnecessary-lambda</code></a>
(<code>PLW0108</code>)</li>
<li><a
href="https://docs.astral.sh/ruff/rules/unnecessary-empty-iterable-within-deque-call "><code>unnecessary-empty-iterable-within-deque-call</code></a>
(<code>RUF037</code>)</li>
<li><a
href="https://docs.astral.sh/ruff/rules/in-empty-collection "><code>in-empty-collection</code></a>
(<code>RUF060</code>)</li>
<li><a
href="https://docs.astral.sh/ruff/rules/legacy-form-pytest-raises "><code>legacy-form-pytest-raises</code></a>
(<code>RUF061</code>)</li>
<li><a
href="https://docs.astral.sh/ruff/rules/non-octal-permissions "><code>non-octal-permissions</code></a>
(<code>RUF064</code>)</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md ">ruff's
changelog</a>.</em></p>
<blockquote>
<h2>0.15.0</h2>
<p>Released on 2026-02-03.</p>
<p>Check out the <a href="https://astral.sh/blog/ruff-v0.15.0 ">blog
post</a> for a migration
guide and overview of the changes!</p>
<h3>Breaking changes</h3>
<ul>
<li>
<p>Ruff now formats your code according to the 2026 style guide. See the
formatter section below or in the blog post for a detailed list of
changes.</p>
</li>
<li>
<p>The linter now supports block suppression comments. For example, to
suppress <code>N803</code> for all parameters in this function:</p>
<pre lang="python"><code># ruff: disable[N803]
def foo(
legacyArg1,
legacyArg2,
legacyArg3,
legacyArg4,
): ...
# ruff: enable[N803]
</code></pre>
<p>See the <a
href="https://docs.astral.sh/ruff/linter/#block-level ">documentation</a>
for more details.</p>
</li>
<li>
<p>The <code>ruff:alpine</code> Docker image is now based on Alpine 3.23
(up from 3.21).</p>
</li>
<li>
<p>The <code>ruff:debian</code> and <code>ruff:debian-slim</code> Docker
images are now based on Debian 13 "Trixie" instead of Debian
12 "Bookworm."</p>
</li>
<li>
<p>Binaries for the <code>ppc64</code> (64-bit big-endian PowerPC)
architecture are no longer included in our releases. It should still be
possible to build Ruff manually for this platform, if needed.</p>
</li>
<li>
<p>Ruff now resolves all <code>extend</code>ed configuration files
before falling back on a default Python version.</p>
</li>
</ul>
<h3>Stabilization</h3>
<p>The following rules have been stabilized and are no longer in
preview:</p>
<ul>
<li><a
href="https://docs.astral.sh/ruff/rules/blocking-http-call-httpx-in-async-function "><code>blocking-http-call-httpx-in-async-function</code></a>
(<code>ASYNC212</code>)</li>
<li><a
href="https://docs.astral.sh/ruff/rules/blocking-path-method-in-async-function "><code>blocking-path-method-in-async-function</code></a>
(<code>ASYNC240</code>)</li>
<li><a
href="https://docs.astral.sh/ruff/rules/blocking-input-in-async-function "><code>blocking-input-in-async-function</code></a>
(<code>ASYNC250</code>)</li>
<li><a
href="https://docs.astral.sh/ruff/rules/map-without-explicit-strict "><code>map-without-explicit-strict</code></a>
(<code>B912</code>)</li>
<li><a
href="https://docs.astral.sh/ruff/rules/if-exp-instead-of-or-operator "><code>if-exp-instead-of-or-operator</code></a>
(<code>FURB110</code>)</li>
<li><a
href="https://docs.astral.sh/ruff/rules/single-item-membership-test "><code>single-item-membership-test</code></a>
(<code>FURB171</code>)</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="ce5f7b6127 "><code>ce5f7b6</code></a>
Bump 0.15.0 (<a
href="https://redirect.github.com/astral-sh/ruff/issues/23055 ">#23055</a>)</li>
<li><a
href="b4e40f539c "><code>b4e40f5</code></a>
[ty] Fix <code>__contains__</code> to respect descriptors (<a
href="https://redirect.github.com/astral-sh/ruff/issues/23056 ">#23056</a>)</li>
<li><a
href="848cb72dc1 "><code>848cb72</code></a>
[ty] Fix narrowing of nonlocal variables with conditional assignments
(<a
href="https://redirect.github.com/astral-sh/ruff/issues/22966 ">#22966</a>)</li>
<li><a
href="da7f33af22 "><code>da7f33a</code></a>
[ty] Add a diagnostic for <code>Final</code> without assignment (<a
href="https://redirect.github.com/astral-sh/ruff/issues/23001 ">#23001</a>)</li>
<li><a
href="e65f9a6b03 "><code>e65f9a6</code></a>
Document markdown formatting feature (<a
href="https://redirect.github.com/astral-sh/ruff/issues/22990 ">#22990</a>)</li>
<li><a
href="c0c1b985c9 "><code>c0c1b98</code></a>
Format markdown code blocks with line-by-line regex parse (<a
href="https://redirect.github.com/astral-sh/ruff/issues/22996 ">#22996</a>)</li>
<li><a
href="9f8f3e196b "><code>9f8f3e1</code></a>
Allow positional-only params with defaults in method overrides (<a
href="https://redirect.github.com/astral-sh/ruff/issues/23037 ">#23037</a>)</li>
<li><a
href="ef83810e11 "><code>ef83810</code></a>
[ty] ecosystem-analyzer: Support bare git repositories (<a
href="https://redirect.github.com/astral-sh/ruff/issues/23054 ">#23054</a>)</li>
<li><a
href="54dfee4cb8 "><code>54dfee4</code></a>
Customize where the <code>fix_title</code> sub-diagnostic appears (<a
href="https://redirect.github.com/astral-sh/ruff/issues/23044 ">#23044</a>)</li>
<li><a
href="b53460799b "><code>b534607</code></a>
2026 Ruff Formatter Style (<a
href="https://redirect.github.com/astral-sh/ruff/issues/22735 ">#22735</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/astral-sh/ruff/compare/0.14.11...0.15.0 ">compare
view</a></li>
</ul>
</details>
<br />
Updates `setuptools` to 82.0.0
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/pypa/setuptools/blob/main/NEWS.rst ">setuptools's
changelog</a>.</em></p>
<blockquote>
<h1>v82.0.0</h1>
<h2>Deprecations and Removals</h2>
<ul>
<li><code>pkg_resources</code> has been removed from Setuptools. Most
common uses of <code>pkg_resources</code> have been superseded by the
<code>importlib.resources
<https://docs.python.org/3/library/importlib.resources.html> ;</code>_
and <code>importlib.metadata
<https://docs.python.org/3/library/importlib.metadata.html> ;</code>_
projects. Projects and environments relying on
<code>pkg_resources</code> for namespace packages or other behavior
should depend on older versions of <code>setuptools</code>. (<a
href="https://redirect.github.com/pypa/setuptools/issues/3085 ">#3085</a>)</li>
</ul>
<h1>v81.0.0</h1>
<h2>Deprecations and Removals</h2>
<ul>
<li>Removed support for the --dry-run parameter to setup.py. This one
feature by its nature threads through lots of core and ancillary
functionality, adding complexity and friction. Removal of this parameter
will help decouple the compiler functionality from distutils and thus
the eventual full integration of distutils. These changes do affect some
class and function signatures, so any derivative functionality may
require some compatibility shims to support their expected interface.
Please report any issues to the Setuptools project for investigation.
(<a
href="https://redirect.github.com/pypa/setuptools/issues/4872 ">#4872</a>)</li>
</ul>
<h1>v80.10.2</h1>
<h2>Bugfixes</h2>
<ul>
<li>Update vendored dependencies. (<a
href="https://redirect.github.com/pypa/setuptools/issues/5159 ">#5159</a>)</li>
</ul>
<h2>Misc</h2>
<ul>
<li><a
href="https://redirect.github.com/pypa/setuptools/issues/5115 ">#5115</a>,
<a
href="https://redirect.github.com/pypa/setuptools/issues/5128 ">#5128</a></li>
</ul>
<h1>v80.10.1</h1>
<h2>Misc</h2>
<ul>
<li><a
href="https://redirect.github.com/pypa/setuptools/issues/5152 ">#5152</a></li>
</ul>
<h1>v80.10.0</h1>
<h2>Features</h2>
<ul>
<li>Remove post-release tags on setuptools' own build. (<a
href="https://redirect.github.com/pypa/setuptools/issues/4530 ">#4530</a>)</li>
<li>Refreshed vendored dependencies. (<a
href="https://redirect.github.com/pypa/setuptools/issues/5139 ">#5139</a>)</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="03f3615362 "><code>03f3615</code></a>
Bump version: 81.0.0 → 82.0.0</li>
<li><a
href="530d11498a "><code>530d114</code></a>
Merge pull request <a
href="https://redirect.github.com/pypa/setuptools/issues/5007 ">#5007</a>
from pypa/feature/remove-more-pkg_resources</li>
<li><a
href="11efe9f552 "><code>11efe9f</code></a>
Merge branch 'maint/75.3'</li>
<li><a
href="118f129dd0 "><code>118f129</code></a>
Bump version: 75.3.3 → 75.3.4</li>
<li><a
href="90561ffde1 "><code>90561ff</code></a>
Merge pull request <a
href="https://redirect.github.com/pypa/setuptools/issues/5150 ">#5150</a>
from UladzimirTrehubenka/backport_cve_47273</li>
<li><a
href="4595034db8 "><code>4595034</code></a>
Add news fragment.</li>
<li><a
href="fc008006fc "><code>fc00800</code></a>
Merge pull request <a
href="https://redirect.github.com/pypa/setuptools/issues/5171 ">#5171</a>
from cclauss/ruff-v0.15.0</li>
<li><a
href="127e561362 "><code>127e561</code></a>
Remove tests reliant on pkg_resources, rather than xfailing them.</li>
<li><a
href="64bc21e10b "><code>64bc21e</code></a>
Reference the superseding libraries.</li>
<li><a
href="cf1ff459ea "><code>cf1ff45</code></a>
Merge branch 'main' into debt/pbr-without-pkg_resources</li>
<li>Additional commits viewable in <a
href="https://github.com/pypa/setuptools/compare/v67.6.1...v82.0.0 ">compare
view</a></li>
</ul>
</details>
<br />
Updates `pytest` to 9.0.2
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/pytest-dev/pytest/releases ">pytest's
releases</a>.</em></p>
<blockquote>
<h2>9.0.2</h2>
<h1>pytest 9.0.2 (2025-12-06)</h1>
<h2>Bug fixes</h2>
<ul>
<li>
<p><a
href="https://redirect.github.com/pytest-dev/pytest/issues/13896 ">#13896</a>:
The terminal progress feature added in pytest 9.0.0 has been disabled by
default, except on Windows, due to compatibility issues with some
terminal emulators.</p>
<p>You may enable it again by passing <code>-p terminalprogress</code>.
We may enable it by default again once compatibility improves in the
future.</p>
<p>Additionally, when the environment variable <code>TERM</code> is
<code>dumb</code>, the escape codes are no longer emitted, even if the
plugin is enabled.</p>
</li>
<li>
<p><a
href="https://redirect.github.com/pytest-dev/pytest/issues/13904 ">#13904</a>:
Fixed the TOML type of the <code>tmp_path_retention_count</code>
settings in the API reference from number to string.</p>
</li>
<li>
<p><a
href="https://redirect.github.com/pytest-dev/pytest/issues/13946 ">#13946</a>:
The private <code>config.inicfg</code> attribute was changed in a
breaking manner in pytest 9.0.0.
Due to its usage in the ecosystem, it is now restored to working order
using a compatibility shim.
It will be deprecated in pytest 9.1 and removed in pytest 10.</p>
</li>
<li>
<p><a
href="https://redirect.github.com/pytest-dev/pytest/issues/13965 ">#13965</a>:
Fixed quadratic-time behavior when handling <code>unittest</code>
subtests in Python 3.10.</p>
</li>
</ul>
<h2>Improved documentation</h2>
<ul>
<li><a
href="https://redirect.github.com/pytest-dev/pytest/issues/4492 ">#4492</a>:
The API Reference now contains cross-reference-able documentation of
<code>pytest's command-line flags
<command-line-flags></code>.</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="3d10b5148e "><code>3d10b51</code></a>
Prepare release version 9.0.2</li>
<li><a
href="188750b725 "><code>188750b</code></a>
Merge pull request <a
href="https://redirect.github.com/pytest-dev/pytest/issues/14030 ">#14030</a>
from pytest-dev/patchback/backports/9.0.x/1e4b01d1f...</li>
<li><a
href="b7d7bef90c "><code>b7d7bef</code></a>
Merge pull request <a
href="https://redirect.github.com/pytest-dev/pytest/issues/14014 ">#14014</a>
from bluetech/compat-note</li>
<li><a
href="bd08e85ac7 "><code>bd08e85</code></a>
Merge pull request <a
href="https://redirect.github.com/pytest-dev/pytest/issues/14013 ">#14013</a>
from pytest-dev/patchback/backports/9.0.x/922b60377...</li>
<li><a
href="bc78386299 "><code>bc78386</code></a>
Add CLI options reference documentation (<a
href="https://redirect.github.com/pytest-dev/pytest/issues/13930 ">#13930</a>)</li>
<li><a
href="5a4e398ce8 "><code>5a4e398</code></a>
Fix docs typo (<a
href="https://redirect.github.com/pytest-dev/pytest/issues/14005 ">#14005</a>)
(<a
href="https://redirect.github.com/pytest-dev/pytest/issues/14008 ">#14008</a>)</li>
<li><a
href="d7ae6df394 "><code>d7ae6df</code></a>
Merge pull request <a
href="https://redirect.github.com/pytest-dev/pytest/issues/14006 ">#14006</a>
from pytest-dev/maintenance/update-plugin-list-tmpl...</li>
<li><a
href="556f6a22e1 "><code>556f6a2</code></a>
pre-commit: fix rst-lint after new release (<a
href="https://redirect.github.com/pytest-dev/pytest/issues/13999 ">#13999</a>)
(<a
href="https://redirect.github.com/pytest-dev/pytest/issues/14001 ">#14001</a>)</li>
<li><a
href="c60fbe63a2 "><code>c60fbe6</code></a>
Fix quadratic-time behavior when handling <code>unittest</code> subtests
in Python 3.10 ...</li>
<li><a
href="73d9b01118 "><code>73d9b01</code></a>
Merge pull request <a
href="https://redirect.github.com/pytest-dev/pytest/issues/13995 ">#13995</a>
from nicoddemus/patchback/backports/9.0.x/1b5200c0f...</li>
<li>Additional commits viewable in <a
href="https://github.com/pytest-dev/pytest/compare/8.0.0...9.0.2 ">compare
view</a></li>
</ul>
</details>
<br />
Updates `syrupy` to 5.1.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/syrupy-project/syrupy/releases ">syrupy's
releases</a>.</em></p>
<blockquote>
<h2>v5.1.0</h2>
<h1><a
href="https://github.com/syrupy-project/syrupy/compare/v5.0.0...v5.1.0 ">5.1.0</a>
(2026-01-25)</h1>
<h3>Features</h3>
<ul>
<li>add serializer plugin system; plugins for data models (<a
href="https://redirect.github.com/syrupy-project/syrupy/issues/1062 ">#1062</a>)
(<a
href="df9bc8f6b3 ">df9bc8f</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/syrupy-project/syrupy/blob/main/CHANGELOG.md ">syrupy's
changelog</a>.</em></p>
<blockquote>
<h1><a
href="https://github.com/syrupy-project/syrupy/compare/v5.0.0...v5.1.0 ">5.1.0</a>
(2026-01-25)</h1>
<h3>Features</h3>
<ul>
<li>add serializer plugin system; plugins for data models (<a
href="https://redirect.github.com/syrupy-project/syrupy/issues/1062 ">#1062</a>)
(<a
href="df9bc8f6b3 ">df9bc8f</a>)</li>
</ul>
<h1><a
href="https://github.com/syrupy-project/syrupy/compare/v4.9.1...v5.0.0 ">5.0.0</a>
(2025-09-28)</h1>
<ul>
<li>Switch to MIT license (<a
href="https://redirect.github.com/syrupy-project/syrupy/issues/945 ">#945</a>)
(<a
href="d74d340f88 ">d74d340</a>)</li>
</ul>
<h3>Bug Fixes</h3>
<ul>
<li>Block terminal summary for xdist workers. (<a
href="https://redirect.github.com/syrupy-project/syrupy/issues/978 ">#978</a>)
(<a
href="33a848df7c ">33a848d</a>)</li>
<li>ensure syrupy's pytest_assertrepr_compare hook is called first. (<a
href="https://redirect.github.com/syrupy-project/syrupy/issues/984 ">#984</a>)
(<a
href="eb0024d339 ">eb0024d</a>)</li>
</ul>
<h3>Code Refactoring</h3>
<ul>
<li>remove incorrect private underscore prefix from public methods (<a
href="8cfc9059d3 ">8cfc905</a>)</li>
</ul>
<h3>Features</h3>
<ul>
<li>add --snapshot-dirname option, close <a
href="https://redirect.github.com/syrupy-project/syrupy/issues/810 ">#810</a>
(<a
href="27135c7c86 ">27135c7</a>)</li>
<li>drop support for py3.8, raise min. pytest to v8 (<a
href="https://redirect.gith ...
_Description has been truncated_
---------
Signed-off-by: dependabot[bot] <support@github.com >
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: John Kennedy <65985482+jkennedyvz@users.noreply.github.com >
2026-02-09 22:37:10 -08:00
Sydney Runkle
8767a462ca
feat: support state updates from wrap_model_call with command(s) ( #35033 )
...
Alternative to https://github.com/langchain-ai/langchain/pull/35024 .
Paving the way for summarization in `wrap_model_call` (which requires
state updates).
---
Add `ExtendedModelResponse` dataclass that allows `wrap_model_call`
middleware to return a `Command` alongside the model response for
additional state updates.
```py
@dataclass
class ExtendedModelResponse(Generic[ResponseT]):
model_response: ModelResponse[ResponseT]
command: Command
```
## Motivation
Previously, `wrap_model_call` middleware could only return a
`ModelResponse` or `AIMessage` — there was no way to inject additional
state updates (e.g. custom state fields) from the model call middleware
layer. `ExtendedModelResponse` fills this gap by accepting an optional
`Command`.
This feature is needed by the summarization middleware, which needs to
track summarization trigger points calculated during `wrap_model_call`.
## Why `Command` instead of a plain `state_update` dict?
We chose `Command` rather than the raw `state_update: dict` approach
from the earlier iteration because `Command` is the established
LangGraph primitive for state updates from nodes. Using `Command` means:
- State updates flow through the graph's reducers (e.g. `add_messages`)
rather than being merged as raw dicts. This makes messages updates
additive alongside the model response instead of replacing them.
- Consistency with `wrap_tool_call`, which already returns `Command`.
- Future-proof: as `Command` gains new capabilities (e.g. `goto`,
`send`), middleware can leverage them without API changes.
## Why keep `model_response` separate instead of using `Command`
directly?
The model node needs to distinguish the model's actual response
(messages + structured output) from supplementary middleware state
updates. If middleware returned only a `Command`, there would be no
clean way to extract the `ModelResponse` for structured output handling,
response validation, and the core model-to-tools routing logic. Keeping
`model_response` explicit preserves a clear boundary between "what the
model said" and "what middleware wants to update."
Also, in order to avoid breaking, the `handler` passed to
`wrap_tool_call` needs to always return a `ModelResponse`. There's no
easy way to preserve this if we pump it into a `Command`.
One nice thing about having this `ExtendedModelResponse` structure is
that it's extensible if we want to add more metadata in the future.
## Composition
When multiple middleware layers return `ExtendedModelResponse`, their
commands compose naturally:
- **Inner commands propagate outward:** At composition boundaries,
`ExtendedModelResponse` is unwrapped to its underlying `ModelResponse`
so outer middleware always sees a plain `ModelResponse` from
`handler()`. The inner command is captured and accumulated.
- **Commands are applied through reducers:** Each `Command` becomes a
separate state update applied through the graph's reducers. For
messages, this means they're additive (via `add_messages`), not
replacing.
- **Outer wins on conflicts:** For non-reducer state fields, commands
are applied inner-first then outer, so the outermost middleware's value
takes precedence on conflicting keys.
- **Retry-safe:** When outer middleware retries by calling `handler()`
again, accumulated inner commands are cleared and re-collected from the
fresh call.
```python
class Outer(AgentMiddleware):
def wrap_model_call(self, request, handler):
response = handler(request) # sees ModelResponse, not ExtendedModelResponse
return ExtendedModelResponse(
model_response=response,
command=Command(update={"outer_key": "val"}),
)
class Inner(AgentMiddleware):
def wrap_model_call(self, request, handler):
response = handler(request)
return ExtendedModelResponse(
model_response=response,
command=Command(update={"inner_key": "val"}),
)
# Final state merges both commands: {"inner_key": "val", "outer_key": "val"}
```
## Backwards compatibility
Fully backwards compatible. The `ModelCallResult` type alias is widened
from `ModelResponse | AIMessage` to `ModelResponse | AIMessage |
ExtendedModelResponse`, but existing middleware returning
`ModelResponse` or `AIMessage` continues to work identically.
## Internals
- `model_node` / `amodel_node` now return `list[Command]` instead of
`dict[str, Any]`
- `_build_commands` converts the model response + accumulated middleware
commands into a list of `Command` objects for LangGraph
- `_ComposedExtendedModelResponse` is the internal type that accumulates
commands across layers during composition
2026-02-06 07:28:04 -05:00
ccurme
a434f3aa08
fix(langchain): bump min core version and improve approximate token counting ( #35026 )
2026-02-05 09:37:25 -05:00
Sydney Runkle
e12f592d5d
release: langchain 1.2.9 ( #35023 )
2026-02-05 09:05:59 -05:00
Sydney Runkle
dde2012b83
feat: threading context through create_agent flows + middleware ( #34978 )
...
Closes https://github.com/langchain-ai/langchain/issues/33956
* Making `ModelRequest` generic on `ContextT` and `ResponseT` so that we
can thread type information through to `wrap_model_call`
* Making builtin middlewares generic on `ContextT` and `ResponseT` so
their context and response types can be inferred from the `create_agent`
signature
See new tests that verify backwards compatibility (for cases where folks
use custom middleware that wasn't parametrized).
This fixes:
1. Lack of access to context and response types in `wrap_model_call`
2. Lack of cohesion between middleware context + response types with
those specified in `create_agent`
See examples below:
### Type-safe context and response access
```python
class MyMiddleware(AgentMiddleware[AgentState[AnalysisResult], UserContext, AnalysisResult]):
def wrap_model_call(
self,
request: ModelRequest[UserContext],
handler: Callable[[ModelRequest[UserContext]], ModelResponse[AnalysisResult]],
) -> ModelResponse[AnalysisResult]:
# ✅ Now type-safe: IDE knows user_id exists and is str
user_id: str = request.runtime.context["user_id"]
# ❌ mypy error: "session_id" doesn't exist on UserContext
request.runtime.context["session_id"]
response = handler(request)
if response.structured_response is not None:
# ✅ Now type-safe: IDE knows sentiment exists and is str
sentiment: str = response.structured_response.sentiment
# ❌ mypy error: "summary" doesn't exist on AnalysisResult
response.structured_response.summary
return response
```
### Mismatched middleware/schema caught at `create_agent`
```python
class SessionMiddleware(AgentMiddleware[AgentState[Any], SessionContext, Any]):
...
# ❌ mypy error: SessionMiddleware expects SessionContext, not UserContext
create_agent(
model=model,
middleware=[SessionMiddleware()],
context_schema=UserContext, # mismatch!
)
class AnalysisMiddleware(AgentMiddleware[AgentState[AnalysisResult], ContextT, AnalysisResult]):
...
# ❌ mypy error: AnalysisMiddleware expects AnalysisResult, not SummaryResult
create_agent(
model=model,
middleware=[AnalysisMiddleware()],
response_format=SummaryResult, # mismatch!
)
```
2026-02-05 07:41:27 -05:00
Mason Daugherty
5c018f5cd1
chore: enrich pyproject.toml files ( #34980 )
2026-02-02 13:07:05 -05:00
ccurme
9b4813f8f8
release(langchain): 1.2.8 ( #34976 )
2026-02-02 10:43:40 -05:00
John Kennedy
c5834cc028
chore: upgrade urllib3 to 2.6.3 ( #34940 )
2026-01-31 16:30:17 -05:00
Christophe Bornet
ca9d2c0bdd
test(langchain): use blockbuster to detect blocking calls in the async event loop ( #34777 )
2026-01-23 14:52:56 -05:00
Sydney Runkle
cc72a8c45a
release: langchain 1.2.7 ( #34854 )
2026-01-23 10:19:39 -05:00
Sydney Runkle
bc8620189c
feat: dynamic tool registration via middleware ( #34842 )
...
dependent upon https://github.com/langchain-ai/langgraph/pull/6711
1. relax constraint in `factory.py` to allow for tools not
pre-registered in the `ModelRequest.tools` list
2. always add tool node if `wrap_tool_call` or `awrap_tool_call` is
implemented
3. add tests confirming you can register new tools at runtime in
`wrap_model_call` and execute them via `wrap_tool_call`
allows for the following pattern
```py
from langchain_core.messages import HumanMessage, ToolMessage
from langchain_core.tools import tool
from libs.langchain_v1.langchain.agents.factory import create_agent
from libs.langchain_v1.langchain.agents.middleware.types import (
AgentMiddleware,
ModelRequest,
ToolCallRequest,
)
@tool
def get_weather(location: str) -> str:
"""Get the current weather for a location."""
return f"The weather in {location} is sunny and 72°F."
@tool
def calculate_tip(bill_amount: float, tip_percentage: float = 20.0) -> str:
"""Calculate the tip amount for a bill."""
tip = bill_amount * (tip_percentage / 100)
return f"Tip: ${tip:.2f}, Total: ${bill_amount + tip:.2f}"
class DynamicToolMiddleware(AgentMiddleware):
"""Middleware that adds and handles a dynamic tool."""
def wrap_model_call(self, request: ModelRequest, handler):
updated = request.override(tools=[*request.tools, calculate_tip])
return handler(updated)
def wrap_tool_call(self, request: ToolCallRequest, handler):
if request.tool_call["name"] == "calculate_tip":
return handler(request.override(tool=calculate_tip))
return handler(request)
agent = create_agent(model="openai:gpt-4o-mini", tools=[get_weather], middleware=[DynamicToolMiddleware()])
result = agent.invoke({
"messages": [HumanMessage("What's the weather in NYC? Also calculate a 20% tip on a $85 bill")]
})
for msg in result["messages"]:
msg.pretty_print()
```
2026-01-23 10:12:48 -05:00
Mason Daugherty
624799838c
release(langchain): 1.2.6 ( #34781 )
2026-01-16 14:19:33 -05:00
ccurme
57279c7b81
release(langchain): 1.2.5 ( #34772 )
2026-01-16 11:07:20 -05:00
Sydney Runkle
1d60235b1b
release: langchain 1.2.4 ( #34755 )
2026-01-14 14:24:31 -05:00
Mason Daugherty
3d687ea8fb
chore: update twitter URLs ( #34736 )
2026-01-13 01:54:11 -05:00
Christophe Bornet
a7b943bbe3
fix(langchain): activate test_return_direct_spec tests, fix types ( #34565 )
...
Co-authored-by: Mason Daugherty <mason@langchain.dev >
Co-authored-by: Mason Daugherty <github@mdrxy.com >
2026-01-09 22:52:12 -05:00
Christophe Bornet
ecd19ff71f
chore(langchain): activate mypy warn_return_any rule ( #34549 )
...
Co-authored-by: Mason Daugherty <github@mdrxy.com >
Co-authored-by: Mason Daugherty <mason@langchain.dev >
2026-01-09 22:46:25 -05:00
Christophe Bornet
606ef38e74
chore(langchain): improve ignore_missing_imports config ( #34551 )
...
Co-authored-by: Mason Daugherty <mason@langchain.dev >
2026-01-09 22:18:45 -05:00
Christophe Bornet
36e590ca5f
test(langchain): complete and activate test_responses tests ( #34560 )
...
Co-authored-by: Mason Daugherty <github@mdrxy.com >
Co-authored-by: Mason Daugherty <mason@langchain.dev >
2026-01-09 22:17:03 -05:00
Christophe Bornet
fc417aaf17
fix(langchain): activate mypy warn-unreachable ( #34553 )
...
Co-authored-by: Mason Daugherty <mason@langchain.dev >
2026-01-09 22:11:16 -05:00
Christophe Bornet
9ce73a73f8
test(langchain): activate test_responses_spec tests ( #34564 )
...
description by @mdrxy
- Enable `test_responses_spec.py` integration tests that were previously
skipped at module level
- Widen `ToolStrategy.schema` type annotation from `type[SchemaT]` to
`type[SchemaT] | dict[str, Any]` to match actual supported usage (JSON
schema dicts were already handled at runtime)
- Fix type annotations and linting issues in test file (modernize to
`dict`/`list`, add return types, prefix unused `_request` param)
- Improve generic typing in `load_spec` utility with bounded `TypeVar`
Co-authored-by: Mason Daugherty <mason@langchain.dev >
2026-01-09 17:44:33 -05:00
Christophe Bornet
8e824d9ec4
style: bump ruff version to 0.14.11 ( #34674 )
...
With ruff 0.14.11+, we can remove `PLW1510` from `unfixable` (see
https://github.com/astral-sh/ruff/issues/17091 )
2026-01-09 16:30:24 -05:00
Sydney Runkle
fbe9babb34
fix: remove relative imports ( #34680 )
...
standardizing on absolute imports rather than relative across the
codebase
2026-01-09 13:00:51 -05:00
Mason Daugherty
76da99e022
release(langchain): 1.2.3 ( #34668 )
2026-01-08 15:24:32 -05:00
Eugene Yurtsev
5554a36ad5
release(langchain): release 1.2.2 ( #34643 )
...
Release langchain 1.2.2
2026-01-07 17:27:58 -05:00
Mason Daugherty
aa9c63b96a
release(langchain): 1.2.1 ( #34622 )
2026-01-06 19:10:49 -05:00
Christophe Bornet
e5d4acf681
style(langchain): add ruff rule PLC0415 ( #34559 )
2026-01-04 01:26:04 -05:00
Christophe Bornet
e03d6b80d5
chore(deps): bump mypy to v1.19 and ruff to v1.14 ( #34521 )
...
* Set mypy to >=1.19.1,<1.20
* Set ruff to >=0.14.10,<0.15
2025-12-29 18:07:55 -06:00
Christophe Bornet
0bd862b814
style(langchain): add ruff rule RUF012 ( #34497 )
...
Co-authored-by: Mason Daugherty <mason@langchain.dev >
Co-authored-by: Mason Daugherty <github@mdrxy.com >
2025-12-27 01:36:47 -06:00
Christophe Bornet
d46187201d
style: add ruff ISC001 rule ( #34493 )
...
ISC001 doesn't conflict anymore with the formatter. See
https://github.com/astral-sh/ruff/issues/8272
Co-authored-by: Mason Daugherty <mason@langchain.dev >
2025-12-26 21:39:56 -06:00
Christophe Bornet
3d78cc69f1
style(langchain): add TC ruff rules ( #34496 )
...
Co-authored-by: Mason Daugherty <mason@langchain.dev >
2025-12-26 21:37:57 -06:00
Christophe Bornet
6a416c6186
style(langchain): add ruff rules PT ( #34434 )
2025-12-21 19:31:50 -06:00
ccurme
9f61ed8b81
release(langchain): 1.2 ( #34373 )
2025-12-15 09:49:49 -05:00
Christophe Bornet
3fb90666be
chore(langchain): cleanup ruff config ( #32810 )
...
Co-authored-by: Mason Daugherty <mason@langchain.dev >
Co-authored-by: Sydney Runkle <54324534+sydney-runkle@users.noreply.github.com >
Co-authored-by: Sydney Runkle <sydneymarierunkle@gmail.com >
2025-12-12 09:08:48 -05:00
Christophe Bornet
bbc1d46efe
chore(langchain): check agents integration tests with mypy ( #34308 )
2025-12-12 07:55:34 -05:00