chore(deps): update python minor/patch #178

Open
renovate-bot wants to merge 1 commit from renovate/python-minorpatch into main
Contributor

This PR contains the following updates:

Package Change Age Confidence
alembic (changelog) ==1.18.5 → ==1.20.1 age confidence
asyncpg ==0.31.0 → ==0.32.0 age confidence
authlib ==1.7.2 → ==1.9.5 age confidence
fastapi (changelog) ==0.140.7 → ==0.162.2 age confidence
pydantic-settings (changelog) ==2.14.2 → ==2.16.2 age confidence
pytest (changelog) ==9.1.1 → ==9.2.0 age confidence
python-dotenv ==1.2.2 → ==1.2.4 age confidence
python-multipart (changelog) ==0.0.32 → ==0.0.33 age confidence
ruff (source, changelog) ==0.16.10 → ==0.17.4 age confidence
sqlalchemy (changelog) ==2.0.51 → ==2.1.8 age confidence
starlette (changelog) ==1.8.0 → ==1.10.0 age confidence
timezonefinder ==8.2.5 → ==8.3.0 age confidence
twilio ==9.10.9 → ==9.13.0 age confidence
uvicorn (changelog) ==0.51.0 → ==0.54.0 age confidence

Release Notes

MagicStack/asyncpg (asyncpg)

v0.32.0

Compare Source

Improvements

Fixes

  • Clean up connections rejected by target_session_attrs immediately so an
    unresponsive rejected host cannot delay the selected connection, and cleanup
    tasks cannot outlive the event loop. Rejected connections are aborted without
    waiting for a graceful disconnect; servers may log "unexpected EOF on client
    connection" if the Terminate message is not delivered before the transport
    closes.

  • Fix a connection pool deadlock when releasing a connection after a protocol
    abort (#​1324)
    (by @​pchaseh in 4a83cc2)

  • Honor Connection.close(timeout=...) while waiting for a pending
    cancellation (#​1361)
    (by @​gyanu2507 in c06bcb4)

  • Prevent stuck cancellation from blocking connection teardown or pool release
    by bounding cancellation with the command or release timeout (#​1370)
    (by @​elprans in 4cf0220)

  • Preserve the server error when the connection closes mid-operation (#​1369)
    (by @​RitiGrover in 6c8f1a7)

  • Fix COPY cleanup when a records generator raises, preserving the original
    exception and avoiding protocol desynchronization and stalled rollback (#​1358)
    (by @​CodingCossack in fdc6bc8)

  • Reparse unnamed statements before cursor binding when the statement cache
    is disabled (#​1364)
    (by @​elprans in 302ba49)

  • Allow cursors in transactions started outside Connection.transaction(),
    such as with an explicit BEGIN (#​1350)
    (by @​aryansk in 25aaaf5)

  • Remove the query logger when the query_logger() block raises (#​1373)
    (by @​kratos0718 in 6a7fbd3)

  • Fix a segfault in Record.get() with an invalid number of positional
    arguments (#​1333)
    (by @​apoorvdarshan in 40a3832)

  • Align SSL startup retries with libpq and improve SSL rejection diagnostics
    (#​1366). Retry alternative transports only before authentication succeeds.
    Direct TLS now requires sslmode=require, verify-ca, or verify-full,
    or an explicit SSLContext.
    (by @​elprans in 78752c9)

  • Preserve password errors during SSL fallback when the fallback fails with
    a less specific authorization error (#​1331)
    (by @​Mauricio0129 in 2d97947)

  • Handle cleartext password authentication when no password is supplied
    without raising an AttributeError (#​1351)
    (by @​aryansk in 6be5915)

  • Set the postgresql ALPN protocol on SSL contexts created by asyncpg so
    direct TLS connections work with PostgreSQL 17 and later (#​1372).
    User-provided contexts must set this protocol for direct TLS connections.
    (by @​DurandA in b21325d)

  • Link explicitly against libm on non-Windows platforms to fix undefined
    math symbol errors when loading the extensions (#​1305)
    (by @​veeceey in db8ecc2)

  • Fix builds on FreeBSD 15 by linking against libstdthreads (#​1368)
    (by @​elprans in 87bcaf9)

Other

authlib/authlib (authlib)

v1.9.5

Compare Source

Changelog: https://docs.authlib.org/en/stable/upgrades/changelog.html#changelog-1-9-5

Full Changelog: https://github.com/authlib/authlib/compare/v1.9.4...v1.9.5

v1.9.4

Compare Source

Changelog: https://docs.authlib.org/en/stable/upgrades/changelog.html#changelog-1-9-4

Full Changelog: https://github.com/authlib/authlib/compare/v1.9.3...v1.9.4

v1.9.3

Compare Source

Changelog: https://docs.authlib.org/en/stable/upgrades/changelog.html#changelog-1-9-3

Full Changelog: https://github.com/authlib/authlib/compare/v1.9.2...v1.9.3

v1.9.2

Compare Source

Changelog: https://docs.authlib.org/en/stable/upgrades/changelog.html#changelog-1-9-2

Full Changelog: https://github.com/authlib/authlib/compare/v1.9.1...v1.9.2

v1.9.1

Compare Source

Changelog: https://docs.authlib.org/en/stable/upgrades/changelog.html#changelog-1-9-1

What's Changed

Full Changelog: https://github.com/authlib/authlib/compare/v1.9.0...v1.9.1

v1.9.0

Compare Source

What's Changed

New Contributors

Full Changelog: https://github.com/authlib/authlib/compare/v1.8.0...v1.9.0

v1.8.0

Compare Source

What's Changed

New Contributors

Full Changelog: https://github.com/authlib/authlib/compare/v1.7.2...v1.8.0

fastapi/fastapi (fastapi)

v0.162.2

Compare Source

FastAPI includes an official skill that helps coding agents use new features and recommended patterns for your installed version. Install it with uvx library-skills in your project. See Develop with AI.

Docs
Internal

v0.162.1

Compare Source

Docs
Translations
Internal

v0.162.0

Compare Source

Omitted bool and bool | None form fields now use their declared defaults or produce missing-field errors, consistent with other fields and Pydantic behavior. FastAPI no longer infers False for omitted booleans. This applies to individual form parameters, form models, and unions of form models.

Omitted boolean model fields are excluded from model_dump(exclude_unset=True), and their defaults no longer count as submitted fields during union selection. Default factories and validate_default follow the usual rules.

For HTML checkboxes, declare a boolean with a default of False. See Boolean Form Fields.

Breaking Changes

v0.161.1

Compare Source

Fixes

v0.161.0

Compare Source

Features

v0.160.0

Compare Source

Query, header, cookie, and form parameter models now apply their extra configuration to all submitted fields in the same parameter location, consistent with Pydantic behavior. This includes fields declared in other models, individual parameters, or dependencies, which were previously excluded.

With extra="forbid", fields outside the model are rejected even if another parameter declares them. With extra="allow", those fields are included as model extras. With the default extra="ignore", they are ignored.

Breaking Changes
Internal

v0.159.1

Compare Source

Features

v0.159.0

Compare Source

Features

v0.158.2

Compare Source

Features

v0.158.1

Compare Source

Fixes

v0.158.0

Compare Source

Features

v0.157.0

Compare Source

Features
  • ✨ Add support for combining query, header, and cookie parameter models. PR #​16573 by @​tiangolo.
Docs
Internal

v0.156.8

Compare Source

Fixes

v0.156.7

Compare Source

Fixes

v0.156.6

Compare Source

Fixes
  • 🐛 Respect model alias settings for query, header, and cookie parameters. PR #​16562 by @​tiangolo.

v0.156.5

Compare Source

Fixes

v0.156.4

Compare Source

Fixes

v0.156.3

Compare Source

Fixes

v0.156.2

Compare Source

Fixes

v0.156.1

Compare Source

Fixes

v0.156.0

Compare Source

Fixes

v0.155.0

Compare Source

The deprecated **extra keyword arguments have been removed from Path, Query, Header, Cookie, Body, Form, and File. Unknown keyword arguments now raise TypeError. For additional JSON Schema properties, replace, for example, Query(custom="value") with Query(json_schema_extra={"custom": "value"}).

Breaking Changes

v0.154.0

Compare Source

Features

v0.153.0

Compare Source

Unions of form models now apply the same browser form handling as individual models. Empty scalar fields use defaults or produce missing-field errors, empty list items are preserved, omitted boolean fields become False, and unselected files are treated as missing. JSON request bodies are unchanged.

Fixes

v0.152.0

Compare Source

Validation errors for header parameter models now report the HTTP header name, such as int-val, instead of the Python field name, int_val. Explicit aliases, Header(convert_underscores=False), and Pydantic models with loc_by_alias=False keep their existing behavior.

Fixes

v0.151.0

Compare Source

JSON request bodies now distinguish an explicit null from an omitted value. For individual Body parameters, null is validated as None: nullable types accept it, and non-nullable types reject it even when a default is defined. Defaults and default factories apply only when the value is omitted. This applies both to parameters inside JSON objects and to parameters representing the entire body. Clients that used null to request a default should omit the value instead.

When a JSON object is expected because of Body(embed=True) or multiple body parameters, sending null as the entire body now returns a validation error.

Breaking Changes

v0.150.0

Compare Source

When no file is selected, browsers submit a file part with an empty filename and empty content. FastAPI now treats this as missing: required file fields return a validation error, and fields with defaults or default factories use them. Unselected inputs are ignored in lists of files. Named zero-byte files are still accepted.

Breaking Changes

v0.149.0

Compare Source

Browsers submit empty text inputs as empty strings (""). FastAPI now treats empty scalar form values as missing in form models, matching individual Form parameters. Required fields return a validation error. Fields with defaults or default factories use them and remain unset in model_dump(exclude_unset=True).

Empty strings inside lists are preserved. Omitted boolean form fields still become False. JSON requests and direct Pydantic validation are unchanged.

Breaking Changes

v0.148.0

Compare Source

Defaults for omitted Query, Header, Cookie, and Form parameters and model fields are no longer treated as user input. Defaults are not validated unless validate_default=True is enabled. If you rely on validators running for omitted values, enable default validation with Field(validate_default=True) for model fields or, for example, Query(validate_default=True) for individual parameters. Body(validate_default=True) is now honored too.

For parameter models, applying a default no longer marks a field as explicitly set, so model_dump(exclude_unset=True) excludes it. Default factories run once, and validation errors no longer include injected defaults in input.

Omitted boolean form fields still become False and count as explicitly set.

Breaking Changes

v0.147.0

Compare Source

Omitted bool and bool | None form fields are now interpreted as False, matching unchecked HTML checkboxes. This applies to individual Form parameters and form models, including required fields and fields with defaults of True or None. The inferred value is considered explicitly set, including in model_dump(exclude_unset=True).

JSON requests and direct Pydantic validation are unchanged. See Boolean Form Fields.

Breaking Changes
Internal

v0.146.0

Compare Source

The root_path parameter in FastAPI() is deprecated. Configure the server with fastapi run --root-path /api/v1 instead.

Breaking Changes

v0.145.0

Compare Source

Breaking Changes
Docs

v0.144.0

Compare Source

Features

v0.143.5

Compare Source

Fixes
  • 🐛 Fix handling of empty value for byte file list parameter. PR #​9383 by @​Viicos.

v0.143.4

Compare Source

Upgrades

v0.143.3

Compare Source

Fixes
Docs

v0.143.2

Compare Source

Fixes
Translations
Internal

v0.143.1

Compare Source

Fixes

v0.143.0

Compare Source

Automatic OpenTelemetry exporter setup is now opt-in. If you rely on FastAPI to configure exporters from OTEL_* environment variables, set FASTAPI_OTEL_AUTO_CONFIGURE=true or use FastAPI(telemetry={"auto_configure": True}) to retain the previous behavior.

Applications that configure their own providers and exporters require no changes. FastAPI Cloud enables automatic setup for you.

Breaking Changes

v0.142.4

Compare Source

Fixes

v0.142.3

Compare Source

Fixes
Docs
Translations
Internal

v0.142.2

Compare Source

Fixes

v0.142.1

Compare Source

Fixes

v0.142.0

Compare Source

Features
Refactors
Docs
Translations
Internal

v0.141.1

Compare Source

Fixes
  • 🐛 Fix support for background tasks and headers from dependencies in app.frontend(). PR #​16105 by @​tiangolo.
Docs

v0.141.0

Compare Source

Features
  • ✨ Add app.frontend(check_dir="auto"), to make local development more convenient with fastapi dev. PR #​16102 by @​tiangolo.

v0.140.13

Compare Source

Fixes
Docs

v0.140.12

Compare Source

Fixes

v0.140.11

Compare Source

Fixes
  • 🐛 Fix response_model_* params ignored for non-generator endpoints with Iterable[..] return type. PR #​15093 by @​YuriiMotov.

v0.140.10

Compare Source

Fixes
Internal

v0.140.9

Compare Source

Fixes
  • 🐛 Fix exclude_defaults not propagated to dict keys and values in jsonable_encoder. PR #​16043 by @​MBGrao.
Internal

v0.140.8

Compare Source

Fixes
pydantic/pydantic-settings (pydantic-settings)

v2.16.2

Compare Source

v2.16.1

Compare Source

Highlights

This patch release fixes two CLI regressions introduced in 2.16.0.

Bug fixes

CLI

  • Fixed-length tuple positionals such as CliPositionalArg[tuple[int, int]] and NamedTuples are single-valued again (#​1069). Since 2.16.0 they were treated as variadic, so a CLI either refused to start with a SettingsError or put the wrong argument into the tuple. Variable-length tuples (tuple[int, ...] and bare Tuple) are still variadic.
  • A field typed as an alias of a list of dicts, e.g. type ListOfDict = list[dict[str, int]], accepts a JSON list again (#​1049). Since 2.16.0, --xx '[{"a":1},{"b":2}]' was merged into the single dict {"a": 1, "b": 2} and failed validation.
All changes (including dependency bumps and internal maintenance)

What's Changed

Full Changelog: https://github.com/pydantic/pydantic-settings/compare/v2.16.0...v2.16.1

v2.16.0

Compare Source

Highlights

Breaking changes and behavior changes
  • Python 3.10 is no longer supported (#​1003). pydantic-settings now requires Python 3.11+, since 3.10 reaches end of life this month. The tomli fallback is gone in favor of stdlib tomllib; the toml extra is kept as an empty extra so pip install pydantic-settings[toml] keeps working.
  • python-dotenv>=1.2.2 is now required (#​971) to pick up the fix for CVE-2026-28684.
  • Aliases are ignored in every source when validate_by_alias=False (#​1033). Env vars, secrets, CLI flags and defaults now use only field names, matching pydantic. An env var named after the alias is now ignored instead of raising extra_forbidden, and the CLI exposes --apple rather than --pomo.
  • validation_alias takes precedence over alias (#​1038). When the two differ, values from JSON/YAML/TOML files and the CLI were silently ignored; they now load. CLI help lists the validation_alias flag first, and CliApp.serialize emits it.
  • CLI case-insensitivity only lowercases registered options (#​1036). With case_sensitive=False, args after -- and those captured by CliUnknownArgs keep their case (-Xmx4G no longer becomes -xmx4g). Unrecognized options are now reported as typed (--NOPE instead of --nope).
  • JSON and YAML config files are read as UTF-8 by default (#​955) instead of the locale encoding, completing the secrets-file fix from 2.15.0. json_file_encoding/yaml_file_encoding still override it.
  • Discriminated union defaults are partially updated again (#​997). This reverts the 2.15.0 regression with nested_model_default_partial_update=True: the default is only dropped when the incoming value selects a different union member.
New features
  • Python 3.15 and pydantic 2.14 support (#​1026, #​1029, #​1022). pydantic 2.14 broke CliApp.run and validate_by_alias=False handling; both are fixed.
  • Cached settings instances via Settings.settings_cached() and Settings.settings_clear_cache() (#​952). These give you a process-local singleton per settings class without hand-rolling lru_cache wrappers. Calling the class directly still builds a fresh instance.
  • AWS Systems Manager Parameter Store source — AWSSystemsManagerSettingsSource (#​941). It recursively reads every parameter under an ssm_path, with / mapping onto nested models. Install it with the new aws-systems-manager extra.
  • env_file_depth (#​940) lets a relative env_file be found in parent directories, mirroring pyproject_toml_depth. This is useful when scripts run from a subdirectory of a monorepo. It defaults to 0, which keeps the current behavior.
  • CliVariadicArg for named variadic options (#​949, #​958). It accepts --param a b c in addition to repeated --param a --param b. Required fields need at least one value.
Bug fixes

CLI

  • CliApp.serialize output now round-trips through CliApp.run for enums, tuples, dates and Decimals (#​988), explicit None values (#​981), empty containers (#​1008), CliVariadicArg values (#​976) and populated CliUnknownArgs fields, which previously raised IndexError (#​992).
  • Empty JSON arrays (--items []) now give an empty list instead of [''] (#​994).
  • Tuples, frozenset, MutableSequence and other collection subtypes are now treated as repeatable/variadic options (#​972), and so are named collection type aliases such as TypeAliasType('Addrs', list[IPvAnyAddress]) (#​1032).
  • cli_exit_on_error=False is now honored in CliSubCommand parsers, which raise SettingsError instead of exiting (#​977).
  • CliSubCommand aliases keep their case with case_sensitive=False (#​989).
  • Each CliUnknownArgs field now receives only its own subcommand's leftover args (#​1004).
  • CliApp.format_help no longer crashes when cli_prefix is set in model_config (#​945).

Type aliases and parsing

  • Named union type aliases (TypeAliasType('V', list[int] | str)) now decode like their inline equivalents in env and dotenv sources, including under Optional, Annotated and custom validation aliases (#​1006, #​1030, #​1041).
  • Resolving a named Annotated type alias no longer mutates shared FieldInfo metadata, which made validators run twice on subclasses or after model_rebuild() (#​979).
  • A bare single-segment AliasPath('SOME_KEY') no longer tries to JSON-decode plain string values (#​980).
  • collections.abc.Set/MutableSet/typing.AbstractSet fields now JSON-decode env values (#​973).
  • A bare typing.Dict field with env_nested_delimiter no longer raises IndexError, which was a regression in 2.13.0 (#​1009).
  • Case-insensitive matching now works for nested pydantic dataclasses (#​1010).

Dotenv, secrets and config files

  • With extra='allow', a non-lowercase env_prefix is now stripped from dotenv extras (#​959, #​968).
  • secrets_case_sensitive=True is now honored on Windows (#​1001).
  • An empty JSON config file is treated as an empty mapping instead of crashing (#​947), matching YAML and TOML.
  • TOML table headers: ~ paths are now expanded when checking that the file exists (#​1034), and an explicit toml_table_header=() now overrides the model config to read the file root (#​1027).

Cloud sources

  • Azure Key Vault and GCP Secret Manager now honor env_parse_none_str (#​1019, #​1040).
  • Azure Key Vault: dash_to_underscore=True now works for nested model fields (#​1025).
  • NestedSecretsSettingsSource now validates its specific constructor arguments (#​975).
  • DotenvFiltering is exported from pydantic_settings.sources.types (#​944).
Documentation
  • Document that runtime validation arguments (strict, extra, context) passed to model_validate() are not applied to BaseSettings, and give a workaround (#​1017).
  • Explain why extra='forbid' doesn't reject misspelled top-level env vars (#​986).
  • Clarify alias plus nested model env lookup with populate_by_name (#​933), and add a nested model example for env_prefix_target (#​953).
  • Fix assorted typos (#​942, #​964).
All changes (including dependency bumps and internal maintenance)

What's Changed

New Contributors

Full Changelog: https://github.com/pydantic/pydantic-settings/compare/v2.15.0...v2.16.0

v2.15.0

Compare Source

Highlights

Behavior changes
  • case_sensitive now applies to init kwargs and config-file sources (#​900). InitSettingsSource and the JSON/TOML/YAML config sources previously ignored case_sensitive. Since it defaults to False, case-insensitive matching is now the default for these sources — e.g. Settings(TeSt=...) now populates a test field where it previously did not. Nested keys are still matched case-sensitively.
  • Fields with unresolved forward references now emit a warning (#​901). Settings sources can silently fail to resolve such fields; they now raise IncompleteFieldDefinitionWarning telling you to call model_rebuild(). If you have filterwarnings = error configured, this may surface as a new failure.
  • Non-JSON env values for strict fields now raise ValidationError (#​926) instead of a less specific error.
New features
  • Show environment variable names in CLI help via cli_show_env_vars=True (#​860), so generated --help output doubles as configuration documentation.
  • PYDANTIC_SETTINGS_DEBUG for debugging settings resolution (#​906, #​913). Set it to a truthy value with DEBUG logging enabled to see each source's contribution in priority order, which source won for each value, and which env_file/secret files were probed, loaded, or skipped — the long-standing "why isn't my .env being picked up?" question.
  • toml_table_header for regular TOML files (#​882, #​886, #​887), letting you root settings at a nested table in any TOML file, not just pyproject.toml.
  • Traversable support for JSON/TOML/YAML file sources (#​902), so you can load config packaged inside a distribution — including files inside a zip or wheel — via importlib.resources.files(...) without casting to Path.
  • GCP: project_id can come from an earlier settings source (#​878), rather than only from the constructor or GOOGLE_CLOUD_PROJECT.
Bug fixes
  • Fix env vars not loading on Windows with case_sensitive=True (#​894). Windows upper-cases os.environ keys, so fields raised Field required instead of picking up their values.
  • Read secret files as UTF-8 instead of the platform locale encoding (#​917). On Windows code pages such as cp1252 this silently corrupted non-ASCII secrets.
  • Fix AliasPath on nested model fields not JSON-decoding env values (#​898).
  • Fix case-insensitive matching for optional nested models (#​905).
  • Fix dotenv extras being wrongly claimed by a complex field sharing a name prefix (#​912) — e.g. dbx_token being swallowed by a db: dict field.
  • Fix nested_model_default_partial_update=True corrupting discriminated unions (#​876).
  • Fix Secret subclasses crashing when loaded from the environment (#​920).
  • Fix enum names not parsing through nested annotations such as Optional[Annotated[MyEnum, ...]] with env_parse_enums=True (#​910).
  • An empty yaml_config_section now falls back to defaults instead of raising AttributeError: 'NoneType' object has no attribute 'keys' (#​914).
  • NestedSecretsSettingsSource no longer follows symlinks pointing outside secrets_dir (#​889).
  • GCP: skip the list_secrets call when case_sensitive=True (#​862), lowering the required IAM permissions to just roles/secretmanager.secretAccessor.
  • AWS: types-boto3[secretsmanager] is no longer required at runtime (#​880).
Documentation
  • Document JSON parsing of complex env values, plus a comma-separated-values recipe (#​919).
  • Recommend an async settings loading pattern (#​908).
  • Clarify behavior when an unprefixed value is present in a dotenv file (#​895).
  • Clarify environment variable helper descriptions (#​867) and fix assorted typos (#​904).
All changes (including dependency bumps and internal maintenance)

What's Changed

New Contributors

Full Changelog: https://github.com/pydantic/pydantic-settings/compare/v2.14.1...v2.15.0

pytest-dev/pytest (pytest)

v9.2.0

Compare Source

pytest 9.2.0 (2026-10-27)

Removals and backward incompatible breaking changes

  • #​14716: -c now raises a usage error for a path that does not exist, is a directory, or is in a format pytest has no loader for. Such paths were previously either ignored or reported as an unhandled FileNotFoundError.

  • #​8593: The indirect, ids and scope arguments of Metafunc.parametrize() <pytest.Metafunc.parametrize> -- and therefore of @pytest.mark.parametrize <pytest.mark.parametrize ref> -- are now keyword-only.

    Passing them positionally was a common source of confusing errors, e.g. parametrize("arg1", "arg2", [(1, 2)]) made the argvalues land in indirect and failed with indirect fixture '(1, 2)' doesn't exist; such mistakes now fail with an understandable TypeError. The type annotations have always declared these arguments as keyword-only.

  • #​993: Plugin import failures at startup are now reported and classified instead of escaping as a raw traceback with the accidental exit code 1:

    • a plugin that cannot be found -- via -p, pytest_plugins or PYTEST_PLUGINS -- exits with pytest.ExitCode USAGE_ERROR (4), like a conftest.py that fails to import;
    • a plugin that is found but raises while importing -- including a broken pytest11 entry point or a missing plugin dependency -- exits with pytest.ExitCode INTERNAL_ERROR (3), with the traceback preserved.

    pytest.main now returns these codes instead of raising ImportError. Also fixed an IndexError from pytest's own internals when the plugin raised an exception with no arguments.

Deprecations (removal in next major release)

  • #​14742: The private _pytest.python.CallSpec2 name has been renamed to CallSpec.
    The old CallSpec2 alias remains available for now and will be removed in pytest 10 or 11.

  • #​14755: Schedule yield_fixture decorator for removal in pytest 10 or 11.

  • #​14774: Similarly to the deprecation of class-scoped fixtures defined as instance methods in pytest 9.1,
    all higher-scoped fixtures (module, package, and session) defined
    as instance methods are now deprecated.

    They suffer from the same issue the original deprecation only fixed for
    class-scoped fixtures, see 10819 and 14011.

  • #​14808: Passing a non-string value to a string-typed ini option now emits a pytest.PytestRemovedIn10Warning. This affects [tool.pytest.ini_options] in pyproject.toml. In pytest 10 this will raise a TypeError, matching the behavior of the corresponding TOML config path.

  • #​7323: Passing bytes to TerminalReporter.write_line() is now deprecated, pass a str instead.

New features

  • #​14743: Full diff: now contains a legend explaining the + & - symbols in diff output.
  • #​2781: When strict_markers is enabled, marker names used in -m expressions are now validated against registered markers.
  • #​6881: Added the parametrize_long_str_id_strategy configuration option to control how long str/bytes parameter values are handled in auto-generated test IDs. Explicit IDs set via ids=[...] or pytest.param(..., id=...) are not affected. Available strategies: short (default, values over 100 chars fall back to argname+index), sha256 (SHA-256 hex digest), legacy (keep full value), and disallow (error requesting explicit IDs).

Improvements in existing functionality

  • #​10745: A RecursionError whose recursion origin cannot be located now shows only the
    first and last 10 stack frames, matching what pytest already did when locating
    the origin failed outright. Previously the full traceback -- often around a
    thousand near-identical frames -- was rendered, which was both slow and
    unreadable. Pass --full-trace to see every frame.

  • #​10745: The line numbers of a module's statements are now computed once per traceback
    instead of once per traceback entry, which noticeably speeds up rendering
    failures raised from large test modules.

  • #​11418: The cached rewritten modules in __pycache__ are now invalidated by a hash of
    the source instead of its modification time, using the checked-hash pyc format
    from 552.

    Timestamps make the cache useless wherever source files get fresh modification
    times, most notably in CI: a checkout gives every file a new mtime, so a
    restored cache is discarded in full and every test module is rewritten again.
    Hashing the source costs roughly 15 microseconds per file and makes the cache
    survive that.

    Existing timestamp based caches are ignored and rewritten once.

  • #​12624: The pytest_plugins variable and the PYTEST_PLUGINS environment variable now also accept entry point names of installed plugins (e.g. xdist), in addition to importable module names, matching the behavior of the -p command-line option.

    As part of this change, plugins specified by entry point name through these mechanisms are now also listed in the plugins: line of the terminal header (12615).

    Based on the original implementation by Marcel Telka in 12616.

  • #​12697: Warnings emitted while importing plugins through -p, PYTEST_PLUGINS, or entry point autoloading are now captured, filtered, and reported like other warnings.

  • #​12860: Assertion diffs for dict.items() and dict.keys() comparisons (>=, <=, >, <, ==) now show which items are missing, the same way set comparisons do.

  • #​13354: Node.get_closest_marker <_pytest.nodes.Node.get_closest_marker> now also accepts a ~pytest.MarkDecorator as its default, for example item.get_closest_marker("foo", pytest.mark.foo(1)), and returns the wrapped ~pytest.Mark.

    Previously the only way to build a default was to instantiate ~pytest.Mark directly, which is private and warns.

  • #​13369: Improved the error from pytest.RunResult.assert_outcomes when a plugin changes or removes pytest's standard terminal summary, and documented how to isolate output-changing plugins.

  • #​13431: Exposed pytest.ParameterSet as the type of the return value of pytest.param().
    This can be used in type annotations and isinstance checks.

  • #​13564: Issue a warning when fixtures are wrapped with a decorator that prevents
    correct discovery, including @classmethod above @pytest.fixture and
    @staticmethod above @pytest.fixture. Put @pytest.fixture above
    those decorators on test classes.

  • #​14164: Exposed pytest.Approx as the type of the return value of pytest.approx().
    This can be used in type annotations and isinstance checks.

  • #​14463: Assertion diffs for mappings now match up keys the way the compared mappings match them themselves.

    Key comparison goes through the mappings' key views instead of plain sets of their keys, so a mapping
    with its own notion of key equivalence, such as case-insensitive header mappings, no longer
    reports its common keys as missing on either side.

  • #​14523: Large assertion comparison diffs are now built lazily and capped to the
    truncation budget, so a huge diff is no longer formatted in full just to
    be truncated. As a consequence, the truncation footer no longer
    reports the exact number of hidden lines.

  • #​14687: The default fd-level output capturing (--capture=fd) now skips reading the capture buffer for tests which produce no output, reducing per-test overhead in large test suites.

  • #​14724: --no-summary now only applies directly to pytest's own summary.

    The flag no longer skips the pytest_terminal_summary hook, so third-party
    plugins (for example coverage) can still write their terminal summaries.

  • #​14751: parser.addini <pytest.Parser.addini> now also accepts type expressions for its type argument, in addition to the existing string tags: the plain Python types str, bool, int, float, a Literal of strings, and unions of these (for example int | str or int | Literal["auto"]).

  • #​14754: pytest.approx() now rejects infinite relative tolerances for datetime.timedelta values with a clear ValueError instead of raising OverflowError.

  • #​14791: The junit_family, junit_logging, junit_duration_report, console_output_style, empty_parameter_set_mark, assertion_text_diff_style and tmp_path_retention_policy configuration options are now registered with the set of values they accept: an invalid value now fails with a clean usage error instead of being silently ignored or crashing later, and pytest --help lists the accepted values.

    config.getini <pytest.Config.getini> now raises pytest.UsageError instead of TypeError or ValueError when the value read from the configuration file does not match the registered type, so a bad value is always reported as a short usage error message instead of an internal error traceback. Asking for an option name that was never registered still raises ValueError.

  • #​15006: pytest.approx now emits pytest.PytestApproxDecimalToleranceWarning when a rel or abs tolerance is given as a float that cannot be represented exactly for a ~decimal.Decimal comparison, since such a tolerance is widened to the float's exact binary value.

  • #​14675, #​14953, #​15153, #​15132: The truncation_limit_lines, truncation_limit_chars, max_warnings, verbosity_assertions, verbosity_test_cases, verbosity_subtests, tmp_path_retention_count, log_level, log_cli_level, log_file_level,log_auto_indent and faulthandler_timeout configuration options now accept native integer (and, for log_auto_indent, boolean) values in TOML configuration files, while still accepting strings for backward compatibility.
    log_file_mode now reports invalid values as a usage error.

  • #​15254: tmp_path and TempPathFactory.mktemp <pytest.TempPathFactory.mktemp> no longer list the whole base temporary directory on every call, which made sessions with many temporary directories quadratically slow. Numbers are now handed out from a per-prefix counter, skipping names that already exist.

  • #​4569: Node.add_marker <_pytest.nodes.Node.add_marker> now stores a ~pytest.Mark in node.keywords, matching what marks applied during collection store. Previously it stored a ~pytest.MarkDecorator.

  • #​9436: Avoided formatting tracebacks for tests marked with xfail(run=False).

Bug fixes

  • #​10128: Configured warning filters now apply to warnings emitted by pytest_configure hooks.

  • #​10210: pytest.approx now raises a TypeError for any nested container, not
    only for one of the same type as its parent. Previously approx([{"k": 1}])
    and approx({"k": [1]}) were accepted and then compared unequal to every
    value, silently ignoring the tolerance, while approx([[1]]) correctly
    reported that nesting is unsupported.

  • #​10644: monkeypatch.setattr() no longer leaves a new entry in the instance __dict__ when it patches an attribute that the instance inherits from its class.

    Previously undo() assigned the inherited value onto the instance, which shadowed the class attribute -- permanently freezing the result for descriptors that resolve dynamically.

  • #​1139: Fixed tracebacks showing ??? instead of source lines for code compiled with a filename relative to a directory other than the current working directory -- e.g. compiled Cython modules, when running pytest from a subdirectory of the project root.
    The source lookup now falls back to searching sys.path for such filenames, as the standard traceback module does.

  • #​11502: The rootdir is no longer derived from a configuration file that is not a regular file, such as --config-file=/dev/null.

  • #​11783: Plugins installed in editable mode (660) are marked for assertion rewriting again.

    Such installs do not record the package's Python files in the distribution metadata, so pytest found nothing to rewrite and assertions inside the plugin lost their introspection. The plugin's entry point is now used to locate the package in that case.

  • #​11933: pytest.warns no longer re-emits unmatched warnings with module="warnings", which caused module-based warning filters to be applied to the wrong warnings. Since warnings.WarningMessage does not record the module a warning was emitted with, re-emitted warnings now use the standard warnings.warn_explicit default of deriving the module from the warning's filename.

  • #​12175: ExceptionInfo.exconly(tryshort=True) <pytest.ExceptionInfo.exconly> now strips the AssertionError: prefix of failed assert statements for ~pytest.ExceptionInfo objects created by pytest.raises, and failures inside unittest.TestCase.subTest report the same short crash line as regular tests.

  • #​12223: The message attribute of <failure> and <error> elements in --junitxml reports is now shortened to whole lines within 500 characters. When something is dropped, it ends with a note pointing to the element text, which still holds the full report. Previously, very verbose assertion output (e.g. with -vv) produced attributes tens of thousands of characters long, which some XML parsers fail on.

  • #​12307: Fixed truncation of long collections (lists, dicts, sets, etc.) in the "message" part of failed assertions (as in assert condition, msg) when using -vv: the message now uses the same unlimited repr as the rest of the assertion output, instead of eliding collection elements with ....

  • #​12824: Custom command-line options now fail with a clear error when their implicit
    destination conflicts with an existing option, avoiding silent overrides of
    built-in options such as -k.

  • #​13292: Fixed a stale rewritten module being used when a test file is modified twice
    within the same second without changing its size -- the pyc header could only
    record whole-second timestamps. The cache is now keyed on a hash of the source.

  • #​14036: __tracebackhide__ is now respected in ExceptionGroup tracebacks, both for the group itself and for its sub-exceptions.

  • #​14189: Nested usage of caplog.filtering <pytest.LogCaptureFixture.filtering> no longer removes filters early if they were already present.

  • #​14412: Fixed incorrect timing information for subtests and parent tests when console_output_style = "times".

  • #​14445: Assertion rewriting no longer evaluates walrus operator (:=) expressions more than once, which reported results the test never computed when the expression had side effects.

    An operand evaluated before a later walrus is now reported with the value it actually saw, so assert value != identity(value := value.lower()) keeps Python's left-to-right order.

  • #​14552: Fixed stale co_filename values after a test module or directory is moved. Assertion-rewrite caches are reused when the source hash still matches, and in-memory code objects are pointed at the current path.

  • #​14586: Negative values passed to log_auto_indent now correctly fall back to no indentation, matching the documented behavior.

  • #​14619: Fixed a crash in pytest.mark.parametrize when a non-sequence value is passed for a parameter set. It now provides a clear error message during collection.

  • #​14635: Fixed fixture resolution failures when specifying multiple test paths on the command line that share common parent directories. Parametrized fixtures defined in a conftest.py could be silently dropped depending on the order of the specified paths.

  • #​14637: Pytest now correctly skips identical trailing characters in assertion text diffs even when the compared strings differ at the beginning.

  • #​14638: Top-level options in pytest.toml and .pytest.toml files now raise an error instead of being silently ignored when no [pytest] table is present.

  • #​14683: Fixed a regression in pytest 9.1 where a conftest.py located in the rootdir was no longer visible to tests and doctests collected from outside the rootdir (for example when passing a parent directory of the rootdir as a collection argument, or setting --rootdir to a subdirectory).

    As a result, fixtures defined in such a conftest -- including doctest_namespace injections -- were not available, causing errors such as NameError in doctests.

  • #​14700: Fixed an internal error on Python 3.12 when a doctest on a fixture-decorated function was skipped.

  • #​14705: TOML configuration files passed via -c now also read their configuration from the [pytest] table, the one pytest's own configuration files use. The [tool.pytest] and [tool.pytest.ini_options] tables such files were previously restricted to keep working; using both styles in one file is an error.

  • #​14828: Exception groups raised from another exception now print their cause chain only once in the traceback output.

  • #​14864: Fixed collection on Windows collecting the whole suite instead of the given path, on file systems which do not support file IDs (st_ino is 0 for every file, as seen for example on sshfs-win/WinFsp mounts).

  • #​14884: Cache.get(), Cache.set() and Cache.mkdir() now reject keys that resolve outside the cache directory, and --cache-show ignores glob matches outside it.

  • #​14909: Fixed MonkeyPatch.delattr <pytest.MonkeyPatch.delattr>, MonkeyPatch.setitem <pytest.MonkeyPatch.setitem> and MonkeyPatch.delitem <pytest.MonkeyPatch.delitem> recording a stale undo entry when the underlying mutation failed, which could cause spurious errors during teardown. The undo entry is now recorded only after the mutation succeeds, matching the behavior of MonkeyPatch.setattr <pytest.MonkeyPatch.setattr>.

  • #​14912: ~pytest.PytestWarning instances defined in _pytest.deprecated are no longer reused across warnings.warn calls, so warnings raised as errors (e.g. with -W error) no longer accumulate stale traceback frames from previous raises.

  • #​14942: Fixed a regression in 9.1.0 that made collection very slow (quadratic) when many fixtures are defined with the same name.
    This can happen particularly when many tests are defined in separate classes which inherit from a base class which defines fixtures (the fixtures are repeated per class).

  • #​15005: pytest.approx no longer treats finite ~decimal.Decimal values outside the float range (such as Decimal("1e400")) as infinite, which made in-tolerance comparisons fail.

  • #​15006: Restored the tolerance shown by pytest.approx for ~decimal.Decimal values, which since 9.0 displayed ??? for the default tolerance and reported the raw rel ratio instead of the absolute tolerance actually compared against.

  • #​15006: The failure message for pytest.approx comparisons of ~decimal.Decimal collections no longer reports Max absolute difference: -inf, or crashes for mappings, when the decimal.FloatOperation trap is set.

  • #​15006: pytest.approx no longer raises AttributeError when comparing numpy.ndarray instances with object dtype, such as arrays of ~decimal.Decimal.

  • #​15032: Help texts for command-line options and configuration options now keep their indentation
    and blank lines. Previously each line was stripped before wrapping, so a wrapped
    list item was indistinguishable from a new one and blank lines were dropped; configuration
    option help lost its line breaks entirely.

  • #​15043: Cache writes now emit pytest.PytestCacheWarning when writing or closing the cache file fails, consistent with errors opening the file.

  • #​15052: Fixed possible off-by-one line numbers in --fixtures and --fixtures-per-test output.

  • #​15145: With console_output_style set to times, durations just below a unit boundary are now shown in the next unit (e.g. 1.000ms instead of 1000.0us).

  • #​15172: Assertion diffs now pretty-print the built-in frozendict (Python 3.15+) across multiple lines, similarly to how dict is displayed.

  • #​4569: -k no longer matches attributes that end up in a test function's __dict__ without being meant as keywords, such as pytest's own pytestmark attribute and the bookkeeping left behind by functools.wraps and functools.lru_cache.

  • #​6750: Fix fixture argument discovery for custom collectors that pass bound methods to pytest.Function.

  • #​6997: XFAIL reports from teardown phases now include the phase in the short test
    summary.

  • #​7940: Fixed cleanup of temporary directories failing when subdirectories have their execute permission removed.

  • #​8321: Fixed exception chains being duplicated in the traceback output when an exception in the chain (__cause__/__context__) has no traceback of its own, and that exception is itself linked to further exceptions.

  • #​8914: Tests parametrized with higher-than-function scope are now reordered by
    parameter value rather than by parameter index, so that items using equal
    parameter values are grouped together and share a single fixture setup, even
    when they are parametrized by separate @pytest.mark.parametrize <pytest.mark.parametrize ref>
    calls. Previously, an expensive higher-scoped fixture could be set up and torn
    down repeatedly for the same parameter value.

    Unhashable parameter values (e.g. dicts) keep the previous index-based
    grouping behavior.

    As a consequence, the order in which parametrized tests run may change
    (fixture setup/teardown counts can only decrease, not increase).

  • #​9924: Fixed doctest option flags leaking between docstrings after a failure, skip, or expected failure.

Improved documentation

  • #​10721: Replaced setup.py usage with pyproject.toml in writing-plugins.
  • #​12658: Moved the fixture setup and finalizer hooks to the test running hooks section in the reference documentation.
  • #​12857: Documented how --confcutdir affects initial conftest.py discovery.
  • #​14157: Added the pytest-flakefighters plugin to the list of flaky test plugins in plugins.rst.
    Added flaky test papers published on the Test FLARE project to the list of flaky papers in plugins.rst.
  • #​15127: Added guidance on typing yield fixtures, including annotating fixture functions with their generator type and fixture consumers with the yielded value type.
  • #​15242: The installation instructions <installation> and install-package-with-pip now show how to install pytest into a virtual environment with venv and pip, uv or virtualenv, and explain the externally-managed-environment error.
  • #​4569: pytest --help, the -k reference entry and select-tests no longer describe -k as a Python expression matched against test names only; keyword expressions now shows marker names being matched as well. The examples that looked up a marker use Node.get_closest_marker <_pytest.nodes.Node.get_closest_marker> rather than item.keywords.
  • #​9614: Clarified that session.items and session.testscollected exclude deselected tests in the pytest_collection documentation.

Packaging updates and notes for downstreams

  • #​11680: Source archives of arbitrary commits -- the tarballs GitHub serves under
    /archive/, not just the ones for tags -- can now be built into an sdist or a
    wheel with a correct version. A .git_archival.txt file, expanded by git archive via export-subst, carries the describe output that
    setuptools-scm would otherwise have to ask git for.

    The archival file deliberately omits ref-names. Recording it would make the
    content of an archive -- and therefore its checksum -- change whenever a branch
    that points at the archived commit is moved afterwards, which is how the
    equivalent tarballs of tagged releases became unstable for other projects.
    Describe output alone depends only on the commit and on the tags reachable from
    it.

    The archival file is not shipped in the sdist -- an sdist carries its version
    in its metadata, and the template is only ever expanded by git archive.

    Building pytest from a git checkout now requires setuptools-scm >= 10.1.

  • #​9236: pluggy>=1.6 is now required.

    Older pluggy versions stopped running the remaining hook wrapper teardowns once an
    old-style hookwrapper raised in its own teardown. The logging plugin's wrapper was
    left suspended, and when it was finalised later it detached the handler that
    caplog of a subsequent test was recording through, so that test saw no records.

Contributor-facing changes

  • #​14813: Added a systematic coverage matrix for assertion rewriting.
  • #​14921: Added scripts/diff-assert-rewrite.py, which diffs the assert-rewritten form of a snippet between the plain source, this checkout and released pytest versions.
  • #​15190: Fixed the documentation build with Pluggy 1.7 by ignoring a reference to its undocumented DistFacade compatibility class.

Miscellaneous internal changes

  • #​13888: FixtureRequest.node <pytest.FixtureRequest.node> is now explicitly annotated as returning Any, so strict pyright no longer reports it as Unknown. The return type stays deliberately broad, see 13888.
  • #​14758: Internal node ids (the ::-separated strings identifying collected items, e.g. path/to/test_file.py::TestClass::test_method[param]) are now represented internally by a single structured ~_pytest.nodeid.NodeId dataclass instead of being repeatedly re-parsed as plain strings. The public nodeid: str attribute on nodes and reports is unchanged and remains fully backward compatible for plugins.
theskumar/python-dotenv (python-dotenv)

v1.2.4

Compare Source

Fixed
  • dotenv get no longer exits with code 1 for empty string values (KEY=) by [@​ShamikOfficial] in [#​700]
  • An unquoted empty value followed by an inline comment (e.g. KEY= # comment) is now parsed as an empty string instead of the comment text by [@​Noethix55555] in [#​663]
  • dotenv run --no-override now expands variable references with the same precedence as load_dotenv(override=False), so a value like ${BASE}/suffix uses the existing BASE from the environment instead of the one from the .env file by [@​ROTl24] in [#​698]

v1.2.3

Compare Source

Fixed
  • Strip a leading UTF-8 BOM from .env file contents so the first variable is no longer silently lost when the file is saved with BOM (e.g. by some JetBrains IDEs on Windows) by [@​h1whelan] in [#​640]
  • set_key now escapes backslashes, so values containing them (Windows paths, regular expressions) survive a write/read round-trip. Quoted values ending in an escaped backslash are no longer mis-parsed as an escaped quote, which used to swallow the following lines by [@​dchaudhari7177] in [#​680]
  • dotenv run now prints a friendly error instead of a traceback when no command is given by [@​bbc2] in [#​606]
  • Cache the parsed result for empty .env files so repeated dotenv_values/load_dotenv calls no longer re-read the file by [@​ReinerBRO] in [#​638]
Kludex/python-multipart (python-multipart)

v0.0.33

Compare Source

  • Drop Python 3.10 support #​329.
  • Add Python 3.15 support #​350.
  • Add opt-in field-count and field-size limits for URL-encoded forms in FormParser #​333.
  • Normalize the content type returned by parse_options_header when the header has parameters #​287.
  • Finalize Content-Transfer-Encoding decoding before invoking field and file callbacks #​336.
  • Keep only the incomplete escape when quoted-printable data is split across writes #​355.
  • Handle nameless uploads when UPLOAD_KEEP_FILENAME or UPLOAD_KEEP_EXTENSIONS is set #​343.
  • Accept a str UPLOAD_DIR when UPLOAD_KEEP_FILENAME is set #​335.
  • Speed up parser state lookups #​330.
  • Speed up opening boundary matching #​328.
  • Speed up querystring callback dispatch #​316.
astral-sh/ruff (ruff)

v0.17.4

Compare Source

Released on 2026-11-05.

Preview features
  • [flake8-logging-format] Avoid behavior changes and syntax errors in fixes (G004) (#​27419)
  • [security] Implement tarfile-ignore-zeros-true (#​28680)
Bug fixes
  • Accept a bare raise before a semicolon (#​29761)
  • Allow match identifiers after a semicolon (#​29760)
  • Fix panic on BOM-prefixed files in diagnostic renderer (#​30017)
  • [flake8-simplify] Report collapsible elif clauses after a multi-statement if branch (SIM102) (#​29814)
Rule changes
  • Show more nonprinting characters in diagnostic fix diffs (#​30062)
Performance
  • Coalesce source slices when formatting attributes (#​29841)
  • Collect return statements with a statement-only visitor (#​29911)
  • [pyflakes] Defer value comparisons for repeated dictionary keys (F601, F602) (#​29739)
  • Format node fields directly when comment handling is unnecessary (#​29853)
  • Reduce formatter source-slice overhead (#​29855)
  • Reuse a callee's qualified name across lint rules (#​29916)
  • Skip invalid string character checks when the source contains none (#​29883)
  • Use a Bloom filter for formatter comment lookups (#​29852)
  • Use a concrete buffer for ordinary writes (#​29819)
CLI
  • Give NO_COLOR precedence in Ruff and ty diagnostics (#​29898)
  • Honor CLICOLOR=0 in Ruff and ty diagnostics (#​29910)
Documentation
  • Correct the documented version and src defaults for ruff-action (#​29880)
  • [flake8-bugbear] Make B014 example error out-of-the-box (#​29941)
  • [flake8-no-pep420] Document preview behavior (INP001) (#​29764)
  • [isort] Expand I001 documentation (#​29843)
Other changes
  • [syntax-errors] Extend __debug__ write check to attribute targets (#​27908)
Contributors

v0.17.3

Compare Source

Released on 2026-10-26.

Preview features
  • [suspicious] Add shared-clock-mock (#​29074)
Bug fixes
  • [pyupgrade] Avoid incorrect conversions to f-strings (UP032) (#​25485)
Performance
  • Buffer stdout in ruff format (#​29631)
  • Specialize ASCII identifier lexing (#​29503)
  • Speed up identifier and keyword lexing (#​29463)
Documentation
  • [flake8-bandit] Describe what the rule actually checks for httpx (S113) (#​27936)
Contributors

v0.17.2

Compare Source

Released on 2026-10-22.

Preview features
  • [complexity] Add unnecessary-regular-expression-compile (#​25533)
Bug fixes
  • Avoid syntax errors for type variables with starred constraints (UP040, UP046, UP047, RUF053) (#​28362)
  • [pydocstyle] Treat backslash-escaped *args and **kwargs as documented (D417) (#​29536)
  • [pylint] Avoid false positive on starred elements (PLE0643) (#​29483)
  • [pylint] Mark fixes unsafe when deleting comments (PLR5501, PLW0120) (#​29414)
  • [pyupgrade] Mark fix unsafe when deleting comments (UP035) (#​29413)
Performance
  • Avoid intermediate names in lint name resolution (#​29506)
  • Prefilter bidirectional Unicode checks by UTF-8 leading bytes (#​29561)
  • Share postfix parsing and reduce expression copies (#​29480)
Configuration
  • [pylint] Add a configurable allowlist for magic-value-comparison (PLR2004) (#​18961)
Documentation
  • Clarify documentation and correct stale guidance (#​29374)
  • [pyupgrade] Remove mentions of variance related to fix safety (UP040, UP047) (#​29592)
Contributors

v0.17.1

Compare Source

Released on 2026-10-15.

Preview features
  • [pycodestyle] Don't treat None, True, or False as keywords (E271-E274) (#​29322)
Bug fixes
  • Fix dedent with multiple leading comments (#​29382)
  • [flake8-pyi] Detect legacy positional-only parameters in __new__ methods (PYI063) (#​28502)
  • [flake8-pyi] Fix false positives on quoted annotations (PYI036) (#​29274)
  • [perflint] Avoid invalid comprehension suggestions (PERF401, PERF403) (#​29366)
Rule changes
  • Treat more collections and weakref containers as mutable (#​29213)
Documentation
  • [flake8-import-conventions] Update default and example aliases (#​29333)
Contributors

v0.17.0

Compare Source

Released on 2026-10-09.

The executables in our macOS and Windows release archives and ruff wheels are now code-signed.
macOS executables are signed with an Apple Developer ID certificate and notarized by Apple. Windows
executables have timestamped Authenticode signatures from Azure Artifact Signing. This enables
verification of the release publisher and binary integrity, supports publisher-based allowlisting,
and should reduce security warnings and antivirus false positives.

Breaking changes
  • Update the default and latest Python versions for 3.15 (#​28792)

    Ruff now defaults to Python 3.11 instead of 3.10 when no Python version is configured through
    target-version or
    requires-python. When
    checking for syntax errors without a configured Python version, Ruff now defaults to Python 3.15
    instead of 3.14.

  • Update the default rule set (#​28786)

    Several of the flake8-datetimez rules
    (DTZ001,
    DTZ005,
    DTZ006,
    DTZ007,
    DTZ011,
    DTZ012, and
    DTZ901) are no longer enabled by default,
    while undefined-local-with-nested-import-star-usage
    (F406), which corresponds to a syntax error, is now enabled by default.

  • Update Rust crate quick-junit to 0.8.0 (#​27295)

    JUnit output now uses a skipped attribute instead of disabled on <testsuite> elements and
    includes a skipped attribute on the root <testsuites> element.

  • [flake8-import-conventions] Add datetime as dt as a conventional alias (ICN001) (#​28790)

  • Support Unicode dummy variable names (#​28722)

    The default lint.dummy-variable-rgx
    now recognizes underscore-prefixed Unicode names, such as _次, as dummy variables.

  • Update to Unicode 17 (#​21229, #​28784)

    Ruff now uses Unicode 17 data for identifier normalization and named character escapes ("\N{...}").

  • Always show unsafe and display-only fixes in the CLI (#​27810)

    The default full output format now shows unsafe fixes and suggestions requiring manual review,
    regardless of the unsafe-fixes setting.
    Actually applying unsafe fixes still requires explicit opt-in.

  • Remove the Python dependency from conda-forge builds (conda-forge/ruff-feedstock#361)

    The conda-forge build no longer depends on Python, now supports linux-riscv64, win-arm64, and
    linux-ppc64le platforms, and now includes shell completions. However, no longer depending on
    Python means that python -m ruff and import ruff will no longer work. Use ruff directly from
    PATH instead. PyPI installations and those from the standalone installer are unaffected.

  • Remove support for ruff-lsp (#​28750)

    Support for ruff-lsp, the legacy Python language server deprecated in Ruff
    v0.9.5
    , has been removed. The Ruff VS Code
    extension now always uses the native language server; ruff.nativeServer is deprecated and
    ignored. See the migration guide.

Stabilization

The following rules have been stabilized and are no longer in preview:

The following behaviors have been stabilized:

  • The formatter, unsorted-imports (I001),
    line-too-long (E501), and
    doc-line-too-long (W505) now
    consistently ignore trailing pragma comments when computing line length. This resolved several
    bugs involving interactions between these rules
    (#​27313) but may also cause existing imports to be
    reformatted and was thus classified as a breaking change.
Preview features
  • [flake8-bugbear] Report the method name and a more precise range (B005) (#​27050)
  • [refurb] Mark fix unsafe and move to suspicious (FURB152) (#​28405)
  • [ruff] Allow docstrings in strict mode (RUF067) (#​28679)
Bug fixes
  • [flake8-builtins] Expand checks in class scopes (A001) (#​29076)
  • [flake8-self] Allow private access on object.__new__(cls) instances (SLF001) (#​29001)
  • [flake8-tidy-imports] Skip lazy-import-mismatch in stubs (TID254) (#​29095)
  • [flake8-type-checking] Add the notion of runtime-ambiguous references (#​26508)
  • [flake8-type-checking] Never flag annotations in function scopes (#​29183)
  • [pyflakes] Mark the fix as unsafe when it creates a docstring (F541) (#​28258)
  • [pylint] Preserve trailing comments in useless-return fix (PLR1711) (#​29180)
  • [ruff] Avoid false positive when pytest.raises is used in a with statement (RUF061) (#​28186)
Rule changes
  • [pyupgrade] Suggest typing.TypeForm on Python 3.15 (UP035) (#​29084)
Contributors
Kludex/starlette (starlette)

v1.10.0: Version 1.10.0

Compare Source

📝 Leaner URL-encoded form parsing

Starlette 1.10.0 parses URL-encoded forms with less memory and CPU, no longer drops the last field when a stream ends early, and lets you compare FormData that holds several uploads under one key.

uv pip install starlette==1.10.0
  • Forms with many fields parse faster and use less memory (#​3724). FormParser builds each field in the parser callbacks instead of queueing every event and replaying it. On CodSpeed, 1000 fields went from 42.8 ms to 34.9 ms and from 63.5 KB to 54.5 KB, and the max_fields limit case went from 6,880 B to 864 B.
  • The last field is kept when the request stream ends without an empty chunk (#​3599). The parser is now finalized once the stream is exhausted, so custom streams that never yield a final b"" no longer lose their last field.
  • FormData with repeated uploads can be compared (#​3619). Comparing two FormData objects with several UploadFile values under the same key used to raise TypeError.

⚠️ Behaviour changes

  • Multidict equality keeps the order of values under a repeated key (#​3619). Keys can still appear in any order, but QueryParams("a=1&a=2") and QueryParams("a=2&a=1") are no longer equal, matching what getlist() returns.
  • starlette.formparsers.FormMessage is deprecated (#​3724). The parser no longer uses it, and FormParser.messages is gone. Calling FormMessage(...) emits a StarletteDeprecationWarning.

🧭 Routing and URL generation

  • Path parameter values that look like a placeholder are kept as they are (#​3725). url_path_for("route", category="{id}", id="42") on /{category}/{id} now returns /{id}/42 instead of /42/42. Substitution also got faster, from 549 ns to 520 ns with two parameters and from 1,078 ns to 779 ns with five.
  • Route matching does less work per request (#​3665, #​3722). Match members are compared by identity, cutting up to 4.9% of the instructions per dispatch in the routing benchmarks.
  • WSGIMiddleware strips root_path only at a path segment boundary (#​3718). A request to /application under a root_path of /app no longer becomes /lication.
  • FloatConvertor reports NaN and infinity correctly (#​3716). NaN was reported as a negative float.

🛡️ Middleware, responses and config

  • Handled exceptions no longer keep requests alive (#​3205). Starlette clears the traceback after an exception handler runs, so an exception instance reused across requests, such as a module-level HTTPException, no longer pins per-request objects in memory.
  • Middlewares accept http.response.start without headers (#​3721). BaseHTTPMiddleware, GZipMiddleware and SessionMiddleware default the omitted field to an empty list instead of raising KeyError.
  • FileResponse ignores Range on methods other than GET and HEAD (#​3679). A POST endpoint that returns a file now sends the full file, as RFC 9110 requires.
  • Config strips one pair of matching outer quotes from env file values (#​3720). KEY='say "hi"' now reads as say "hi" instead of say "hi.

Full changelog: 1.9.0...1.10.0

v1.9.0: Version 1.9.0

Compare Source

This release streams TestClient response bodies, so client.stream() returns before the application finishes. It also escapes path delimiters when building URLs, matches host names case-insensitively, and keeps every existing Vary header.

Changed

  • Stream TestClient response bodies, so client.stream() returns before the application finishes. Closing an unfinished streamed response now cancels the application #​3491.

Fixed

  • Percent-encode ?, #, \ and a leading // in the request path when building request.url, and \ and a leading // in url_path_for #​3671.
  • Use the byte length for Content-Length when the response body is a typed or multidimensional memoryview #​3622.
  • Include HEAD in the Allow header of HTTPEndpoint 405 responses when GET is defined #​3585.
  • Match host names case-insensitively in Host routing and TrustedHostMiddleware #​3542.
  • Preserve every existing Vary header in MutableHeaders.add_vary_header(), used by GZipMiddleware and SessionMiddleware #​3675.

Full changelog: 1.8.0...1.9.0

jannikmi/timezonefinder (timezonefinder)

v8.3.0

Compare Source

New features:

  • The dataset version is now exposed at runtime. TimezoneFinder().data_version (and TimezoneFinderL().data_version) return the timezone-boundary-builder release the packaged data was built from, read from a data_version.txt stamp that scripts/file_converter.py writes into the data directory it generates and that ships in the wheel. Previously an installed timezonefinder could not state it at all: the release tag lived only in a repo-root file that is not packaged. Which release a parse is stamped with comes from the input's filename (combined-with-oceans-2026c.json, which update_data.sh now produces), or from scripts/file_converter.py --data-version for an input that cannot carry it; your own GeoJSON is stamped "unknown", and an unpacked release archive that lost its tag is refused rather than compiled into data that could never say where it came from. timezonefinder.__version__ is now exposed as well, read from the installed distribution metadata. Solves issue #​498.
  • The command line script gained a --stdin streaming mode: it reads delimited rows from standard input and writes each back out with a timezone column appended, building the finder once instead of paying full initialisation per coordinate. Which columns hold the coordinates is read off the header by name, or stated with --lng-col/--lat-col, and never inferred from their position - a swapped pair is still a valid coordinate for any longitude between -90 and 90, so guessing would answer with a real but wrong timezone instead of failing. Every input row produces exactly one output row, and a row that cannot be used warns on stderr and makes the run exit non-zero rather than ending the stream. Whether the first row is a header is worked out from the row, or stated with --header/--no-header. New flags -d/--delimiter and --in-memory apply to the whole stream. See the usage documentation <https://timezonefinder.readthedocs.io/en/latest/1_usage.html#looking-up-many-coordinates-at-once>. Solves issue #​504. Thanks to weed33834 <https://github.com/weed33834> for the PR #​516.

Changed:

  • Polygon coordinates are now stored one axis at a time in the packaged coordinates.bin files - all x values followed by all y values per polygon, instead of interleaved. The point in polygon test scans a single axis per iteration, so contiguous per-axis blocks halve the cache lines it touches: ~1.6x faster on a median polygon and ~2.5x faster on the largest ones via the C extension, 14-25% faster via Numba. The bundled data was regenerated accordingly, and the layout is described in the data format documentation <https://timezonefinder.readthedocs.io/en/latest/data_format.html>__.
  • Every packaged FlatBuffers file now carries a file identifier and a layout version, and TimezoneFinder raises a ValueError naming the offending file when either does not match - previously such a directory was read without complaint and produced wrong timezones. For coordinates.bin the version records how the coordinates are encoded and which polygons the file holds. The hybrid shortcut binaries get an identifier that differs per zone id width, because the uint8 and uint16 schemas differ only in the width of a zone id and each parses cleanly as the other; the width is now read from the buffer instead of being guessed from the file name, so a renamed or mispaired shortcut file fails loudly rather than returning wrong zones. If you compile your own data and point bin_file_location at it, regenerate it once with scripts/file_converter.py, since the coordinate layout, the hole storage, the shortcut container and the file names all changed in this release. The markers track what a file holds rather than the package version, so this is not a per-release obligation. Solves issue #​458.
  • The hybrid shortcut loader no longer keeps the entire shortcut binary in memory. The polygon id arrays it returns were zero-copy views onto the ~1.5 MB file buffer, so ~47 KB of live data pinned the whole thing for the lifetime of every TimezoneFinder / TimezoneFinderL instance. They are now disjoint read-only slices of a single compact array, cutting the shortcut mapping's footprint from ~7.4 MB to ~4.7 MB per instance, and every finder's resident set by ~2 MB, at unchanged initialisation time - which matters most for concurrent workloads, where the recommended one-instance-per-thread pattern multiplied the waste.
  • Holes that duplicate a timezone boundary polygon are no longer stored twice. Almost every hole is an enclave, cut into the surrounding zone with exactly the ring the upstream data also emits as the enclosed zone's own boundary polygon - the same geometry under two IDs. The packaged hole coordinate file now holds only the rings with no such twin (27 of 756 in the current data), and a new holes/poly_ref.npy records per hole which boundary polygon to read instead. Hole data drops from ~2.0 MiB to ~0.16 MiB, and in_memory=True saves the same amount of RAM, since those holes now resolve into the boundary arrays rather than materialising a second copy. Matching is exact - rings are compared as integer coordinates in a canonical form, with bounding boxes used only to narrow the search - so every timezone lookup returns what it did before. One visible consequence: get_geometry() may hand back a deduplicated hole ring starting at a different vertex or winding the other way than it used to, tracing the same closed path. The encoding is described in the data format documentation <https://timezonefinder.readthedocs.io/en/latest/data_format.html>__.
  • The timezone boundary data now ships as its own distribution, timezonefinder-data. pip install timezonefinder is unchanged - it is a hard dependency and is installed automatically - but the dataset can now be pinned on its own (pip install timezonefinder "timezonefinder-data==1.2026.3"), where previously holding a dataset meant pinning an old timezonefinder and forfeiting every code fix since. Every release used to carry the whole ~65 MB dataset in three platform wheels plus an sdist to distinguish a few kilobytes of compiled code, which had already exhausted the PyPI project storage quota once. A data update is consequently no longer a timezonefinder release at all: it publishes timezonefinder-data under its own tag namespace and is recorded in that package's README rather than here. Its version reads <format>.<year>.<letter> - 1.2026.3 is data format generation 1 built from timezone-boundary-builder 2026c - and timezonefinder requires timezonefinder-data>=…,<2: no ceiling on the data axis, so a dataset update needs no code release, and a hard one on the format axis, so code paired with data it cannot read fails when resolving rather than at the first lookup. DATA_LICENSE moves with the database it covers and now ships inside the data wheel, and a compiled data directory additionally carries a schemas/ copy of the FlatBuffers definitions its binaries were written by, so it can be read back without the package that wrote it. Solves the first part of issue #​446.
  • The packaged FlatBuffers binaries are now named .bin rather than .fbs: boundaries/coordinates.bin, holes/coordinates.bin and hybrid_shortcuts_uint16.bin. .fbs is the FlatBuffers schema extension, and the data directory now ships actual schemas next to the buffers, so one extension was naming two unrelated kinds of file. Each buffer already states what it is through the file identifier in its first bytes, which is what a rename or a mispaired copy cannot forge - the name never carried that meaning. The bytes are unchanged.

Bug fixes:

  • Fixed a BufferError: cannot close exported pointers exist raised during resource cleanup in file mode (in_memory=False). A coordinate array obtained from coords_of() is a zero-copy view onto the memory-mapped file, and mmap.close() refuses to unmap while one is alive, so an array outliving its TimezoneFinder raised on cleanup. The mapping now stays valid instead of leaving the views dangling, and FileCoordAccessor.cleanup() releases its own references so the deferred close happens as soon as the last view is dropped. The accessor must not be used after cleanup().

Documentation:

  • The memory footprint of every finder configuration is now measured and published in a new memory report <https://timezonefinder.readthedocs.io/en/latest/benchmark_results_memory.html>__, separating what a configuration allocates (tracemalloc) from what it makes resident (RSS, which additionally counts memory-mapped pages). The distinction is the point: the default mode maps the coordinate data instead of reading it, so it allocates an order of magnitude less than the in-memory mode, and only the pages a lookup actually touches become resident. This replaces documentation claiming a 40MB process ceiling and a 41MB data directory, both long out of date.
  • Restructured the two entry points a reader actually arrives at - README.rst and the documentation landing page <https://timezonefinder.readthedocs.io/en/latest/>__ - so both state what the package is and how it works instead of only what it is called. The README opens with the project banner and a one-sentence statement of what the package is for, then the badges, then the quick guide - and adds three short sections that were missing entirely: How it works (the lookup pipeline and the no-simplification trade-off), Performance (a concrete throughput figure with its configuration named, the three point-in-polygon backends and the pure-Python fallback), and Engineering notes linking the architecture, data format and benchmarking methodology pages. The maintainers-wanted notice moves from the first heading after the intro into a new Contributing section at the bottom, which also links CONTRIBUTING.md for the first time. The badge block is corrected along the way: the code style: black badge named a formatter this project has never used and is replaced by ruff, and a supported-Python-versions badge was added. The banner is referenced by absolute URL, since PyPI serves the long description without the repository and a docs/… path renders as a broken image there. The landing page gains the same How it works summary, the no-simplification trade-off and the ocean-zone consequence for timezone_at(), and its flat seventeen-entry table of contents is grouped into Using it, Design, Performance and Project, so the sidebar says what kind of project this is rather than listing pages in the order they were written.
  • Rewrote the package comparison <https://timezonefinder.readthedocs.io/en/latest/alternatives.html>__ page. It now states its position in prose before the first table - border correctness is what this package optimises for, speed is the constraint that work happens under - and says plainly when tzfpy is the better choice. Every quantitative cell names what it measures and links its source, and the speed row is deliberately qualitative on both sides, with a note explaining that the two packages have never been benchmarked under one harness. The decision table drops the rows on which the two packages do not differ.
  • Two new documentation pages: Architecture <https://timezonefinder.readthedocs.io/en/latest/architecture.html>__ describes the lookup pipeline, the three point-in-polygon backends and the memory modes, and states the ceilings this package deliberately does not exceed - unsimplified geometry, ~1 cm coordinate resolution, no general-purpose spatial code. It also documents how the package is built and shipped, which was previously described nowhere outside the workflow YAML: why one abi3 wheel per target replaces one wheel per Python version and what abi3audit is guarding, why three libc targets are built, why the end-to-end job installs the built wheel and asserts the C extension loaded rather than merely importing the package, and why a tag pushed from outside master aborts the release. The testing section gained the property-based suite and the reason the tox matrix is a matrix - the acceleration paths are bound at import time, so a passing run describes one configuration only. Both sections are linked from the README's Engineering notes. Benchmarking Methodology <https://timezonefinder.readthedocs.io/en/latest/benchmarking_methodology.html>__ documents how the published numbers are produced and what they can and cannot tell you: ubuntu-latest pins the runner image and not the CPU, which is why a pull request is measured against its own merge base on the same runner and why every alert threshold is derived from measured noise. It was previously addressed only to contributors, in the second half of CONTRIBUTING.md, which now keeps the operational instructions and links to it.
  • The H3 resolution choice in the data format documentation <https://timezonefinder.readthedocs.io/en/latest/data_format.html>__ is no longer asserted to "offer a good balance" but reports the study behind it (prototypes/single_resolution_bench.py): resolution 3 keeps the hybrid index at a small fraction of the packaged polygon data, while resolution 4 would exceed 10 % of it for gains that do not justify the increase.
  • The hand-written documentation no longer restates exact figures that belong to the generated pages - dataset vertex, polygon and hole counts, index and distribution sizes, memory footprints, lookup throughput. Those change with every data update and with code that shifts a footprint, which silently left the copies wrong: the memory figures had already gone stale in four places. The prose now states the magnitude that survives a data update and links the data report <https://timezonefinder.readthedocs.io/en/latest/data_report.html>__ or the relevant benchmark report <https://timezonefinder.readthedocs.io/en/latest/7_performance.html>__, which are regenerated from the packaged data and are always current.
  • The three weakest hand-written documentation pages no longer answer a question by pointing at a file the reader has to open. The performance page <https://timezonefinder.readthedocs.io/en/latest/7_performance.html>__ now opens with the four benchmark reports and the trend chart instead of a bullet list of adjectives about the binary format, and its C extension and Numba sections are cut to what a user does - which call reports the active backend - with the explanation left to the architecture page that already carried a more precise version of it. Getting started lists the four runtime dependencies and what each is for, where it previously said to consult pyproject.toml, which remains linked as the authoritative source for version ranges. The use case pages carry runnable snippets for building an aware datetime and reading a UTC offset, with the examples/ scripts as the follow-up rather than the whole answer; the snippets use the standard library's zoneinfo, so neither needs an optional dependency.
  • The shortcut entry distributions in the data report <https://timezonefinder.readthedocs.io/en/latest/data_report.html>__ no longer report three quarters of all H3 cells as holding 0 polygons, which is impossible for data whose ocean zones cover the globe. Those cells are covered by a single timezone and store its id directly, so a lookup there needs no point-in-polygon test at all - the column is now Polygons to test and the row reads none (unique zone). The tables are introduced by a sentence on what they measure, including why no cell ever needs exactly one test.
  • The usage examples in README.rst and the usage documentation <https://timezonefinder.readthedocs.io/en/latest/1_usage.html>__ now show the result the packaged data actually returns. Every snippet queries the same Berlin coordinates and annotated the answer as 'Europe/Paris', which is the value from the reduced timezones-now dataset, where Europe/Berlin is merged into Europe/Paris - not from the full dataset the package ships by default. All eleven annotations now read 'Europe/Berlin', verified against the packaged data for each of timezone_at(), timezone_at_land(), certain_timezone_at(), unique_timezone_at() and TimezoneFinderL, and the get_geometry() call in the opening example asks for that same zone instead of a different one. tests/test_documented_contracts.py now re-runs each of those documented lookups, so a data update that moves the example coordinate's zone fails there rather than leaving every snippet on both pages quietly wrong again.

Internal:

  • The release pipeline refuses to publish timezonefinder unless a compatible timezonefinder-data already exists on PyPI. The two distributions release independently, and on a data format change the order is fixed - data first, then the code requiring it - because a code wheel whose declared data version does not exist yet is uninstallable for everyone until it does, and the version number cannot be reused to fix it. The check reads the requirement out of the built wheel rather than out of pyproject.toml, and asks the index the same question a user's resolver will, so a yanked release does not count as one that satisfies it. It runs before the GitHub Release, which is the first step of the release that cannot be taken back.
  • Pull requests are opened against a template (.github/pull_request_template.md) prompting for the change, its motivation and the checks that were run.
  • update_data.sh resolves the timezone-boundary-builder release tag before downloading and fetches that release's asset, instead of fetching releases/latest/download/ and separately asking the API what latest was - two independent questions that a release landing between them answered differently, attributing one release's data to the other. The tag now names the downloaded archive and the GeoJSON as well, so a leftover file from another release or another dataset variant cannot satisfy the "already downloaded" checks and be parsed in place of what was asked for.
  • Names and docstrings now describe what the code does. TimezoneFinder.timezone_at documents the optimisation it actually performs: once no other zone can be matched the last remaining zone is returned without a point in polygon test, which is always correct against the packaged data - the ocean zones cover the globe, so every point lies within one of the candidate polygons - but not against custom data that leaves areas uncovered, where a point inside none of the candidates is still attributed to that zone and certain_timezone_at is the method that tests every candidate. Three tests were named after something other than what they do: test_rectify_coords_valid/_invalid were named for a rectify_coords that exists nowhere in the package and both call validate_coordinates, and the first was subsumed entirely by test_validate_coordinates_accepts_finite_values, which covers all four of its distinct corners and additionally asserts the return value where the older test asserted only "does not raise"; and test_single_element_arrays_should_not_occur asserted that they do occur (assert single_element_count == 2) under a triple-quoted string placed after the first statement, making it a discarded expression rather than a docstring - so it reached neither --collect-only nor a failure report, which is where the contradicting name was the only thing a reader saw. A stale comment duplicated across the last two lines of tests/main_test.py, reading as a to-do for something TestTimezonefinderClassTestMEM already does, is gone.
  • Added DATA_VERSION file tracking which timezone-boundary-builder release the packaged data was generated from, written automatically by the data update script after a successful parse. Thanks to Lucas Hemkemeier <https://github.com/hemkdev>__ for the PR #​429.
  • The packaged data now updates itself: a weekly workflow compares DATA_VERSION against the latest timezone-boundary-builder release, regenerates the data and opens a ready-to-review update PR, which is merged and released automatically once its CI passes - the version tag is pushed with a GitHub App token, since the default one would not trigger the release pipeline. The tag lives in its own data-v* namespace, which the code release pipeline excludes at its trigger and again on the job that creates the GitHub Release, and the data stream publishes by PyPI Trusted Publishing from its own deployment environment rather than with a shared token. It refuses to release when the squash it produced did not land on the master it checked, so the tag names a tree that was actually built. Failed CI takes the same manual-attention path and falls back to the previous notification issue. Each cause labels the PR automation-failed and leaves one comment naming that cause and linking the run, deduplicated per cause so re-running CI neither repeats a notice nor hides a second one; a failure past the merge is a cause of its own, since that leaves master carrying the update with no tag pushed and only a hand-pushed tag still releases it. The manual release path drops the stop condition it carried for an out-of-order CHANGELOG.rst: the automation can no longer produce one, and the test suite asserts the committed file's section order if anything else does (issues #​273, #​167 and #​510). Thanks to Lucas Hemkemeier <https://github.com/hemkdev>__ for the PRs #​434 and #​436, and to Nice6042 <https://github.com/Nice6042>__ for the PR #​518.
  • update_data.sh (renamed from parse_data.sh) is CI-ready: interactive prompts replaced by flags (--dataset=full|same-since-now, --with-oceans, --rm-tmp), the release note for a data update written automatically into the data package's README, no redundant tox run, and a make reports at the end so the benchmark and data reports cannot go stale relative to the data an update PR ships. A standalone make parse/make testparse still needs a manual make reports (issues #​167 and #​510). Thanks to Lucas Hemkemeier <https://github.com/hemkdev>__ for the PRs #​432 and #​434.
  • Added property-based tests (hypothesis) for coordinate validation (solves issue #​143). Thanks to Lu Yicheng <https://github.com/01luyicheng>__ for the PRs #​431 and #​433.
  • Replaced the hand-rolled timeit timing in scripts/check_speed_*.py with pytest-benchmark suites under benchmarks/, excluded from make test/make testall via testpaths. Both they and the memory harness run over deterministic committed fixtures (tests/fixtures/benchmarks/), so two runs of the same commit execute the exact same workload; the loader rejects fixtures that no longer match the checkout. Measurement and rendering are decoupled, so docs/benchmark_results_*.rst can be regenerated from a stored JSON without re-measuring. Run via make speedtest, make benchmarks, make memory or make reports.
  • Memory is measured by its own harness (scripts/measure_memory.py, make memory) rather than by pytest-benchmark, which times code and would have its timings distorted by allocation tracking. It emits pytest-benchmark-shaped JSON, so the existing normalisation, noise and comparison tooling works on it unchanged given a --metric. tests/test_memory_footprint.py fails if a mode's allocation leaves its order of magnitude - the regression that would make in_memory=False stop being the low-memory option.
  • Added continuous benchmarking on CI (solves issue #​150), deliberately kept out of the release pipeline in build.yml: the tracked core subset and the memory harness run on every pull request and every push to master, publishing trend charts <https://jannikmi.github.io/timezonefinder/dev/bench/>__ to gh-pages and posting a same-runner base/head comparison on the pull request. The comparison reports added or removed benchmark IDs without trying to ratio unmatched measurements, which lets the trusted default-branch consumer remain compatible while the suite evolves. A pull request is measured against its own merge base in the same job rather than against a stored baseline, because runs-on: ubuntu-latest pins the runner image and not the CPU. The measurement design, the tracked estimator and every alert threshold are documented in the new benchmarking methodology <https://timezonefinder.readthedocs.io/en/latest/benchmarking_methodology.html>__ page. The measuring job holds no write permissions and no secrets, so branch and fork pull requests behave identically; the comment is posted by a separate, privileged workflow via workflow_run.
  • Guarded the benchmark plumbing against silent drift: tests/test_benchmark_names.py and tests/test_memory_metric_names.py pin the node ids and metric names that join a measurement to its chart history, so a rename fails loudly instead of starting an empty chart beside the orphaned old one; tests/test_benchmark_workflows.py asserts that the constants duplicated across the two workflows agree, where a one-sided edit previously had no failure mode at all, and that the cross-machine trend chart cannot creep back into the pull request comparison; and every generated report page states the inputs it describes - docs/benchmark_results_*.rst the fixture and timezone data versions they were measured against, docs/data_report.rst the timezone data version its figures were derived from. Both stamps are covered by tests: one renders each report and fails if a renderer stops emitting it, another checks the committed pages against the current fixture metadata and DATA_VERSION, so regenerating fixtures or updating the data without re-rendering fails loudly instead of leaving a page whose numbers are all plausible and all stale.
  • Every generator now emits output that is already pre-commit-clean, so regenerating and diffing compares like with like: write_json sorts keys the way pretty-format-json does, and neither scripts/reporting.py nor BenchmarkReporter emits trailing whitespace on empty cells or a trailing blank line. Previously every make parse/make reports left its outputs looking modified until the hooks had run, which masked whether a regeneration had actually changed anything.
  • Every generated benchmark report now opens with its headline figure and the configuration behind it, above the tables: how long a lookup takes and how many per second, the per-check cost across polygon sizes, construction time, footprint per mode - all derived from the same parsed JSON as the tables, never hardcoded. The banner beneath states which acceleration path and platform produced the numbers, and says whether that is the configuration CI tracks: the committed reports are rendered from a developer machine with Numba enabled, while CI measures the C extension without Numba, so their figures were never comparable to the trend chart and now say so.
  • make flatbuf no longer overwrites hand-maintained __init__.py files. flatc derives its output path from the schema namespace and writes an empty __init__.py at every level of it, so generating in place wiped the __all__ in timezonefinder/__init__.py - the whole public API. The target now generates into a scratch tree, copies back only the generated packages, and runs the formatters on the result so a regeneration diff shows the codegen change rather than formatting churn.
  • Mypy now type-checks the whole package except the flatc-generated bindings. ignore_errors previously covered roughly 800 lines of hand-written code as well, where a blatantly wrong return type still reported "Success"; they all pass once the exemption is lifted, bar two genuine findings now fixed. tests/test_mypy_config.py keeps the list restricted to generated code, so silencing a module is a reviewed decision rather than a one-line edit.
  • The hybrid shortcut reader and writer now select their FlatBuffers schema from a single registry (SHORTCUT_SCHEMAS in timezonefinder/flatbuf/io/hybrid_shortcuts.py) instead of dispatching on the zone id width in three places, each keyed differently. One ShortcutSchema per width owns the width, the file name, the uintN marker and the maximum zone id, which were previously written down across five places with nothing tying them together. Verified behaviour-preserving down to the bytes: re-writing the shipped shortcut binary produces a byte-identical file.
  • Each distribution's build is now asserted to contain exactly what it should. The data wheel's payload is compared against the committed dataset as a set, in both directions: a missing binary fails on first use and gets reported, but an extra one ships silently - setuptools copies package data into build/lib and never prunes it, so a file renamed in the source tree keeps being zipped into every later wheel built from that checkout, which is how a 63 MB coordinates.fbs was still shipping next to the coordinates.bin that replaced it and doubling the wheel whose size is the reason the distribution was split out. The wheel builders clear that directory first, so a local build matches the fresh checkout CI builds from, and the code sdist's checks cover its grafted test fixtures again.
  • The packaged data is additionally held to a floor on how much hole deduplication achieves - the test suite fails if fewer than 90% of its holes match a boundary polygon (96.4% currently), because a future upstream release that stopped emitting enclaves as shared rings would still compile and still return correct timezones, just with the shipped data quietly re-inflated. The floor applies to that dataset and nothing else: compiling your own GeoJSON with scripts/file_converter.py is a supported use case, holes that are ordinary interior rings rather than enclaves are stored inline and answer correctly, and the converter only reports the ratio rather than refusing to compile. prototypes/hole_boundary_redundancy.py is the study behind the threshold: it reads the upstream GeoJSON, so re-running it against a new release re-verifies the assumption rather than restating it. prototypes/hole_removal_impact.py is the study behind keeping the unmatched holes stored inline rather than dropping them, which is the obvious next step and does not work: dropping holes and re-running the lookups changes answers, wrongly, because being covered by another zone only puts that zone among the shortcut candidates and says nothing about it being tested first (issue #​513).
  • Removed constructs that provably did nothing, and gave two vacuous tests real assertions. Most consequentially, four __slots__ entries were declared but assigned by nothing, which silently re-permitted the very attributes __slots__ is there to forbid - assigning those names now raises AttributeError, and test_declared_slots_are_assigned keeps the list honest.
  • get_corrected_hex_boundaries exists once again. An earlier refactor left two verbatim copies of the antimeridian and pole clipping rules with nothing keeping them in sync; the copy without callers is deleted, and the survivor is now covered by tests/hex_utils_test.py - it previously had no direct tests at all. scripts/configs.py no longer declares MAX_LAT/MAX_LNG as a second pair of names for timezonefinder.configs's constants.
  • prototypes/ has a README.md saying what the three scripts there are: exploratory studies behind committed design decisions, run by hand, outside the package and the test suite. One of them is the measurement that chose H3 resolution 3 - the central algorithmic parameter of the package, already cited from the data format page - and another is the evidence for not building a hierarchical index. MANIFEST.in now excludes the whole directory from the source distribution rather than only its *.py files.
  • plans/ is git-ignored alongside tmp/ and .venv/: implementation plans written while working on a change are local scratch, and leaving the directory untracked-but-unignored made it noise in every git status and a candidate for an over-broad git add.
  • Failing paths now report the input that failed. tests/auxiliaries.py's run_command assembled the child's stdout and stderr into a message and then raised a fresh CalledProcessError that never used it, with from None discarding the original too, so a packaging failure under make testint reported an exit code and nothing about the cause; it now echoes the captured streams and re-raises the original exception with its traceback intact. scripts/reporting.py passes the coordinate file paths into get_polygon_collection, whose optional file_path exists precisely so an incompatible-layout ValueError can say which of the two files was stale - make reports against an outdated data directory previously could not. Boundaries.overlaps names the type it rejected instead of raising a bare TypeError, and the RuntimeError for missing original_polygons names the polygon and resolution it was computing. The two re-raises ruff flags under B904 now say from None explicitly, so a deliberately dropped exception chain is distinguishable from a forgotten one, and timezonefinder/command_line.py drops FileNotFoundError from an except tuple that already caught its base class OSError. tests/test_error_diagnostics.py pins what each of these messages must contain.
  • The command line interface no longer routes its own output through a temporary file. main redirected stdout to a mkstemp file for the duration of the lookup and then, in verbose mode, reopened it to read back a string it still held in a local variable - nothing inside the redirected block ever wrote to stdout, since the lookup functions return their result rather than printing it. The context manager, the read-back, its warning path and the file cleanup are gone, and the lookup function is now resolved once per invocation instead of twice, so -f 3/-f 4 under -v no longer construct a second TimezoneFinderL and reload its shortcut data just to read a function name. Output is unchanged character for character, across every function id in both modes. tests/cli_test.py gains the coverage that makes that checkable - verbose mode, the empty line printed when no timezone is found, and the rejected function id had none - and asserts the printed name verbatim instead of passing it through rstrip("\n\x1b[0m"), which strips a set of characters rather than a suffix and so truncates 12 of the packaged zone names (Europe/Amsterdam -> Europe/Amsterda).
  • Docstrings now describe the code that exists. Six documented something the implementation contradicts: AbstractTimezoneFinder.__init__ called in_memory inert and "kept for API compatibility" when it is what selects memory-mapped against in-memory coordinate access - the claim help(TimezoneFinder) surfaces, and the opposite of what the usage docs say; both get_geometry docstrings pointed at a timezone_names.json that does not exist under that name; read_zone_names promised an empty list where it raises FileNotFoundError, and illustrated itself with a hardcoded zone count that the packaged data had since outgrown; and zone_id_of / zone_name_from_id each advertised an exception type they convert away, sending callers to write handlers that can never fire. Five further :param:/Args: entries in scripts/ and tests/ documented arguments that were removed along with the parallel shortcut compilation they belonged to. tests/test_documented_contracts.py pins the exception types and the coordinate access mode, so those promises now rest on something besides prose.
  • The test and benchmark suites no longer contain checks that cannot fail. Eighteen calls sat inside four shared pytest.raises blocks in tests/main_test.py, and execution leaves such a block at the first statement to raise - so one out-of-range coordinate, one positional call shape and one rejected get_geometry input were verified while the remaining fifteen were unreachable. Each is a test case of its own now: every coordinate just outside the WGS84 range, every positional call shape of every keyword-only lookup method, and the unknown-zone-name, past-the-end and negative zone id rejections of get_geometry. The __del__ cleanup test binds its exception per iteration rather than closing over the loop variable, which decided what a garbage-collected instance would raise long after the loop had moved on. On the benchmark side, pip_inputs_by_stratum validated only the strata the fixture happened to contain, so one missing from it altogether passed and surfaced later as a bare KeyError inside a benchmark, and the points and their labels were paired from two files with a non-strict zip that truncates silently. That grouping now lives in tests/auxiliaries.py as group_pip_inputs_by_stratum, checks against the declared PIP_STRATA - which the generator no longer keeps a second copy of - and has tests for each way the two fixture files can disagree.
  • Both point-in-polygon acceleration paths are now covered by a local test run, whichever one the environment happens to bind. The implementation is selected at import time and Numba wins whenever it is importable - which the documented setup (uv sync --all-groups) makes it - so the C extension was reached only by direct-kernel tests on hand-built arrays, and everything about how real polygon buffers arrive at it, including the read-only memory-mapped views, was first exercised in CI's non-numba tox environments: the configuration a plain pip install timezonefinder produces. tests/test_acceleration_paths.py now rebinds utils.inside_polygon and drives the full lookup stack through both implementations, asserting that they agree across the real boundary data, that the C path returns the known-correct answers, and that the point-in-polygon stage was reached at all rather than short-circuited by the shortcut layer (issue #​482).
  • The packaging guard in tests/test_package_contents.py no longer names files that do not exist. It asserts that nothing in the built sdist and wheel matches a list of unwanted paths, which passes just as readily when a pattern matches nothing at all: .github lacked the trailing slash that directory patterns need, Agents.* stopped matching when the file was renamed to AGENTS.md, and readthedocs.yaml never matched readthedocs.yml - so the CI configuration and both of those files were unguarded while the suite stayed green. The patterns are corrected, the provider stubs, contributing/, .agents/, .claude/ and .cursor/ are covered to match what MANIFEST.in excludes, and test_every_unwanted_pattern_matches_a_project_file now fails on any hand-written pattern that matches no path in the checkout, so the next rename cannot silently disarm one. It carries the unit marker rather than the module's former blanket integration mark, since it needs no build: a mistyped pattern surfaces in make test. .gitignore re-include lines (!…) are also no longer read as exclusions, which had produced one more parametrised case that could never fail. The converse direction is checked too: test_every_manifest_exclusion_is_guarded parses the exclude/recursive-exclude/prune/global-exclude directives out of MANIFEST.in and fails when one of them keeps a path out of the build that no pattern here names - previously such a line was enforced by the build and verified by nothing, so deleting it would have shipped the file with the suite still green. The two lists are hand-maintained statements of one intent and had drifted before, in both directions. The architecture page <https://timezonefinder.readthedocs.io/en/latest/architecture.html>__ describes the guard from both sides: among the tests that exist to give an invariant a failure mode, and under How it ships as the check on what the built artifacts actually contain.
  • The distributions built by the test suite are now built for the interpreter running it. uv build was invoked without --python, so it targeted the newest interpreter on the machine, while tests/test_integration.py creates its throwaway venv from sys.executable: on a checkout whose .venv is older than the newest installed Python, make testint produced a cp314 wheel and failed with pip's "not a supported wheel on this platform". Every tox environment offers a single interpreter, so the two agreed by accident in CI and the mismatch only ever hit developer machines, where the workaround was to pin UV_PYTHON. test_build_commands_pin_the_running_interpreter keeps the pin in place; it needs no build, so it fails in make test rather than waiting on a CI environment that cannot reproduce the mismatch.
  • Two tests no longer leak numpy's global error state into whatever pytest collects next. np.seterr and the warning filters are process-global, and test_overflow (tests/main_test.py) plus test_inside_polygon (tests/utils_test.py, six parametrisations) each set them and never restored them - so every later test in the same process ran with under promoted from ignore to warn, and which of the two modules pytest collected first decided the state the other ran under. The filters were undone only incidentally, by pytest's per-test catch_warnings(), not by the tests themselves. benchmarks/conftest.py already had the correct pattern; it now lives in tests/auxiliaries.py as the strict_numpy_errors context manager plus a thin strict_numpy_warnings fixture, re-exported through the conftest of each suite, and both call sites request it. The context manager form is what makes the restore directly testable - a leaked global otherwise surfaces only as an unrelated later failure that depends on collection order, which is the hardest kind to attribute.
  • The zone id invariants in scripts/timezone_data.py are each enforced in exactly one place, and now have tests. ZoneCollection.validate_structure and zone_positions each walked poly_zone_ids element by element checking it was non-decreasing and each raised the same message built from its own locals; the scan moves into one _validate_non_decreasing helper and zone_positions drops its copy, which could only ever have fired if a caller mutated the array in place - the validator runs at construction and nothing writes to it afterwards. A if min_zone_id < 0 branch is deleted as unreachable: the same method rejects any non-unsigned dtype a dozen lines earlier, so it read as the guard against negative zone ids while being incapable of firing. The class had no tests at all, so what it actually promises - the unsigned-dtype rejection that makes a negative id unrepresentable, the ordering and maximum-id rules, and the shape zone_positions returns - is now pinned by tests/timezone_data_test.py.
  • The seven out-of-range coordinates - one representable step outside the valid WGS84 range, per axis and at every corner - are declared once in tests/locations.py instead of verbatim in both tests/main_test.py and tests/utils_test.py, where only one copy carried the comment explaining what makes them interesting and adding a corner to it left the other testing a smaller set.
  • The shortcut compilation chain in scripts/shortcuts.py is annotated for what it is actually passed. Both annotations were the wrong way round: check_shortcut_sorting declared np.ndarray and only ever receives the list[int] that optimise_shortcut_ordering returns, and it hands the np.ndarray it derives to has_coherent_sequences(lst: list[int]). Widened rather than swapped, since tests/shortcut_test.py calls the latter with real lists.
  • The supported Python versions are declared in five places that cannot read each other - requires-python and one classifier per minor version in pyproject.toml, the py{...} factors of tox.ini's envlist, the test matrix and CIBW_BUILD_VERSIONS in build.yml, and py_limited_api in setup.py - and two "must match" comments said so while nothing enforced them. tests/test_python_version_support.py fails when they drift, in either of the two directions that fail silently: a classifier added without a matrix entry ships a version the package claims to support and CI never runs, and a requires-python raised without moving the abi3 base builds wheels tagged for an interpreter that is no longer supported. Each assertion was checked against the specific one-sided edit it targets, and both comments now name the test.
  • The data report generator states figures it derives rather than ones it restates, and its annotations describe what it returns. calculate_shortcut_index_stats took the number of H3 cells existing at the shortcut resolution from a ladder of literals covering resolutions 0 to 4 and fell through, for anything else, to the number of cells actually stored - which reports coverage of exactly 100 % instead of failing - behind an except ImportError that cannot fire, since h3 is a runtime dependency rather than an optional one. It asks h3.get_num_cells, which returns precisely the numbers that were tabulated. Running mypy over scripts/reporting.py, which the pre-commit hook excludes, found seventeen further disagreements between the module and its own signatures: the statistics bag was typed as holding scalars while returning two distributions, load_binary_data's nine-key result was a bare dict indexed by string literal, the table renderer declared string rows while stringifying whatever it is handed, main was annotated None while returning exit codes to exit(), and print_polygon_distribution_table documented a return value it never produced while its one caller discarded it. The two dict results are now TypedDict\ s in scripts/configs.py, carrying tests that assert their keys against what is really returned, since CI cannot type-check scripts/. The polygon count that labels a distribution row is no longer formatted into that label and parsed back out of it to key the example lookup. docs/data_report.rst and the benchmark reports regenerate byte-identically throughout.
  • Removed five definitions nothing referenced - three JSON/pickle helpers in scripts/utils.py and the import pickle they kept alive, the i8 dtype shim in timezonefinder/_numba_replacements.py that the no-numba fallback never imports, and a test helper self-documented as kept for future reference - and a guard in scripts/hex_utils.py that could not fire. Hex.poly_candidates re-read its cache after initialising it and returned an empty set if it were still unset, which no path through _init_candidates leaves it: an empty set there means "no candidate polygons", so a converter bug would have surfaced as silently missing shortcuts rather than as a failure. The property had no direct test, being reached only through shortcut generation, and now has one. _memory_mode_label looks its two labels up in PARAM_LABELS instead of spelling them out, so renaming the display vocabulary can no longer leave the comparison bullets and the tables above them disagreeing.
  • make parse and make testparse run again. Both invoked scripts/file_converter.py by path, which puts scripts/ on sys.path[0] instead of the repository root, so the converter's own from scripts.timezone_data import ... raised ModuleNotFoundError before any work started - a total failure that CI never sees, since it runs neither target. make testparse is the only cheap end-to-end exercise of the converter (update_data.sh needs a ~55 MB download), and nothing under tests/ covers parse_data(), so while it was broken the converter had no smoke test at all. The invocation documented in the usage docs had the same defect and is now the python -m scripts.file_converter form that update_data.sh already used; tests/test_script_invocations.py fails if a by-path invocation returns. Note that parse_data() writes its report to the checkout's committed docs/data_report.rst whatever -out it is given, so make testparse leaves that file describing the three-zone fixture - the target now says so.
  • scripts/ is type-checked by the mypy pre-commit hook instead of being excluded from it. The directory holds the data converter and the benchmark tooling - most of the repository's non-library Python - and with nothing running mypy over it the annotations had drifted to fifteen errors: two # type: ignore codes mypy no longer emits, so the ignore silenced nothing; two implicit Optional defaults that no_implicit_optional = true was already configured to reject; a dict annotated with a narrower value type than it is assigned; a bucket key and four bounding-box lists annotated int while Boundaries declares float; and two missing variable annotations. All fixed as annotations, with no runtime change. Two of the four errors mypy reported in tests/auxiliaries.py, which it reaches by following imports out of scripts/, are fixed alongside. test_scripts_are_type_checked_by_the_hook guards the exclude, which is a quieter way to stop type-checking a directory than the ignore_errors list the neighbouring tests already cover: it takes no override entry and reports nothing.
  • The eight __del__ cleanup tests that differed only in which exception cleanup() raised, and whether zero or one ResourceWarning was expected, are two parametrized tests over the suppressed and warned exception tuples. Each previously repeated the same subclass, the same catch_warnings block and the same filter, so adding a ninth exception to __del__'s suppression list meant copying the block a ninth time and a copy asserting the wrong count would be invisible. Coverage rises rather than falls: the hand-rolled loop asserting that __del__ never raises to user code now runs over all six exception types instead of four.
  • Three leftovers in the converter that read as bugs are gone: has_coherent_sequences built an iterator solely to take its first element and then looped from the start anyway (correct, but it reads as an off-by-one), compile_bboxes unpacked a pair and immediately reassigned half of it, and process_single_hex returned the hex_id it was handed so its only caller reassigned the loop variable to itself. Two shadowed builtins (dir as a loop variable, id as a parameter) are renamed and three bare generator signatures annotated. The benchmark renderer classifies its "other" group by name suffix, as the two lines above it do, rather than by deep-equality scan over lists of dicts; and the check-manifest ignore list drops two entries naming files that do not exist (CONTRIBUTING.rst, publish.py). Every converter change was verified by parsing tests/test_input.json before and after and comparing the outputs byte for byte.
twilio/twilio-python (twilio)

v9.13.0

Compare Source

Library - Chore

Twiml

  • Add ElevenLabs voices to <Say> verb.
  • Add partialPromptOnHangup, eagerEotThreshold, asrSmartFormat, ttsTextNormalization, ttsLanguageTextNormalization, elevenlabsLanguageTextNormalization, includeInPrompt, customerName, applicationReconnect, echoPromptFiltering, turnDetection attributes to <ConversationRelay>, and hints, asrSmartFormat, ttsTextNormalization, ttsLanguageTextNormalization attributes to <Language>

Api

  • API Changes

  • 2026-09-22

  • Simplified the criteria field description.
  • 2026-09-18

  • Moved readOnly on the snapshot count fields (profileCount, partitionCount) from the shared schema to the response usage sites, so the counts stay read-only in responses (no change for API consumers).
  • 2026-09-17

  • Renamed 3 Get* operations to Fetch* to match the operationId standard: FetchCohort, FetchSnapshot, FetchOperation.
  • Removed the unused ExpressionId schema and made the operation error example cohort-native, so no aud_ identifiers remain in the spec.
  • Kept libraryVisibility: hidden across the whole surface (info, path items, and operations).
  • 2026-09-08

  • Removed the deprecated header-based-versioning unified specs, consolidating audiences onto the path-based api.twilio.com/v1 surface.
  • 2026-08-31

  • Published the unified audiences spec at api.twilio.com/v1.
  • 2026-08-26

  • Fixed the Cohort operation response mapping in the unified audiences API.
  • 2026-08-19

  • Migrated the unified audiences spec to the Cohort surface (Audiences renamed to Cohorts).
  • Switched downstreamServiceName to audiences-domain.
  • 2026-08-05

  • Added the api.unified.version.preview beta feature.
  • Made the unified APIs available in prod us1.
  • 2026-07-30

  • Fixed example values.
  • 2026-07-29

  • Added the initial version of the audiences API to the unified APIs.
  • 2026-07-20

  • Deployed the audiences-domain OAS to the dev edge.
  • 2026-07-06

  • Added the prod-us1 realm to the audiences public API.
  • 2026-06-23

  • Changed the storeType enum from MEMORA to TWILIO.
  • 2026-05-04

  • Added the stage-us1 realm and x-rate-limit to the audiences API.
  • 2026-04-08

  • Added the initial audiences endpoints.
  • API Changes

  • 2026-10-28

  • Enabled the Redaction Configurations and Redaction Catalog resources in prod-us1.
  • 2026-10-27

  • Enabled the Redaction Configurations and Redaction Catalog resources in stage-us1.
  • 2026-09-28

  • Added the Redaction Configurations resource (/v1/RedactionConfigurations) as a private beta in dev-us1, gated by the api.redaction.enabled beta feature.
  • Added the Redaction Catalog resource (/v1/RedactionCatalog), under the same beta feature. It is restricted to One Console.
  • Add ApplicationSid parameter to TwimlSession and TwimlProcess Create endpoints

Audiences

  • 2026-10-23

  • Content updates:
  • Updated description for AdminFetchRecord
  • Updated description for AdminListCohorts
  • Updated description for AdminListCohortSnapshots
  • Updated description for AdminFetchCohortOperation
  • Updated description for AdminListSnapshotOperations
  • Updated schema description for OperationStatus
  • Added properties to Cohort: tags
  • Removed properties from Cohort: labels
  • Added properties to CohortSnapshot: tags
  • Removed properties from CohortSnapshot: labels
  • 2026-10-23

  • Content updates:
  • Updated description for ListCohorts
  • Updated description for CreateCohort
  • Updated description for UpdateCohort
  • Updated description for ListCohortSnapshots
  • Updated description for CreateCohortSnapshot
  • Updated description for FetchCohortOperation
  • Updated schema description for OperationStatus
  • Added properties to Cohort: tags
  • Removed properties from Cohort: labels
  • Added properties to CohortSnapshot: tags
  • ...and 8 more changes
  • 2026-10-14

  • Minor updates (formatting, metadata)
  • 2026-10-07

  • Minor updates (formatting, metadata)

Conversations

  • Enable the Imports endpoints (list, create, fetch, cancel) and the Import Outcomes list endpoint in prod-us1
  • Add GET /v2/Imports/{ImportId}/Outcomes to list an import's per-resource outcomes (dev-us1 and stage-us1)
  • Add EMAIL to the Conversations v2 Communication channel enum.

Deletions

  • 2026-10-28

  • Enable the User Data Deletions API in the stage-us1 realm.

Destinations

  • 2026-11-03

  • Enable Replay admin APIs for prod-us1 and prod-ie1 realms

Iam

  • Raised the most permissions in a POST /v1/Account/AuthorizedApps section, and in a part of the PUT /v1/Organization/AgentsRegistration/Permissions request, to 2000 for MCP agents; the limit of other consents is unchanged
  • Lowered the most permissions in a POST /v1/Account/AuthorizedApps section to 150, which is what an XMS policy holds
  • Made the GET and PUT /v1/Organization/AgentsRegistration/Permissions routes available in stage-us1 and prod-us1
  • Added the MCP agent consent fields to GET /v1/Account/AuthorizedApps: agent, account, organization, sections (the offered permissions per context) and redirect, and a 401 body with redirect when the account's organization has not registered or enabled the agent (code 25110, with organization_sid) or the account has no organization (code 25111). oauth_app_sid, client_sid, consent_state and app_permissions are now nullable, since an MCP agent response does not use them
  • Added sections (at least 1) with permissionSelectionMode (ALL_READ, ALL_READ_WRITE, SPECIFIC) and permissions (at most 200) to the POST /v1/Account/AuthorizedApps request, and response_mode and form_params to its 201 response
  • Made the /v1/Organization/AgentsRegistration routes available in stage-us1 and prod-us1
  • Added created_by (the name of the user who registered the agent) and created_by_sid to the /v1/Organization/AgentsRegistration responses; both are null for a registration made before the user was recorded
  • Moved the POST /v1/actions/post_login (PostLoginActionRequest) webhook payload to camelCase (accountSid, nodeId, actionId, userContext, authenticationContext, requestContext, ipAddress, userAgent, requestId, clientId, identifierType); replaced timestamp with the RFC 3339 sentAt, made authorizationDetails a JSON array, made completedAt an RFC 3339 string, and added userContext (isFirstLogin, user) with the CIAM id at userContext.user.userId
  • Added the optional type, agent, account, organization, sections, last_used and expires_at to the iam.v1.consent responses of the GET /v1/Account/AuthorizedApps and GET /v1/Organization/AuthorizedApps lists, for MCP connections. The list shows an MCP connection beside the OAuth applications, and deleting it revokes the whole connection
  • Added a 404 to PUT /v1/Account/AuthorizedApps/{consentSid} for an MCP connection, which cannot be updated
  • Added the GET and PUT /v1/Organization/AgentsRegistration/Permissions routes for what any agent may do in the caller's organization (dev-us1)
  • Renamed the properties of the /v1/Organization/AgentsRegistration responses to snake_case (registration_sid, friendly_name, client_url, date_created, date_updated), as the other IAM responses are; the request bodies keep clientUrl and enabled
  • Fixed the pagination meta of the GET /v1/Organization/AgentsRegistration response: it is mapped from the service's snake_case fields, as in the other IAM list routes, so key, pageSize and the tokens are no longer null
  • Added the /v1/Organization/AgentsRegistration routes (list, register, fetch, enable or disable, remove) for the MCP agents an organization lets its users connect (dev-us1)

Instrumentation

  • API Changes

  • 2026-10-12

  • Initial read-only admin-api spec for the Behavioral Events (events-domain) One Admin console: event producers (list, fetch), write keys (list), event schemas (list, fetch). dev-us1 and stage-us1 only.
  • 2026-10-27

  • Control Plane create, update and attach are synchronous (dev-us1), matching the deployed service:
  • CreateEventProducer returns 201 with the event producer (ETag, Idempotent-Replayed), not 202 with an operation
  • PatchEventProducer returns 200 with the event producer (ETag), not 202; If-Match is its only header parameter
  • AttachEventProducerSchemaVersion returns 201 with the attachment (Idempotent-Replayed), not 202
  • 2026-10-21

  • Replaced the Control Plane with the private-beta API (/v1/ControlPlane/…), enabled in dev-us1 only:
  • Removed the EventSources, Datasets, EventSources EventSchemas and AutoInstrumentationRules operations
  • Added /v1/ControlPlane/EventProducers (CreateEventProducer, ListEventProducers)
  • Added /v1/ControlPlane/EventProducers/{producerId} (FetchEventProducer, PatchEventProducer, DeleteEventProducer)
  • Added /v1/ControlPlane/EventProducers/{producerId}/WriteKeys (CreateWriteKey, ListWriteKeys)
  • Added /v1/ControlPlane/EventProducers/{producerId}/WriteKeys/{writeKey} (DeleteWriteKey)
  • Added /v1/ControlPlane/EventProducers/{producerId}/EventSchemas (AttachEventProducerSchemaVersion, ListEventProducerSchemaAttachments)
  • Added /v1/ControlPlane/EventProducers/{producerId}/EventSchemas/{schemaId}/Versions/{version} (DetachEventProducerSchemaVersion)
  • Added /v1/ControlPlane/EventSchemas (CreateEventSchema, ListEventSchemas)
  • Added /v1/ControlPlane/EventSchemas/{schemaId} (FetchEventSchema, PatchEventSchema, DeleteEventSchema)
  • Added /v1/ControlPlane/EventSchemas/{schemaId}/Versions (ListEventSchemaVersions)
  • Added /v1/ControlPlane/EventSchemas/{schemaId}/Versions/{version} (FetchEventSchemaVersion, DeleteEventSchemaVersion)
  • Updated /v1/ControlPlane/Operations/{operationId} (FetchControlPlaneOperationStatus) to the new operation shape; now dev-us1 only

Knowledge

  • 2026-10-27

  • Added 1 new path(s):
  • /v2/ControlPlane/KnowledgeMigrations/{accountSid}/Limits (AdminFetchKnowledgeMigrationLimits)
  • 2026-10-21

  • Content updates:
  • AdminListKnowledgeMigrations: the state query parameter is optional; without it the list returns every account with knowledge bases
  • Added properties to MigrationSummary: knowledgeBaseCount
  • 2026-10-19

  • Added 7 new path(s):
  • /v2/ControlPlane/KnowledgeMigrations (AdminListKnowledgeMigrations)
  • /v2/ControlPlane/KnowledgeMigrations/{accountSid} (AdminFetchKnowledgeMigration)
  • /v2/ControlPlane/KnowledgeMigrations/{accountSid}/History (AdminListKnowledgeMigrationHistory)
  • /v2/ControlPlane/KnowledgeMigrations/{accountSid}/Readiness (AdminFetchKnowledgeMigrationReadiness)
  • /v2/ControlPlane/KnowledgeMigrations/{accountSid}/Runs (AdminListKnowledgeMigrationRuns)
  • /v2/ControlPlane/KnowledgeMigrations/{accountSid}/Transitions (AdminListKnowledgeMigrationTransitions, AdminCreateKnowledgeMigrationTransition)
  • /v2/ControlPlane/KnowledgeMigrations/{accountSid}/Transitions/{transitionId} (AdminFetchKnowledgeMigrationTransition)

Lookups

  • Add test api support for Lookup Bulk Jobs endpoints

Memory

  • 2026-10-14

  • No path changes (schema only)
  • Added optional dataAsOf to the Store schema returned by AdminFetchStore.
  • 2026-10-14

  • Added optional dataAsOf to the Store schema returned by FetchStore.
  • 2026-10-08

  • Added FetchProfileOperation (GET /v1/ProfileOperations/{operationId}) to check the status and
  • progress of an asynchronous profile operation. The response includes a Retry-After header with
  • the minimum number of seconds to wait before polling again. The endpoint is hidden from the
  • helper libraries and gated behind the api.memory.2026Q3 beta feature.
  • The 202 responses of UpdateProfilesBulk and CreateProfilesImportV2 now return operationId,
  • createdAt and statusUrl (behind the api.memory.2026Q3 beta feature), plus the Operation-Id,
  • Location and Retry-After response headers. Use statusUrl with FetchProfileOperation to
  • track the operation.
  • Additive and backwards compatible: existing request and response fields are unchanged.

Messaging

  • Add data access policy admin endpoints (GET/PUT /v1/Accounts/{AccountSid}/DataAccessPolicy) to the messaging admin-api, backed by postflight-messaging-api (dev-us1 and stage-us1 only)
  • Enable data access policy admin endpoints (GET/PUT /v1/Accounts/{AccountSid}/DataAccessPolicy) in prod-us1 and prod-ie1

Segment

  • API Changes

  • 2026-11-04

  • Add read-only Cob routes: GET /v1/Segment/Cob/Whoami, /Records, /Audits, /Audits/{Family}/{Name}
  • 2026-10-30

  • Add GET /v1/Whoami (One Admin identity check for the Segment oneadmin-gateway)

Trusthub

  • Make id, sessionId and sessionToken required and non-nullable in the A2P embedded session response. (breaking change)

Voice

  • Add internal console ProvisioningStatus endpoint.

Webhooks

  • 2026-10-28

  • Changed: Rule prefix and value are limited to 1000 characters. A prefix must end with / and a value must not.
  • 2026-10-13

  • API maturity level changed from beta to ga. Library visibility changed from private to public.

v9.12.0

Compare Source

Audiences

  • 2026-10-06

  • Minor updates (formatting, metadata)
  • 2026-10-05

  • Minor updates (formatting, metadata)
  • 2026-10-02

  • Added 1 new path(s):
  • /preview/Cohorts/{cohortId}/Operations (AdminListCohortOperations)
  • 2026-10-01

  • Content updates:
  • Updated description for AdminListSnapshotOperations
  • 2026-09-28

  • Content updates:
  • Updated description for AdminListCohortSnapshots
  • Updated description for AdminFetchCohortSnapshot
  • Updated schema description for Criteria
  • Added properties to OperationPayload: cohortId
  • Removed properties from OperationPayload: audienceId
  • Updated schema description for OperationResult
  • Added properties to OperationResult: cohortId
  • Removed properties from OperationResult: audienceId
  • Updated schema description for Record
  • Updated schema description for Cohort
  • ...and 3 more changes
  • 2026-10-01

  • Minor updates (formatting, metadata)
  • 2026-09-28

  • Content updates:
  • Updated schema description for CohortOperationResult
  • Updated schema description for PartitionCount

Conversations

  • Add PATCH /v2/Imports/{id} to cancel an import, and the CANCELED import status (dev-us1 and stage-us1)
  • Add Imports endpoints for 1console (private visibility, dev-us1 and stage-us1)
  • Add traitExtractionStrategyIds and observationExtractionStrategyIds to the Conversations v2 Admin Configuration schema.
  • Align the Conversations v2 Capabilities list and create contracts with the backend domainId field.

Data-ingress

  • 2026-10-01

  • Minor updates (formatting, metadata)
  • 2026-09-17

  • Add support for Hubspot connector
  • 2026-10-01

  • Minor updates (formatting, metadata)
  • 2026-09-17

  • Add support for Hubspot connector

Events

  • Remove the Replays API (/v1/Replays, beta feature api.eventstreams.replay); the feature was never GA and is being sunset (breaking change)

Knowledge

  • 2026-09-24

  • Routing updates:
  • Changed downstreamServiceName from memora-domain to enterprise-knowledge-domain for all operations

Memory

  • 2026-09-30

  • The source field on observations and conversation summaries, and the source filter
  • on ListProfileObservations, now also accept forward slashes (/). The pattern is
  • ^[a-zA-Z0-9 _./-]+$. This is additive and backwards compatible: every previously
  • valid value is still accepted.
  • UpdateStore, UpdateTraitGroup, and UpdateDataMapping now require a body with at least one property. An empty {} gets a 400.

Messaging

  • Add opt-out configuration admin endpoints (GET/PUT/DELETE /v1/Accounts/{AccountSid}/OptOuts/{OptOutSid}/...) to the messaging admin-api (dev-us1 and stage-us1 only)
  • Add create opt-out configuration endpoint (POST /v1/Accounts/{AccountSid}/OptOuts) to the messaging admin-api (dev-us1 and stage-us1 only)
  • Add update messaging service endpoint (PUT /v1/Accounts/{AccountSid}/Services/{MessagingServiceSid}) to the messaging admin-api (dev-us1 and stage-us1 only)
  • Enable messaging service add-ons, update messaging service, and opt-out configuration admin endpoints in prod-us1 and prod-ie1
  • Add WhatsApp display name change support to Sender API: pending_display_name, pending_display_name_status and pending_display_name_status_date on fetch, and display_name_status on update and partial update

Routes

  • Set SDK and docs visibility of GET/POST /v3/ShortCodes/{isoCountryCode}/{shortCode} to public, maturity to ga

v9.11.2

Compare Source

Twiml

  • Add audio_format and sample_rate to Stream for HDCodec

Api

  • API Changes

  • 2026-09-22

  • Simplified the criteria field description.
  • 2026-09-18

  • Moved readOnly on the snapshot count fields (profileCount, partitionCount) from the shared schema to the response usage sites, so the counts stay read-only in responses (no change for API consumers).
  • 2026-09-17

  • Renamed 3 Get* operations to Fetch* to match the operationId standard: FetchCohort, FetchSnapshot, FetchOperation.
  • Removed the unused ExpressionId schema and made the operation error example cohort-native, so no aud_ identifiers remain in the spec.
  • Kept libraryVisibility: hidden across the whole surface (info, path items, and operations).
  • 2026-09-08

  • Removed the deprecated header-based-versioning unified specs, consolidating audiences onto the path-based api.twilio.com/v1 surface.
  • 2026-08-31

  • Published the unified audiences spec at api.twilio.com/v1.
  • 2026-08-26

  • Fixed the Cohort operation response mapping in the unified audiences API.
  • 2026-08-19

  • Migrated the unified audiences spec to the Cohort surface (Audiences renamed to Cohorts).
  • Switched downstreamServiceName to audiences-domain.
  • 2026-08-05

  • Added the api.unified.version.preview beta feature.
  • Made the unified APIs available in prod us1.
  • 2026-07-30

  • Fixed example values.
  • 2026-07-29

  • Added the initial version of the audiences API to the unified APIs.
  • 2026-07-20

  • Deployed the audiences-domain OAS to the dev edge.
  • 2026-07-06

  • Added the prod-us1 realm to the audiences public API.
  • 2026-06-23

  • Changed the storeType enum from MEMORA to TWILIO.
  • 2026-05-04

  • Added the stage-us1 realm and x-rate-limit to the audiences API.
  • 2026-04-08

  • Added the initial audiences endpoints.
  • Add TwimlProcessStatusCallbackEvents parameter to CreateTwimlProcess endpoint
  • Add twiml_process resource alongside twiml_session (twiml_session is deprecated and will be removed in a future release)

Audiences

  • 2026-09-14

  • Minor updates (formatting, metadata)
  • 2026-09-11

  • Content updates:
  • Updated summary for AdminFetchRecord
  • Updated summary for AdminFetchCohort
  • Updated summary for AdminFetchCohortSnapshot
  • Updated summary for AdminFetchCohortOperation
  • Updated schema description for ResourceLabels
  • 2026-09-22

  • Content updates:
  • Updated schema description for Criteria
  • 2026-09-18

  • Minor updates (formatting, metadata)
  • 2026-09-17

  • Minor updates (formatting, metadata)
  • 2026-09-17

  • Content updates:
  • Updated description for CreateCohort
  • Updated description for ListCohortSnapshots
  • Updated description for CreateCohortSnapshot
  • Updated description for FetchCohortSnapshot
  • Updated description for ListCohortSnapshotProfiles
  • Updated schema description for Criteria
  • Updated schema description for Cohort
  • Updated schema description for CohortSnapshot
  • Updated schema description for CohortOperationResult
  • Updated schema description for CohortOperation
  • 2026-09-15

  • Minor updates (formatting, metadata)
  • 2026-09-14

  • Content updates:
  • Updated summary for FetchCohort
  • Updated summary for FetchCohortSnapshot
  • Updated summary for FetchCohortOperation
  • Updated schema description for ResourceLabels

Capabilities

  • Add a feature-gated preview endpoint to create Capabilities.

Conversations

  • Add the feature-gated Capabilities list and create endpoints to Conversations v2.

Data-ingress

  • 2026-09-07

  • Minor updates (formatting, metadata)
  • 2026-09-09

  • Added 16 new path(s):
  • /v1/DataSyncs/{syncId} (FetchDataSync)
  • /v1/CloudAppSources/{sourceId}/Objects (ListCloudAppObjects)
  • /v1/WarehouseSources/{sourceId}/Preview (CreateWarehousePreview)
  • /v1/WarehouseSources/{sourceId}/Preview/{operationId} (FetchWarehousePreview)
  • /v1/DataSample/{operationId} (FetchDataSample)
  • /v1/ControlPlane/CloudAppSources/{sourceId} (FetchCloudAppSource, PatchCloudAppSource, DeleteCloudAppSource)
  • /v1/ControlPlane/CloudAppSources/{sourceId}/Datasets (ListCloudAppDatasets, CreateCloudAppDataset)
  • /v1/ControlPlane/CloudAppSources/{sourceId}/Datasets/{datasetId} (FetchCloudAppDataset, PatchCloudAppDataset, DeleteCloudAppDataset)
  • /v1/ControlPlane/WarehouseSources/{sourceId} (FetchWarehouseSource, PatchWarehouseSource, DeleteWarehouseSource)
  • /v1/ControlPlane/WarehouseSources/{sourceId}/Datasets (ListWarehouseDatasets, CreateWarehouseDataset)
  • ...and 6 more paths
  • Removed 31 path(s):
  • /v1/DataSyncs/{SyncId} (FetchDataSync)
  • /v1/CloudAppSources/{SourceId}/Objects (ListCloudAppObjects)
  • /v1/WarehouseSources/{SourceId}/Preview (CreateWarehousePreview)
  • /v1/WarehouseSources/{SourceId}/Preview/{OperationId} (FetchWarehousePreview)
  • /v1/DataSample/{OperationId} (FetchDataSample)
  • /v1/ControlPlane/CloudAppSources/{SourceId} (FetchCloudAppSource, PatchCloudAppSource, DeleteCloudAppSource)
  • /v1/ControlPlane/CloudAppSources/{SourceId}/Datasets (ListCloudAppDatasets, CreateCloudAppDataset)
  • /v1/ControlPlane/CloudAppSources/{SourceId}/Datasets/{DatasetId} (FetchCloudAppDataset, PatchCloudAppDataset, DeleteCloudAppDataset)
  • /v1/ControlPlane/WarehouseSources/{SourceId} (FetchWarehouseSource, PatchWarehouseSource, DeleteWarehouseSource)
  • /v1/ControlPlane/WarehouseSources/{SourceId}/Datasets (ListWarehouseDatasets, CreateWarehouseDataset)
  • ...and 21 more paths

Destinations

  • 2026-09-24

  • Content updates:
  • Removed GET from the method enum on the webhook destination type's config options
  • 2026-09-22

  • Content updates:
  • Added CDP to the categories enum on DestinationType
  • 2026-09-14

  • Enable admin APIs for stage-us1 and prod-ie1 realms
  • 2026-09-11

  • Content updates:
  • Updated description for CreateDestination
  • Updated description for UpdateDestination
  • Updated description for DeleteDestination
  • Updated schema description for CredentialInput
  • Updated schema description for DestinationCredentialOptions
  • 2026-09-11

  • Content updates:
  • Updated description for ListDestinationTypes
  • Updated description for GetDestinationType
  • Updated description for CreateDestination
  • Updated description for UpdateDestination
  • 2026-09-10

  • Made ListDestinationTypes and GetDestinationType unauthenticated (security: []).
  • Removed iamOperation, addAuthorizationHeader, and betaFeature from these operations.

Iam

  • Removed user_context from the POST /v1/actions/post_login (PostLoginActionRequest) webhook payload; the login email is read from authentication_context.methods
  • Replaced acr and completed_factors with authentication_context (acr, amr, methods) on the POST /v1/actions/post_login (PostLoginActionRequest) webhook payload
  • Made request_context and request_context.ip_address required on the POST /v1/actions/post_login (PostLoginActionRequest) webhook payload

Intelligence

  • Added optional rule.operators[] parameter override field to `POST /v3/RuleExecutions
  • Change Summary in POST /v3/RuleExecutions

Knowledge

  • 2026-09-23

  • Content updates:
  • Added properties to WebSourceDetails: errors
  • Routing updates:
  • Changed downstreamServiceName from memora-domain to enterprise-knowledge-domain for all operations

Memory

  • 2026-09-18

  • Added 2 new path(s):
  • /v1/ControlPlane/TraitExtractionStrategies (AdminListTraitExtractionStrategies)
  • /v1/ControlPlane/TraitExtractionStrategies/{traitStrategyId} (AdminFetchTraitExtractionStrategy)
  • 2026-09-03

  • No path changes (schema description only)
  • Clarified the DataMappingCore description: the PATCH body requires at least one field.
  • 2026-09-10

  • Added 2 new path(s) for Observation Extraction Strategies:
  • /v1/ControlPlane/ObservationExtractionStrategies (ListObservationExtractionStrategies, CreateObservationExtractionStrategy)
  • /v1/ControlPlane/ObservationExtractionStrategies/{observationExtractionStrategyId} (FetchObservationExtractionStrategy, UpdateObservationExtractionStrategy, DeleteObservationExtractionStrategy)
  • Content updates:
  • Updated CreateObservationExtractionStrategyInput description to document that at least one of allowedCategories/prohibitedCategories must be provided with a non-empty list
  • 2026-09-07

  • Added 1 new path(s) for Profile:
  • /v1/Stores/{storeId}/Profiles/BulkDeletions (CreateProfilesBulkDeletion)
  • 2026-09-03

  • UpdateStore, UpdateTraitGroup, UpdateDataMapping, and UpdateTraitExtractionStrategy now require a body with at least one property. An empty {} gets a 400.

Routes

  • Add GET/POST /v3/ShortCodes/{isoCountryCode}/{shortCode} to assign and fetch the Inbound Processing Region for short codes

Verify

  • Add aaguid and date_last_approved to passkeys factors metadata.

Voice

  • Add typed Recording AccountDefaultConfiguration public API endpoints.

Webhooks

  • 2026-09-24

  • Changed: GET /v1/Webhooks/Settings now documents each item as the full Setting rather than SettingSummary, adding auth, signature, connection and edgeZones to the list response. The service already returned these fields; only the schema understated them. Additive for consumers — no field is removed or renamed. The now-unreferenced SettingSummary schema is removed.

v9.11.1

Compare Source

Library - Fix

Audiences

  • 2026-09-01

  • Backticked brace- and angle-bracket-bearing tokens in descriptions for MDX safety.
  • Updated a prose reference to the renamed FetchCohortSnapshot operation.
  • 2026-08-26

  • Removed 5 path(s):
  • /preview/Audiences (AdminListAudiences)
  • /preview/Audiences/{audienceId} (AdminGetAudience)
  • /preview/Snapshots (AdminListSnapshots)
  • /preview/Snapshots/{snapshotId} (AdminGetSnapshot)
  • /preview/Operations/{operationId} (AdminGetOperation)
  • 2026-08-25

  • Minor updates (formatting, metadata)
  • 2026-08-24

  • Added 1 new path(s):
  • /preview/Snapshots/{cohortSnapshotId}/Operations (AdminListSnapshotOperations)
  • Removed 1 path(s):
  • /preview/Snapshots/{snapshotId}/Operations (ListAdminSnapshotOperations)
  • 2026-08-20

  • Renamed all 13 operations so the operationId keyword leads (AdminGetCohort -> FetchAdminCohort) to meet standard.
  • Set info libraryVisibility to hidden to exclude this admin spec from generation.
  • Added the standard pageSize/pageToken query parameters to ListAdminSnapshotOperations, the only list operation missing them.
  • 2026-08-19

  • Added 5 new path(s):
  • /preview/Cohorts (AdminListCohorts)
  • /preview/Cohorts/{cohortId} (AdminGetCohort)
  • /preview/CohortSnapshots (AdminListCohortSnapshots)
  • /preview/CohortSnapshots/{cohortSnapshotId} (AdminGetCohortSnapshot)
  • /preview/CohortOperations/{cohortOperationId} (AdminGetCohortOperation)
  • 2026-09-01

  • Renamed 3 Get* operations to Fetch* to match the operationId standard: FetchCohort, FetchCohortSnapshot, FetchCohortOperation. The transpiler skips operations whose operationId does not start with a standard keyword, which had been dropping all three from generated output.
  • Set libraryVisibility to private (was hidden) so the spec is eligible for the private docs pipeline.
  • Backticked brace- and angle-bracket-bearing tokens in descriptions for MDX safety.
  • 2026-08-28

  • Removed 6 path(s):
  • /preview/Audiences (ListAudiences, CreateAudience)
  • /preview/Audiences/{audienceId} (FetchAudience, UpdateAudience, DeleteAudience)
  • /preview/Snapshots (ListSnapshots, CreateSnapshot)
  • /preview/Snapshots/{snapshotId} (FetchSnapshot, DeleteSnapshot)
  • /preview/Snapshots/{snapshotId}/Profiles (ListSnapshotProfiles)
  • /preview/Operations/{operationId} (FetchOperation)
  • 2026-08-20

  • Renamed 6 Get* operations to Fetch* to match the operationId standard.
  • Hid the deprecated Audiences/Snapshots paths and /preview/Operations/{operationId}.
  • Backticked 11 brace-bearing tokens in descriptions for MDX safety.

Conversations

  • Add PATCH support for partial updates to Configuration
  • Add VIDEO to the Conversations v2 Communication channel enum.

Data-ingress

  • API Changes

  • 2026-09-01

  • Minor updates (formatting, metadata)
  • 2026-08-12

  • Minor updates (formatting, metadata)
  • 2026-08-12

  • Initial release with 13 paths and 13 operations

Destinations

  • 2026-09-08

  • Added prod-ie1 to supportedRealms and iamOperationEnabledRealms for all endpoints
  • 2026-09-01

  • Removed the unused admin-api placeholder from supportedRealms on the public endpoints;
  • One Admin routes now live in admin_openapi.yaml.
  • Added 6 new path(s) (admin_openapi.yaml):
  • /v1/ControlPlane/Destinations (AdminListDestinations)
  • /v1/ControlPlane/Destinations/{destinationId} (AdminGetDestination)
  • /v1/ControlPlane/Subscriptions (AdminListSubscriptions)
  • /v1/ControlPlane/Subscriptions/{subscriptionId} (AdminGetSubscription)
  • /v1/ControlPlane/Subscriptions/{subscriptionId}/EventTypes (AdminListSubscribedEvents)
  • /v1/ControlPlane/Subscriptions/{subscriptionId}/EventTypes/{eventType} (AdminGetSubscribedEvent)
  • 2026-08-26

  • Minor updates (formatting, metadata)
  • 2026-08-26

  • Minor updates (formatting, metadata)
  • 2026-08-25

  • Content updates:
  • Updated description for CreateDestination
  • 2026-08-12

  • Minor updates (formatting, metadata)
  • 2026-08-12

  • Content updates:
  • Added properties to DestinationType: releaseStatus
  • Removed properties from DestinationType: maturity

Email

  • API Changes

  • 2026-09-02

  • Added 1 new path(s):
  • /v1/Sends/Cohorts (sendCohort)
  • 2026-08-28

  • Content updates:
  • Updated summary for sendTransactional
  • Added parameter(s) to sendTransactional: X-Twilio-Version
  • Updated schema description for SuppressionsGroup
  • Added properties to SuppressionsGroup: type
  • Removed properties from SuppressionsGroup: mode
  • Updated schema description for SuppressionsGlobal
  • Added properties to SuppressionsGlobal: type
  • Removed properties from SuppressionsGlobal: mode
  • Updated schema description for Suppressions
  • Updated schema description for LongRunningOperationResponse
  • 2026-08-27

  • Content updates:
  • Updated description for SendEmail
  • Added parameter(s) to SendEmail: Content-Encoding, Idempotency-Key
  • Updated schema description for Envelope
  • Updated schema description for SuppressionsGroup
  • Updated schema description for SuppressionsGlobal

Iam

  • Removed redirect_urls from the GET /v1/Account/AuthorizedApps/{consentSid} response
  • Added company_name, homepage_url, tos_url, and redirect_urls to the GET /v1/Account/AuthorizedApps/{consentSid} response
  • Added GET /v1/Account/AuthorizedApps/{consentSid} - fetch authorized app details, including allowed permissions, by consent identifier SID
  • added container-scoped entitlements endpoint (GET /v2/Container/{containerId}/Entitlements)

Instrumentation

  • API Changes

  • 2026-09-04

  • Content updates:
  • Added IdempotencyKeyHeader to Create/Patch/Delete AutoInstrumentationRule; corrected the shared header's description
  • Added operationId/createdAt to LongRunningOperationResponse; corrected example status from RUNNING to PENDING
  • Renamed Signal.timestamp → occurredAt, HourlyStats.hourTimestamp → hourAt; uppercased Signal.type and ListSignals' signalType enums to SCREAMING_SNAKE_CASE
  • Renamed UserBehaviors request/response fields to camelCase; added the summaryDelivery webhook callback
  • Reshaped PaginationMeta (added required key, corrected pageSize bounds) and all 6 list operations (ListEventSources, ListEventSourceDatasets, ListEventSchemas, ListAutoInstrumentationRules, ListSignals, ListSignalStats) to the meta envelope; added ListSignalStats' 500 response
  • Narrowed the domain's default supportedRealms to dev-us1 only; POST /v1/UserBehaviors (AnalyzeUserBehaviors) keeps its own dev-us1/stage-us1 override (prod withheld pending stage validation) — every other operation is now dev-only
  • 2026-08-31

  • Content updates:
  • Fixed stale tdi_ TTID prefix throughout (path params, examples, transaction URLs) to events_; unified dataset/schema ID formats (tdi_dat_/tdi_dataset_ → events_dataset_, tdi_schema_ → events_evsch_); fixed rule-version examples to match the real version: integer field
  • Fixed operationId to use the domain-agnostic proc_job_ TTID prefix; corrected the OperationId parameter's length constraint (max=34 → max=35) and added a pattern
  • Fixed two length constraints hardcoded for the old tdi_ prefix length: IngestEventBatch's sourceId path parameter (maxLength 37 → 40); removed the stale, redundant Twilio-Write-Key header parameter
  • Added the missing AutoInstrumentationRuleId regex pattern
  • Fixed info.title ("Twilio Data Ingress - Instrumentation API" → "Events Domain - Instrumentation API")
  • Added 1 new API path:
  • /v1/UserBehaviors (AnalyzeUserBehaviors)
  • 2026-07-28

  • Initial release — 21 paths, 37 operations across three API surfaces:
  • Control Plane (/v1/ControlPlane/…):
  • /v1/ControlPlane/EventSources (CreateEventSource, ListEventSources)
  • /v1/ControlPlane/EventSources/{sourceId} (FetchEventSource, PatchEventSource, DeleteEventSource)
  • /v1/ControlPlane/EventSources/{sourceId}/WriteKeys (CreateWriteKey, ListWriteKeys)
  • /v1/ControlPlane/EventSources/{sourceId}/WriteKeys/{writeKey} (DeleteWriteKey)
  • /v1/ControlPlane/EventSources/{sourceId}/Datasets (CreateEventSourceDataset, ListEventSourceDatasets)
  • /v1/ControlPlane/EventSources/{sourceId}/Datasets/{datasetId} (FetchEventSourceDataset, PatchEventSourceDataset, DeleteEventSourceDataset)
  • /v1/ControlPlane/EventSources/{sourceId}/EventSchemas (CreateEventSchema, ListEventSchemas)
  • /v1/ControlPlane/EventSources/{sourceId}/EventSchemas/{schemaId} (FetchEventSchema, PatchEventSchema, DeleteEventSchema)
  • /v1/ControlPlane/EventSources/{sourceId}/AutoInstrumentationRules (CreateAutoInstrumentationRule, ListAutoInstrumentationRules)
  • /v1/ControlPlane/EventSources/{sourceId}/AutoInstrumentationRules/{autoInstrumentationRuleId} (FetchAutoInstrumentationRule, PatchAutoInstrumentationRule, DeleteAutoInstrumentationRule)
  • /v1/ControlPlane/EventSources/{sourceId}/AutoInstrumentationRules/{autoInstrumentationRuleId}/Versions (ListAutoInstrumentationRuleVersions)
  • /v1/ControlPlane/EventSources/{sourceId}/AutoInstrumentationRules/{autoInstrumentationRuleId}/Versions/{version} (FetchAutoInstrumentationRuleVersion)
  • /v1/ControlPlane/Datasets (ListDatasets)
  • /v1/ControlPlane/Datasets/{datasetId} (FetchDataset)
  • /v1/ControlPlane/Operations/{operationId} (FetchControlPlaneOperationStatus)
  • /v1/ControlPlane/Datasets (ListDatasets)
  • /v1/ControlPlane/Datasets/{datasetId} (FetchDataset)
  • Event Ingestion (/v1/EventSources/…):
  • /v1/EventSources/{sourceId}/Batch (IngestEventBatch)
  • /v1/EventSources/{sourceId}/AutoInstrumentationRules/{autoInstrumentationRuleId}/Preview (TriggerAutoInstrumentationPreview)
  • /v1/EventSources/{sourceId}/AutoInstrumentationRules/{autoInstrumentationRuleId}/Preview/{operationId} (GetAutoInstrumentationPreviewResult)
  • Signal API (/v1/EventSources/…):
  • /v1/EventSources/{sourceId}/Signals (IngestSignals, ListSignals)
  • /v1/EventSources/{sourceId}/Signals/{signalKey} (GetSignalBySignalKey)
  • /v1/EventSources/{sourceId}/SignalStats (ListSignalStats)

Knowledge

  • 2026-07-20

  • Content updates:
  • Added new schemas: KnowledgeErrorInstance, KnowledgeErrorGroup
  • Added errors field to WebSourceDetails for reporting web crawl errors

Memory

  • 2026-08-18

  • Breaking change:
  • Removed the deprecated CSV and DATASET values from the DataMappingType enum.
  • INGRESS, DATASET_CLOUDAPP, and DATASET_WAREHOUSE are the only valid values now.
  • Removed the DataMappingFromCSV and DataMappingFromDataSet schemas and their
  • oneOf/discriminator entries on DataMappingFromTypes, along with the corresponding
  • CSV/DATASET discriminator mapping keys.
  • Any caller still sending type: CSV or type: DATASET on AdminListDataMappings
  • (filtering by those values) will get a 400.
  • 2026-08-10

  • No path changes (updated metadata only)
  • DataMappingType gains INGRESS, DATASET_CLOUDAPP, and DATASET_WAREHOUSE.
  • CSV and DATASET remain valid and unchanged; they are deprecated aliases and
  • will be removed in a follow-up change.
  • DataMappingFromTypes gains three oneOf members and three discriminator keys:
  • DataMappingFromIngress (renames DataMappingFromCSV),
  • DataMappingFromCloudAppDataSet and DataMappingFromWarehouseDataSet
  • (both split from DataMappingFromDataSet, distinguishing a cloud-app-backed
  • TDI dataset from a warehouse-backed one).
  • Additive and backwards compatible: existing CSV and DATASET payloads are
  • unaffected.
  • 2026-08-27

  • Added 2 new path(s) for Trait Extraction Strategies:
  • /v1/ControlPlane/TraitExtractionStrategies (ListTraitExtractionStrategies, CreateTraitExtractionStrategy)
  • /v1/ControlPlane/TraitExtractionStrategies/{traitStrategyId} (FetchTraitExtractionStrategy, UpdateTraitExtractionStrategy, DeleteTraitExtractionStrategy)
  • 2026-08-18

  • Breaking change:
  • Removed the deprecated CSV and DATASET values from the DataMappingType enum.
  • INGRESS, DATASET_CLOUDAPP, and DATASET_WAREHOUSE are the only valid values now.
  • Removed the DataMappingFromCSV and DataMappingFromDataSet schemas and their
  • oneOf/discriminator entries on DataMappingFromTypes, along with the corresponding
  • CSV/DATASET discriminator mapping keys.
  • Any caller still sending type: CSV or type: DATASET on CreateDataMapping or
  • UpdateDataMapping (or filtering ListDataMappings/ListDataMappingSuggestions by
  • those values) will get a 400.
  • 2026-08-10

  • No path changes (updated metadata only)
  • DataMappingType gains INGRESS, DATASET_CLOUDAPP, and DATASET_WAREHOUSE.
  • CSV and DATASET remain valid and unchanged; they are deprecated aliases and
  • will be removed in a follow-up change.
  • DataMappingFromTypes gains three oneOf members and three discriminator keys:
  • DataMappingFromIngress (renames DataMappingFromCSV),
  • DataMappingFromCloudAppDataSet and DataMappingFromWarehouseDataSet
  • (both split from DataMappingFromDataSet, distinguishing a cloud-app-backed
  • TDI dataset from a warehouse-backed one).
  • Additive and backwards compatible: existing CSV and DATASET payloads are
  • unaffected.

Messaging

  • Add SenderIdentity, SenderType, and SenderRegion filter query parameters to list numbers and senders endpoint (beta)
  • Add capabilities field to the numbers and senders response (beta)
  • Remove the WhatsApp Senders v1 endpoints (/v1/Channels/WhatsApp/Senders) from RestProxy; the sender was routed to the sunsetting messaging-whatsapp-k8s-orch downstream. Use the Senders v2 API (/v2/Channels/Senders) instead.

Verify

  • Add Templates optional parameter on Verification creation (a stringified JSON array of sid/substitutions entries). When provided, Templates takes precedence over TemplateSid.

Voice

  • 2026-09-03

  • Added links.conversation to Transcription resources as the absolute Conversations API URL for the
  • transcript's conversationId. It is present once the transcript has been stored; the links object
  • is omitted otherwise.
  • 2026-09-01

  • Removed mediaUrl from CreateRequestWithMediaUrl's required fields so a request with neither sourceId nor mediaUrl reaches the downstream service, which rejects it with the specific error code 17500 instead of a generic gateway 400
  • Set additionalProperties: false on both CreateRequestWithSourceId and CreateRequestWithMediaUrl so the two oneOf variants stay mutually exclusive: sourceId is undeclared on the media-URL variant and mediaUrl is undeclared on the source-ID variant, keeping every request shape resolvable to exactly one variant
  • 2026-08-05

  • Added GET /v3/Transcriptions to list and filter transcriptions (status, sourceId, languageCode, createdAfter/createdBefore) with pageSize/pageToken pagination. createdAfter is inclusive and createdBefore exclusive. Returns 422 (error code 17535) when a sourceId's historical item count exceeds the service scan cap

Webhooks

v9.11.0

Compare Source

Library - Fix

Twiml

  • Remove <Assistant> noun from <Connect> verb as part of the AI Assistants deprecation (breaking change)
  • Add passports attribute to <Dial> verb for SHAKEN/STIR passport passthrough

Accounts

  • Add SuppressEmailNotification parameter to the Secondary Auth Token and Auth Token promotion endpoints. Set it to true to suppress the email notification sent to account owners and administrators. Defaults to false, preserving existing behavior.
  • Add SMS Pumping Protection GET and POST API

Ai

  • Removing ai workbench apis

Api

  • Add missing uri property to the twiml_session resource

Data-ingress

  • 2026-08-07

  • Removed 1 API path:
  • /v1/DataQuery (Realtime DataQuery)
  • 2026-07-07

  • Added 1 new API path (data plane):
  • /v1/DataQuery (Realtime DataQuery)
  • 2026-06-17

  • Content updates:
  • Added properties to OAuthJWTBearerCredentials: privateKey, privateKeyPassphrase
  • 2026-06-12

  • Added 16 new path(s):
  • /v1/DataSyncs/{syncId} (FetchDataSync)
  • /v1/CloudAppSources/{sourceId}/Objects (ListCloudAppObjects)
  • /v1/WarehouseSources/{sourceId}/Preview (CreateWarehousePreview)
  • /v1/WarehouseSources/{sourceId}/Preview/{operationId} (FetchWarehousePreview)
  • /v1/DataSample/{operationId} (FetchDataSample)
  • /v1/ControlPlane/CloudAppSources/{sourceId} (FetchCloudAppSource, PatchCloudAppSource, DeleteCloudAppSource)
  • /v1/ControlPlane/CloudAppSources/{sourceId}/Datasets (ListCloudAppDatasets, CreateCloudAppDataset)
  • /v1/ControlPlane/CloudAppSources/{sourceId}/Datasets/{datasetId} (FetchCloudAppDataset, PatchCloudAppDataset, DeleteCloudAppDataset)
  • /v1/ControlPlane/WarehouseSources/{sourceId} (FetchWarehouseSource, PatchWarehouseSource, DeleteWarehouseSource)
  • /v1/ControlPlane/WarehouseSources/{sourceId}/Datasets (ListWarehouseDatasets, CreateWarehouseDataset)
  • ...and 6 more paths
  • Removed 16 path(s):
  • /v1/DataSyncs/{SyncId} (FetchDataSync)
  • /v1/CloudAppSources/{SourceId}/Objects (ListCloudAppObjects)
  • /v1/WarehouseSources/{SourceId}/Preview (CreateWarehousePreview)
  • /v1/WarehouseSources/{SourceId}/Preview/{OperationId} (FetchWarehousePreview)
  • /v1/DataSample/{OperationId} (FetchDataSample)
  • /v1/ControlPlane/CloudAppSources/{SourceId} (FetchCloudAppSource, PatchCloudAppSource, DeleteCloudAppSource)
  • /v1/ControlPlane/CloudAppSources/{SourceId}/Datasets (ListCloudAppDatasets, CreateCloudAppDataset)
  • /v1/ControlPlane/CloudAppSources/{SourceId}/Datasets/{DatasetId} (FetchCloudAppDataset, PatchCloudAppDataset, DeleteCloudAppDataset)
  • /v1/ControlPlane/WarehouseSources/{SourceId} (FetchWarehouseSource, PatchWarehouseSource, DeleteWarehouseSource)
  • /v1/ControlPlane/WarehouseSources/{SourceId}/Datasets (ListWarehouseDatasets, CreateWarehouseDataset)
  • ...and 6 more paths
  • 2026-06-11

  • Added 3 new Signal API path(s) for public exposure (data plane):
  • /v1/EventSources/{sourceId}/Signals (ListSignals)
  • /v1/EventSources/{sourceId}/Signals/{signalKey} (GetSignalBySignalKey)
  • /v1/EventSources/{sourceId}/SignalStats (ListSignalStats)
  • Added new Signal API schemas:
  • Signal, SignalListResponse, HourlyStats, SignalStatsResponse
  • 2026-05-26

  • Added 12 new path(s) for public exposure:
  • /v1/ControlPlane/EventSources (CreateEventSource, ListEventSources)
  • /v1/ControlPlane/EventSources/{SourceId} (FetchEventSource, PatchEventSource, DeleteEventSource)
  • /v1/ControlPlane/EventSources/{SourceId}/WriteKeys (CreateWriteKey, ListWriteKeys)
  • /v1/ControlPlane/EventSources/{SourceId}/WriteKeys/{WriteKey} (DeleteWriteKey)
  • /v1/ControlPlane/EventSources/{SourceId}/Datasets (CreateEventSourceDataset, ListEventSourceDatasets)
  • /v1/ControlPlane/EventSources/{SourceId}/Datasets/{DatasetId} (FetchEventSourceDataset, PatchEventSourceDataset, DeleteEventSourceDataset)
  • /v1/ControlPlane/EventSources/{SourceId}/EventSchemas (CreateEventSchema, ListEventSchemas)
  • /v1/ControlPlane/EventSources/{SourceId}/EventSchemas/{SchemaId} (FetchEventSchema, PatchEventSchema, DeleteEventSchema)
  • /v1/ControlPlane/AutoInstrumentationRule (CreateAutoInstrumentationRule, ListAutoInstrumentationRules)
  • /v1/ControlPlane/AutoInstrumentationRule/{AutoInstrumentationRuleId} (FetchAutoInstrumentationRule, PatchAutoInstrumentationRule, DeleteAutoInstrumentationRule)
  • /v1/ControlPlane/AutoInstrumentationRule/{AutoInstrumentationRuleId}/Versions (ListAutoInstrumentationRuleVersions)
  • /v1/ControlPlane/AutoInstrumentationRule/{AutoInstrumentationRuleId}/Versions/{Version} (FetchAutoInstrumentationRuleVersion)
  • Added new schemas:
  • EventSource, EventSourceCreate, EventSourceUpdate
  • WriteKey, WriteKeyCreate
  • EventSourceDataset, EventSourceDatasetCreate, EventSourceDatasetUpdate
  • EventSchema, EventSchemaCreate, EventSchemaUpdate, EventSchemaField, EventSchemaProperty
  • AutoInstrumentationRule, AutoInstrumentationRuleCreate, AutoInstrumentationRuleUpdate
  • AutoInstrumentationRuleVersion, AutoInstrumentationRuleVersionsResponse
  • 2026-06-12

  • Added 16 new path(s):
  • /v1/DataSyncs/{syncId} (FetchDataSync)
  • /v1/CloudAppSources/{sourceId}/Objects (ListCloudAppObjects)
  • /v1/WarehouseSources/{sourceId}/Preview (CreateWarehousePreview)
  • /v1/WarehouseSources/{sourceId}/Preview/{operationId} (FetchWarehousePreview)
  • /v1/DataSample/{operationId} (FetchDataSample)
  • /v1/ControlPlane/CloudAppSources/{sourceId} (FetchCloudAppSource, PatchCloudAppSource, DeleteCloudAppSource)
  • /v1/ControlPlane/CloudAppSources/{sourceId}/Datasets (ListCloudAppDatasets, CreateCloudAppDataset)
  • /v1/ControlPlane/CloudAppSources/{sourceId}/Datasets/{datasetId} (FetchCloudAppDataset, PatchCloudAppDataset, DeleteCloudAppDataset)
  • /v1/ControlPlane/WarehouseSources/{sourceId} (FetchWarehouseSource, PatchWarehouseSource, DeleteWarehouseSource)
  • /v1/ControlPlane/WarehouseSources/{sourceId}/Datasets (ListWarehouseDatasets, CreateWarehouseDataset)
  • ...and 6 more paths
  • Removed 16 path(s):
  • /v1/DataSyncs/{SyncId} (FetchDataSync)
  • /v1/CloudAppSources/{SourceId}/Objects (ListCloudAppObjects)
  • /v1/WarehouseSources/{SourceId}/Preview (CreateWarehousePreview)
  • /v1/WarehouseSources/{SourceId}/Preview/{OperationId} (FetchWarehousePreview)
  • /v1/DataSample/{OperationId} (FetchDataSample)
  • /v1/ControlPlane/CloudAppSources/{SourceId} (FetchCloudAppSource, PatchCloudAppSource, DeleteCloudAppSource)
  • /v1/ControlPlane/CloudAppSources/{SourceId}/Datasets (ListCloudAppDatasets, CreateCloudAppDataset)
  • /v1/ControlPlane/CloudAppSources/{SourceId}/Datasets/{DatasetId} (FetchCloudAppDataset, PatchCloudAppDataset, DeleteCloudAppDataset)
  • /v1/ControlPlane/WarehouseSources/{SourceId} (FetchWarehouseSource, PatchWarehouseSource, DeleteWarehouseSource)
  • /v1/ControlPlane/WarehouseSources/{SourceId}/Datasets (ListWarehouseDatasets, CreateWarehouseDataset)
  • ...and 6 more paths

Deletions

  • API Changes

  • 2026-06-23

  • Initial public Rest Proxy registration for the User Data Deletions API
  • (POST / GET /v1/UserDataDeletions, GET /v1/UserDataDeletions/{deletionId},
  • GET /v1/Operations/{operationId}).
  • A single request may mix identifier formats: E.164 phone numbers, email
  • addresses, and profile IDs.

Destinations

  • API Changes

  • 2026-08-07

  • Content updates:
  • Updated summary for ListDestinationSupportedEventTypes
  • 2026-08-07

  • Content updates:
  • Updated summary for ListDestinationSupportedEventTypes
  • 2026-08-07

  • Added 3 new path(s):
  • /v1/Catalog/DestinationSupportedEventTypes (ListDestinationSupportedEventTypes)
  • /v1/ControlPlane/Subscriptions/{subscriptionId}/EventTypes (ListSubscribedEvents, CreateSubscribedEvent)
  • /v1/ControlPlane/Subscriptions/{subscriptionId}/EventTypes/{eventType} (GetSubscribedEvent, UpdateSubscribedEvent, DeleteSubscribedEvent)
  • Removed 3 path(s):
  • /v1/ControlPlane/Subscriptions/{subscriptionId}/SubscribedEvents (ListSubscribedEvents, CreateSubscribedEvent)
  • /v1/ControlPlane/Subscriptions/{subscriptionId}/SubscribedEvents/{eventType} (GetSubscribedEvent, UpdateSubscribedEvent, DeleteSubscribedEvent)
  • /v1/Catalog/DestinationEventTypes (ListDestinationEventTypes)
  • 2026-08-04

  • Minor updates (formatting, metadata)
  • 2026-08-04

  • Minor updates (formatting, metadata)
  • 2026-08-04

  • Minor updates (formatting, metadata)
  • 2026-08-04

  • Minor updates (formatting, metadata)
  • 2026-08-04

  • Content updates:
  • Added properties to SubscriptionResponse: eventTypes
  • 2026-08-03

  • Content updates:
  • Added properties to DestinationType: documentationUrl, maturity, tier, categories
  • 2026-07-27

  • Minor updates (formatting, metadata)
  • 2026-07-23

  • Content updates:
  • meta is now a required property in the response of ListDestinations, ListSubscriptions, and ListSubscribedEvents
  • CreateSubscribedEvent request body schema consolidated onto SubscribedEventInput (previously SubscribedEventCreate, a duplicate schema)
  • Added response examples for ListDestinations, ListSubscriptions, and ListSubscribedEvents
  • 2026-07-23

  • Added 1 new path(s):
  • /v1/Catalog/DestinationEventTypes (ListDestinationEventTypes)
  • 2026-07-22

  • Content updates:
  • Added parameter(s) to ListDestinations: namePrefix
  • Updated description for UpdateSubscription
  • Added properties to SubscriptionUpdate: eventTypes
  • 2026-07-16

  • Initial release with 9 paths and 18 operations

Events

  • Add stage-ie1 realm support for EventTypes and Schemas endpoints (datataps-catalog)

Memory

  • 2026-08-10

  • Removed Events endpoints from the spec, as they were hidden, never implemented, and are not part of the public API
  • 2026-08-07

  • New functionality:
  • Added pageSize, pageToken, and orderBy query parameters to ListProfileImportsV2, plus a meta object in its response, to support pagination.
  • Content updates:
  • Updated the ListProfileImportsV2 description to document the new pagination behavior.
  • Corrected the example presigned upload URL on CreateProfilesImportV2 to match the real S3 bucket naming convention.
  • Corrected the meta.key example on ListProfileTraits's response (was profiles, now traits) to accurately describe which response field it points to.
  • 2026-08-07

  • Content updates:
  • Updated matchingRules description in IdentityResolutionSettingsCore to remove compound AND rule documentation
  • 2026-07-30

  • Content updates:
  • Increased the maximum value for the Twilio error code from 99999 to 999999
  • 2026-07-28

  • Content updates:
  • Updated the pageSize description on the pagination Meta schema to clarify it reflects the number of items actually returned, not the requested or default page size.
  • 2026-07-13

  • Content updates:
  • Renamed ListProfiles response schema references from ProfileID/ProfilesMeta to IdentityProfileID/IdentityProfilesMeta (new IdentityProfilesMeta schema added; ProfileID/ProfilesMeta retained for other operations).
  • 2026-07-08

  • Content updates:
  • Updated description for CreateDataMappingSuggestion
  • Updated description for FetchDataMappingSuggestion
  • 2026-07-06

  • Added 2 new path(s):
  • /v1/ControlPlane/Stores/{storeId}/DataMappings/Suggestions (ListDataMappingSuggestions, CreateDataMappingSuggestion)
  • /v1/ControlPlane/Stores/{storeId}/DataMappings/Suggestions/{suggestionId} (FetchDataMappingSuggestion)
  • 2026-06-26

  • Content updates:
  • Minor updates (formatting, metadata)
  • Updated x-twilio location parameter from instance to list for all endpoints that don't end with a /{param}
  • Updated description for UpdateProfileTraits
  • Updated summary for UpdateProfileTraits
  • Removed properties from MappingTraitItem: fieldName
  • Removed additionalProperties from allof schemas since it isn't supported and causes invalid lint errors on example blocks.
  • matruity ga and libraryVisibility public
  • 2026-06-24

  • Content updates:
  • Add ConversationID as an optional query parameter for ListObservations and ListConversationSummaries
  • 2026-05-01

  • Content updates:
  • Updated description & summary for UpdateProfileTraits
  • Updated description for FetchIdentityResolutionSettings
  • Removed properties from MappingTraitItem: fieldName
  • Updated patch Observations to not require occurredAt, content, or source
  • 2026-04-28

  • Content updates:
  • Updated description for UpdateProfileTraits
  • Updated summary for UpdateProfileTraits
  • Added properties to TraitDefinition: validationRule
  • Removed properties from MappingTraitItem: fieldName

Messaging_admin

  • Add Intelligent Alerts endpoints at /v1/Messaging/IntelligentAlertsEvents/*, routing to intelligent-alerts-api via messaging-monkey-backend. Account SID is a required query parameter (accountSid) on all three endpoints.
Kludex/uvicorn (uvicorn)

v0.54.0: Version 0.54.0

Compare Source

📨 Send metadata after the response body

uvicorn 0.54.0 adds response trailers and 103 Early Hints to its experimental HTTP/2 implementation through zttp.

uv add uvicorn==0.54.0 "zttp>=0.0.34"
  • Send HTTP/2 response trailers (#​3146). The ASGI http.response.trailers extension lets applications send metadata, such as checksums, after the response body. Clients must send TE: trailers to receive them. Multiple trailer messages are combined before completing the response.
  • HTTP/2 remains experimental and opt-in. Enable it with --http zttp --http2. Upgrade-based h2c and WebSockets over HTTP/2 remain unsupported.

💡 Hint at resources before the final response

  • Send 103 Early Hints over HTTP/2 (#​3137). Applications can use the ASGI http.response.early_hint extension to send resource hints before the final response. Each supplied link becomes a separate Link header.

Full changelog: 0.53.0...0.54.0

v0.53.0: Version 0.53.0

Compare Source

🌐 Opt-in HTTP/2 support

uvicorn 0.53.0 adds experimental HTTP/2 through zttp, alongside a new zuvloop integration and connection-handling improvements.

uv add uvicorn==0.53.0
  • Serve HTTP/1.1 and HTTP/2 with zttp (#​2982, #​3101). Install zttp, then enable HTTP/2 with --http zttp --http2. Uvicorn negotiates HTTP/2 over TLS with ALPN and supports cleartext prior knowledge.
  • HTTP/2 remains experimental. Upgrade-based h2c and WebSockets over HTTP/2 are not supported.

⚙️ More event loop choice

  • Run Uvicorn with zuvloop (#​3104). Install zuvloop separately and select it explicitly with --loop zuvloop on CPython 3.14 or newer.

🛡️ More reliable connections and proxies

  • Honor Connection: close token lists (#​3103). Uvicorn now parses comma-separated tokens case-insensitively across HTTP implementations.
  • Trust IPv6 loopback proxies by default (#​3119). The default FORWARDED_ALLOW_IPS value now includes ::1.
  • Keep upgraded WebSockets alive (#​3107). Uvicorn cancels the HTTP keep-alive timer when the connection becomes a WebSocket.

Full changelog: 0.52.4...0.53.0

v0.52.4: Version 0.52.4

Compare Source

Fixed
  • Remove duplicate Date headers from accepted WebSocket handshakes with websockets-sansio (#​3078)

Full Changelog: https://github.com/Kludex/uvicorn/compare/0.52.3...0.52.4

v0.52.3: Version 0.52.3

Compare Source

Changed
  • Update zttp to 0.0.24 and use its combined receive path, improving HTTP/1.1 request parsing performance (#​3067)

Full Changelog: https://github.com/Kludex/uvicorn/compare/0.52.2...0.52.3

v0.52.2: Version 0.52.2

Compare Source

Fixed
  • Update zttp to 0.0.22, fixing bodyless request receives and improving HTTP/1 request parsing performance (#​3063)

Full Changelog: https://github.com/Kludex/uvicorn/compare/0.52.1...0.52.2

v0.52.1: Version 0.52.1

Compare Source

Fixed
  • Complete the closing handshake on server-initiated WebSocket closes in the websockets-sansio and wsproto implementations, waiting for the client's close reply with a 10 second timeout instead of resetting the connection (#​3053)
  • Add missing write flow control to the websockets-sansio implementation, preventing data truncation on server-initiated closes with large in-flight payloads (#​3048)
  • Handle connection loss while a WebSocket write is waiting on backpressure (#​3050)
  • Remove duplicate Content-Type and Content-Length headers from WebSocket denial responses on the websockets-sansio implementation, and deliver non-UTF-8 denial bodies intact (#​3041)

Full Changelog: https://github.com/Kludex/uvicorn/compare/0.52.0...0.52.1

v0.52.0: Version 0.52.0

Compare Source

This release adds an experimental HTTP/1.1 implementation backed by zttp, a sans-IO HTTP parser I've been developing on the side: a core written in Zig, with bindings to Python. It has been running under a fuzzer for some weeks now, and has been through multiple rounds of security auditing.

It is still experimental, so don't put it in front of production traffic yet. Try it with --http zttp, and please send any feedback to the issue tracker.

Added
  • Add an experimental zttp HTTP/1.1 implementation, selectable with --http zttp (#​2979)
Fixed
  • Keep non-ASCII WebSocket request headers intact with websockets 17.0, which encodes them with ISO-8859-1 (#​3036)

Full Changelog: https://github.com/Kludex/uvicorn/compare/0.51.0...0.52.0


Configuration

📅 Schedule: (in timezone America/New_York)

  • Branch creation
    • "before 6am on monday"
  • Automerge
    • At any time (no schedule defined)

🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.

♻ Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

👻 Immortal: This PR will be recreated if closed unmerged. Get config help if that's undesired.


  • If you want to rebase/retry this PR, check this box

This PR has been generated by Mend Renovate.

This PR contains the following updates: | Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) | |---|---|---|---| | [alembic](https://github.com/sqlalchemy/alembic) ([changelog](https://alembic.sqlalchemy.org/en/latest/changelog.html)) | `==1.18.5` → `==1.20.1` | ![age](https://developer.mend.io/api/mc/badges/age/pypi/alembic/1.20.1?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/pypi/alembic/1.18.5/1.20.1?slim=true) | | [asyncpg](https://github.com/MagicStack/asyncpg) | `==0.31.0` → `==0.32.0` | ![age](https://developer.mend.io/api/mc/badges/age/pypi/asyncpg/0.32.0?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/pypi/asyncpg/0.31.0/0.32.0?slim=true) | | [authlib](https://github.com/authlib/authlib) | `==1.7.2` → `==1.9.5` | ![age](https://developer.mend.io/api/mc/badges/age/pypi/authlib/1.9.5?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/pypi/authlib/1.7.2/1.9.5?slim=true) | | [fastapi](https://github.com/fastapi/fastapi) ([changelog](https://fastapi.tiangolo.com/release-notes/)) | `==0.140.7` → `==0.162.2` | ![age](https://developer.mend.io/api/mc/badges/age/pypi/fastapi/0.162.2?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/pypi/fastapi/0.140.7/0.162.2?slim=true) | | [pydantic-settings](https://github.com/pydantic/pydantic-settings) ([changelog](https://github.com/pydantic/pydantic-settings/releases)) | `==2.14.2` → `==2.16.2` | ![age](https://developer.mend.io/api/mc/badges/age/pypi/pydantic-settings/2.16.2?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/pypi/pydantic-settings/2.14.2/2.16.2?slim=true) | | [pytest](https://github.com/pytest-dev/pytest) ([changelog](https://docs.pytest.org/en/stable/changelog.html)) | `==9.1.1` → `==9.2.0` | ![age](https://developer.mend.io/api/mc/badges/age/pypi/pytest/9.2.0?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/pypi/pytest/9.1.1/9.2.0?slim=true) | | [python-dotenv](https://github.com/theskumar/python-dotenv) | `==1.2.2` → `==1.2.4` | ![age](https://developer.mend.io/api/mc/badges/age/pypi/python-dotenv/1.2.4?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/pypi/python-dotenv/1.2.2/1.2.4?slim=true) | | [python-multipart](https://github.com/Kludex/python-multipart) ([changelog](https://github.com/Kludex/python-multipart/blob/master/CHANGELOG.md)) | `==0.0.32` → `==0.0.33` | ![age](https://developer.mend.io/api/mc/badges/age/pypi/python-multipart/0.0.33?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/pypi/python-multipart/0.0.32/0.0.33?slim=true) | | [ruff](https://docs.astral.sh/ruff) ([source](https://github.com/astral-sh/ruff), [changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md)) | `==0.16.10` → `==0.17.4` | ![age](https://developer.mend.io/api/mc/badges/age/pypi/ruff/0.17.4?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/pypi/ruff/0.16.10/0.17.4?slim=true) | | [sqlalchemy](https://github.com/sqlalchemy/sqlalchemy) ([changelog](https://docs.sqlalchemy.org/en/latest/changelog/)) | `==2.0.51` → `==2.1.8` | ![age](https://developer.mend.io/api/mc/badges/age/pypi/sqlalchemy/2.1.8?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/pypi/sqlalchemy/2.0.51/2.1.8?slim=true) | | [starlette](https://github.com/Kludex/starlette) ([changelog](https://starlette.dev/release-notes/)) | `==1.8.0` → `==1.10.0` | ![age](https://developer.mend.io/api/mc/badges/age/pypi/starlette/1.10.0?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/pypi/starlette/1.8.0/1.10.0?slim=true) | | [timezonefinder](https://github.com/jannikmi/timezonefinder) | `==8.2.5` → `==8.3.0` | ![age](https://developer.mend.io/api/mc/badges/age/pypi/timezonefinder/8.3.0?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/pypi/timezonefinder/8.2.5/8.3.0?slim=true) | | [twilio](https://github.com/twilio/twilio-python) | `==9.10.9` → `==9.13.0` | ![age](https://developer.mend.io/api/mc/badges/age/pypi/twilio/9.13.0?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/pypi/twilio/9.10.9/9.13.0?slim=true) | | [uvicorn](https://github.com/Kludex/uvicorn) ([changelog](https://uvicorn.dev/release-notes)) | `==0.51.0` → `==0.54.0` | ![age](https://developer.mend.io/api/mc/badges/age/pypi/uvicorn/0.54.0?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/pypi/uvicorn/0.51.0/0.54.0?slim=true) | --- ### Release Notes <details> <summary>MagicStack/asyncpg (asyncpg)</summary> ### [`v0.32.0`](https://github.com/MagicStack/asyncpg/releases/tag/v0.32.0) [Compare Source](https://github.com/MagicStack/asyncpg/compare/v0.31.0...v0.32.0) #### Improvements - Support Python 3.15 ([#&#8203;1367](https://github.com/MagicStack/asyncpg/issues/1367), [#&#8203;1378](https://github.com/MagicStack/asyncpg/issues/1378)) (by [@&#8203;elprans](https://github.com/elprans) in [`1b11846`](https://github.com/MagicStack/asyncpg/commit/1b118464) and [`58c0c59`](https://github.com/MagicStack/asyncpg/commit/58c0c595)) - Support PostgreSQL 19 ([#&#8203;1379](https://github.com/MagicStack/asyncpg/issues/1379)) (by [@&#8203;elprans](https://github.com/elprans) in [`8d2a5ae`](https://github.com/MagicStack/asyncpg/commit/8d2a5aed)) - Make pool `min_size` a maintained connection floor and add `init_size` to control the number of connections opened at startup ([#&#8203;1323](https://github.com/MagicStack/asyncpg/issues/1323)). Idle connections at or below `min_size` are retained, and closed connections are replaced in the background. `init_size` defaults to `min_size`. To preserve the previous behavior, where the pool could drain to zero, replace `min_size=N` with `init_size=N, min_size=0`. (by [@&#8203;shatilov-diman](https://github.com/shatilov-diman) in [`67a1cbc`](https://github.com/MagicStack/asyncpg/commit/67a1cbc5)) - Use `hashlib.pbkdf2_hmac()` for faster SCRAM password derivation ([#&#8203;1359](https://github.com/MagicStack/asyncpg/issues/1359)) (by [@&#8203;twelfthlabor](https://github.com/twelfthlabor) in [`00319a9`](https://github.com/MagicStack/asyncpg/commit/00319a9b)) - Use the statement cache for `copy_records_to_table()` introspection ([#&#8203;1360](https://github.com/MagicStack/asyncpg/issues/1360)) (by [@&#8203;matemax](https://github.com/matemax) in [`dd05865`](https://github.com/MagicStack/asyncpg/commit/dd058652)) #### Fixes - Clean up connections rejected by `target_session_attrs` immediately so an unresponsive rejected host cannot delay the selected connection, and cleanup tasks cannot outlive the event loop. Rejected connections are aborted without waiting for a graceful disconnect; servers may log "unexpected EOF on client connection" if the Terminate message is not delivered before the transport closes. - Fix a connection pool deadlock when releasing a connection after a protocol abort ([#&#8203;1324](https://github.com/MagicStack/asyncpg/issues/1324)) (by [@&#8203;pchaseh](https://github.com/pchaseh) in [`4a83cc2`](https://github.com/MagicStack/asyncpg/commit/4a83cc2f)) - Honor `Connection.close(timeout=...)` while waiting for a pending cancellation ([#&#8203;1361](https://github.com/MagicStack/asyncpg/issues/1361)) (by [@&#8203;gyanu2507](https://github.com/gyanu2507) in [`c06bcb4`](https://github.com/MagicStack/asyncpg/commit/c06bcb4d)) - Prevent stuck cancellation from blocking connection teardown or pool release by bounding cancellation with the command or release timeout ([#&#8203;1370](https://github.com/MagicStack/asyncpg/issues/1370)) (by [@&#8203;elprans](https://github.com/elprans) in [`4cf0220`](https://github.com/MagicStack/asyncpg/commit/4cf02203)) - Preserve the server error when the connection closes mid-operation ([#&#8203;1369](https://github.com/MagicStack/asyncpg/issues/1369)) (by [@&#8203;RitiGrover](https://github.com/RitiGrover) in [`6c8f1a7`](https://github.com/MagicStack/asyncpg/commit/6c8f1a7a)) - Fix COPY cleanup when a records generator raises, preserving the original exception and avoiding protocol desynchronization and stalled rollback ([#&#8203;1358](https://github.com/MagicStack/asyncpg/issues/1358)) (by [@&#8203;CodingCossack](https://github.com/CodingCossack) in [`fdc6bc8`](https://github.com/MagicStack/asyncpg/commit/fdc6bc8f)) - Reparse unnamed statements before cursor binding when the statement cache is disabled ([#&#8203;1364](https://github.com/MagicStack/asyncpg/issues/1364)) (by [@&#8203;elprans](https://github.com/elprans) in [`302ba49`](https://github.com/MagicStack/asyncpg/commit/302ba496)) - Allow cursors in transactions started outside `Connection.transaction()`, such as with an explicit `BEGIN` ([#&#8203;1350](https://github.com/MagicStack/asyncpg/issues/1350)) (by [@&#8203;aryansk](https://github.com/aryansk) in [`25aaaf5`](https://github.com/MagicStack/asyncpg/commit/25aaaf54)) - Remove the query logger when the `query_logger()` block raises ([#&#8203;1373](https://github.com/MagicStack/asyncpg/issues/1373)) (by [@&#8203;kratos0718](https://github.com/kratos0718) in [`6a7fbd3`](https://github.com/MagicStack/asyncpg/commit/6a7fbd3e)) - Fix a segfault in `Record.get()` with an invalid number of positional arguments ([#&#8203;1333](https://github.com/MagicStack/asyncpg/issues/1333)) (by [@&#8203;apoorvdarshan](https://github.com/apoorvdarshan) in [`40a3832`](https://github.com/MagicStack/asyncpg/commit/40a38320)) - Align SSL startup retries with libpq and improve SSL rejection diagnostics ([#&#8203;1366](https://github.com/MagicStack/asyncpg/issues/1366)). Retry alternative transports only before authentication succeeds. Direct TLS now requires `sslmode=require`, `verify-ca`, or `verify-full`, or an explicit `SSLContext`. (by [@&#8203;elprans](https://github.com/elprans) in [`78752c9`](https://github.com/MagicStack/asyncpg/commit/78752c9c)) - Preserve password errors during SSL fallback when the fallback fails with a less specific authorization error ([#&#8203;1331](https://github.com/MagicStack/asyncpg/issues/1331)) (by [@&#8203;Mauricio0129](https://github.com/Mauricio0129) in [`2d97947`](https://github.com/MagicStack/asyncpg/commit/2d979472)) - Handle cleartext password authentication when no password is supplied without raising an `AttributeError` ([#&#8203;1351](https://github.com/MagicStack/asyncpg/issues/1351)) (by [@&#8203;aryansk](https://github.com/aryansk) in [`6be5915`](https://github.com/MagicStack/asyncpg/commit/6be59154)) - Set the `postgresql` ALPN protocol on SSL contexts created by asyncpg so direct TLS connections work with PostgreSQL 17 and later ([#&#8203;1372](https://github.com/MagicStack/asyncpg/issues/1372)). User-provided contexts must set this protocol for direct TLS connections. (by [@&#8203;DurandA](https://github.com/DurandA) in [`b21325d`](https://github.com/MagicStack/asyncpg/commit/b21325d2)) - Link explicitly against `libm` on non-Windows platforms to fix undefined math symbol errors when loading the extensions ([#&#8203;1305](https://github.com/MagicStack/asyncpg/issues/1305)) (by [@&#8203;veeceey](https://github.com/veeceey) in [`db8ecc2`](https://github.com/MagicStack/asyncpg/commit/db8ecc2a)) - Fix builds on FreeBSD 15 by linking against `libstdthreads` ([#&#8203;1368](https://github.com/MagicStack/asyncpg/issues/1368)) (by [@&#8203;elprans](https://github.com/elprans) in [`87bcaf9`](https://github.com/MagicStack/asyncpg/commit/87bcaf97)) #### Other - Replace `pkg_resources` with `packaging` in `setup.py` ([#&#8203;1362](https://github.com/MagicStack/asyncpg/issues/1362)) (by [@&#8203;elprans](https://github.com/elprans) in [`6695db7`](https://github.com/MagicStack/asyncpg/commit/6695db76)) - Build Linux and macOS ARM64 wheels on native runners and add Windows ARM64 wheel builds ([#&#8203;1308](https://github.com/MagicStack/asyncpg/issues/1308)) (by [@&#8203;ddelange](https://github.com/ddelange) in [`1e8cc1c`](https://github.com/MagicStack/asyncpg/commit/1e8cc1c4)) - Add manual and PR-label-triggered dry runs to the release workflow ([#&#8203;1374](https://github.com/MagicStack/asyncpg/issues/1374)) (by [@&#8203;elprans](https://github.com/elprans) in [`1bd643e`](https://github.com/MagicStack/asyncpg/commit/1bd643e1)) - Clarify how `execute()` uses prepared statements and how to confirm an `INSERT` in the documentation ([#&#8203;1336](https://github.com/MagicStack/asyncpg/issues/1336)) (by [@&#8203;pctablet505](https://github.com/pctablet505) in [`cdf816c`](https://github.com/MagicStack/asyncpg/commit/cdf816c4)) - Fix typos in comments and docstrings ([#&#8203;1332](https://github.com/MagicStack/asyncpg/issues/1332)) (by [@&#8203;maxtaran2010](https://github.com/maxtaran2010) in [`bc3e246`](https://github.com/MagicStack/asyncpg/commit/bc3e2462)) </details> <details> <summary>authlib/authlib (authlib)</summary> ### [`v1.9.5`](https://github.com/authlib/authlib/releases/tag/v1.9.5) [Compare Source](https://github.com/authlib/authlib/compare/v1.9.4...v1.9.5) Changelog: <https://docs.authlib.org/en/stable/upgrades/changelog.html#changelog-1-9-5> **Full Changelog**: <https://github.com/authlib/authlib/compare/v1.9.4...v1.9.5> ### [`v1.9.4`](https://github.com/authlib/authlib/releases/tag/v1.9.4) [Compare Source](https://github.com/authlib/authlib/compare/v1.9.3...v1.9.4) Changelog: <https://docs.authlib.org/en/stable/upgrades/changelog.html#changelog-1-9-4> **Full Changelog**: <https://github.com/authlib/authlib/compare/v1.9.3...v1.9.4> ### [`v1.9.3`](https://github.com/authlib/authlib/releases/tag/v1.9.3) [Compare Source](https://github.com/authlib/authlib/compare/v1.9.2...v1.9.3) Changelog: <https://docs.authlib.org/en/stable/upgrades/changelog.html#changelog-1-9-3> **Full Changelog**: <https://github.com/authlib/authlib/compare/v1.9.2...v1.9.3> ### [`v1.9.2`](https://github.com/authlib/authlib/releases/tag/v1.9.2) [Compare Source](https://github.com/authlib/authlib/compare/v1.9.1...v1.9.2) Changelog: <https://docs.authlib.org/en/stable/upgrades/changelog.html#changelog-1-9-2> **Full Changelog**: <https://github.com/authlib/authlib/compare/v1.9.1...v1.9.2> ### [`v1.9.1`](https://github.com/authlib/authlib/releases/tag/v1.9.1) [Compare Source](https://github.com/authlib/authlib/compare/v1.9.0...v1.9.1) Changelog: <https://docs.authlib.org/en/stable/upgrades/changelog.html#changelog-1-9-1> #### What's Changed - Use scriv to handle the changelog by [@&#8203;azmeuk](https://github.com/azmeuk) in [#&#8203;954](https://github.com/authlib/authlib/pull/954) **Full Changelog**: <https://github.com/authlib/authlib/compare/v1.9.0...v1.9.1> ### [`v1.9.0`](https://github.com/authlib/authlib/releases/tag/v1.9.0) [Compare Source](https://github.com/authlib/authlib/compare/v1.8.0...v1.9.0) #### What's Changed - feat: add Identity Assertion JWT Authorization Grant (ID-JAG) by [@&#8203;BinoyOza-okta](https://github.com/BinoyOza-okta) in [#&#8203;898](https://github.com/authlib/authlib/pull/898) - Fix empty signatures validation in JWS JSON deserialization by [@&#8203;loporto](https://github.com/loporto) in [#&#8203;938](https://github.com/authlib/authlib/pull/938) - fix(jose): reject boolean values for NumericDate claims by [@&#8203;cpruijsen](https://github.com/cpruijsen) in [#&#8203;942](https://github.com/authlib/authlib/pull/942) - fix(client): avoid duplicated OAuth 1.0 parameters in signed requests by [@&#8203;cpruijsen](https://github.com/cpruijsen) in [#&#8203;943](https://github.com/authlib/authlib/pull/943) - OAuth2 token fetch crashes with JSONDecodeError instead of a catchable error on rate-limit responses by [@&#8203;juneja-varun](https://github.com/juneja-varun) in [#&#8203;929](https://github.com/authlib/authlib/pull/929) - docs: add i18n wrappers in conf.py and templates by [@&#8203;hwhsu1231](https://github.com/hwhsu1231) in [#&#8203;901](https://github.com/authlib/authlib/pull/901) - fix(oauth): enforce JOSE key, scope, and audience validation by [@&#8203;lepture](https://github.com/lepture) in [#&#8203;945](https://github.com/authlib/authlib/pull/945) - AsyncOpenIDMixin.parse\_id\_token: return None when id\_token is absent, matching the sync client by [@&#8203;ckarnell](https://github.com/ckarnell) in [#&#8203;924](https://github.com/authlib/authlib/pull/924) - fix(oauth): enforce nonce and JAR request validation by [@&#8203;lepture](https://github.com/lepture) in [#&#8203;949](https://github.com/authlib/authlib/pull/949) - fix(oauth): require client authentication for ID-JAG grants by [@&#8203;lepture](https://github.com/lepture) in [#&#8203;955](https://github.com/authlib/authlib/pull/955) #### New Contributors - [@&#8203;BinoyOza-okta](https://github.com/BinoyOza-okta) made their first contribution in [#&#8203;898](https://github.com/authlib/authlib/pull/898) - [@&#8203;loporto](https://github.com/loporto) made their first contribution in [#&#8203;938](https://github.com/authlib/authlib/pull/938) - [@&#8203;cpruijsen](https://github.com/cpruijsen) made their first contribution in [#&#8203;942](https://github.com/authlib/authlib/pull/942) - [@&#8203;juneja-varun](https://github.com/juneja-varun) made their first contribution in [#&#8203;929](https://github.com/authlib/authlib/pull/929) - [@&#8203;hwhsu1231](https://github.com/hwhsu1231) made their first contribution in [#&#8203;901](https://github.com/authlib/authlib/pull/901) - [@&#8203;ckarnell](https://github.com/ckarnell) made their first contribution in [#&#8203;924](https://github.com/authlib/authlib/pull/924) **Full Changelog**: <https://github.com/authlib/authlib/compare/v1.8.0...v1.9.0> ### [`v1.8.0`](https://github.com/authlib/authlib/releases/tag/v1.8.0) [Compare Source](https://github.com/authlib/authlib/compare/v1.7.2...v1.8.0) #### What's Changed - Prefer `id_token_signed_response_alg` client metadata to guess algs by [@&#8203;azmeuk](https://github.com/azmeuk) in [#&#8203;888](https://github.com/authlib/authlib/pull/888) - fix: Catch InvalidKeyIdError in RFC 9068 JWTBearerTokenValidator by [@&#8203;liudonggalaxy](https://github.com/liudonggalaxy) in [#&#8203;891](https://github.com/authlib/authlib/pull/891) - fix: make leeway configurable in JWTBearerTokenValidator by [@&#8203;mondi04](https://github.com/mondi04) in [#&#8203;903](https://github.com/authlib/authlib/pull/903) - feat: add default jti claim to sign\_jwt\_bearer\_assertion by [@&#8203;liudonggalaxy](https://github.com/liudonggalaxy) in [#&#8203;897](https://github.com/authlib/authlib/pull/897) - fix(oauth): cast sub claim to string in JWTBearerTokenGenerator by [@&#8203;levinKaus](https://github.com/levinKaus) in [#&#8203;911](https://github.com/authlib/authlib/pull/911) - Declare lower bounds for dependencies by [@&#8203;azmeuk](https://github.com/azmeuk) in [#&#8203;912](https://github.com/authlib/authlib/pull/912) - feat(client): use httpx2 instead of httpx by [@&#8203;levinKaus](https://github.com/levinKaus) in [#&#8203;909](https://github.com/authlib/authlib/pull/909) - Fix RFC7523 malformed claims handling by [@&#8203;azmeuk](https://github.com/azmeuk) in [#&#8203;916](https://github.com/authlib/authlib/pull/916) - Fix httpx oauth1 binary form data by [@&#8203;shc261392](https://github.com/shc261392) in [#&#8203;779](https://github.com/authlib/authlib/pull/779) - fix(starlette\_client): remove default= keyword from config.get calls by [@&#8203;aliaksei-protchanka](https://github.com/aliaksei-protchanka) in [#&#8203;770](https://github.com/authlib/authlib/pull/770) - Added client\_id parameter to AssertionClient by [@&#8203;vilmar-hillow](https://github.com/vilmar-hillow) in [#&#8203;476](https://github.com/authlib/authlib/pull/476) - fix(oauth): save device credential with authenticated client id by [@&#8203;arpitjain099](https://github.com/arpitjain099) in [#&#8203;908](https://github.com/authlib/authlib/pull/908) - fix(oauth1): correct protocol name in InsecureTransportError description by [@&#8203;RavSinghChandan](https://github.com/RavSinghChandan) in [#&#8203;919](https://github.com/authlib/authlib/pull/919) - fix(client): client can be flexible with jwt's header by [@&#8203;lepture](https://github.com/lepture) in [#&#8203;922](https://github.com/authlib/authlib/pull/922) - fix(oidc): omit claims when the value is None by [@&#8203;lepture](https://github.com/lepture) in [#&#8203;923](https://github.com/authlib/authlib/pull/923) #### New Contributors - [@&#8203;mondi04](https://github.com/mondi04) made their first contribution in [#&#8203;903](https://github.com/authlib/authlib/pull/903) - [@&#8203;levinKaus](https://github.com/levinKaus) made their first contribution in [#&#8203;911](https://github.com/authlib/authlib/pull/911) - [@&#8203;aliaksei-protchanka](https://github.com/aliaksei-protchanka) made their first contribution in [#&#8203;770](https://github.com/authlib/authlib/pull/770) - [@&#8203;vilmar-hillow](https://github.com/vilmar-hillow) made their first contribution in [#&#8203;476](https://github.com/authlib/authlib/pull/476) - [@&#8203;arpitjain099](https://github.com/arpitjain099) made their first contribution in [#&#8203;908](https://github.com/authlib/authlib/pull/908) - [@&#8203;RavSinghChandan](https://github.com/RavSinghChandan) made their first contribution in [#&#8203;919](https://github.com/authlib/authlib/pull/919) **Full Changelog**: <https://github.com/authlib/authlib/compare/v1.7.2...v1.8.0> </details> <details> <summary>fastapi/fastapi (fastapi)</summary> ### [`v0.162.2`](https://github.com/fastapi/fastapi/releases/tag/0.162.2) [Compare Source](https://github.com/fastapi/fastapi/compare/0.162.1...0.162.2) > FastAPI includes an official skill that helps coding agents use new features and recommended patterns for your installed version. Install it with `uvx library-skills` in your project. See [Develop with AI](https://fastapi.tiangolo.com/ai-development/). ##### Docs - 📝 Add FastAPI Cloud guidance to the FastAPI skill. PR [#&#8203;16697](https://github.com/fastapi/fastapi/pull/16697) by [@&#8203;tiangolo](https://github.com/tiangolo). - 📝 Add guidance for developing FastAPI apps with AI. PR [#&#8203;16695](https://github.com/fastapi/fastapi/pull/16695) by [@&#8203;tiangolo](https://github.com/tiangolo). ##### Internal - 🔧 Add an agent skills note to GitHub releases. PR [#&#8203;16696](https://github.com/fastapi/fastapi/pull/16696) by [@&#8203;tiangolo](https://github.com/tiangolo). ### [`v0.162.1`](https://github.com/fastapi/fastapi/releases/tag/0.162.1) [Compare Source](https://github.com/fastapi/fastapi/compare/0.162.0...0.162.1) ##### Docs - 📝 Add parameter model guidance to the FastAPI skill. PR [#&#8203;16693](https://github.com/fastapi/fastapi/pull/16693) by [@&#8203;tiangolo](https://github.com/tiangolo). ##### Translations - 🌐 Update translations for zh-hant (update-outdated). PR [#&#8203;16654](https://github.com/fastapi/fastapi/pull/16654) by [@&#8203;pr-submit\[bot\]](https://github.com/apps/pr-submit). - 🌐 Update translations for uk (update-outdated). PR [#&#8203;16655](https://github.com/fastapi/fastapi/pull/16655) by [@&#8203;pr-submit\[bot\]](https://github.com/apps/pr-submit). - 🌐 Update translations for de (update-outdated). PR [#&#8203;16652](https://github.com/fastapi/fastapi/pull/16652) by [@&#8203;pr-submit\[bot\]](https://github.com/apps/pr-submit). - 🌐 Update translations for pt (update-outdated). PR [#&#8203;16653](https://github.com/fastapi/fastapi/pull/16653) by [@&#8203;pr-submit\[bot\]](https://github.com/apps/pr-submit). - 🌐 Update translations for fr (update-outdated). PR [#&#8203;16649](https://github.com/fastapi/fastapi/pull/16649) by [@&#8203;pr-submit\[bot\]](https://github.com/apps/pr-submit). - 🌐 Update translations for tr (update-outdated). PR [#&#8203;16651](https://github.com/fastapi/fastapi/pull/16651) by [@&#8203;pr-submit\[bot\]](https://github.com/apps/pr-submit). - 🌐 Update translations for ja (update-outdated). PR [#&#8203;16648](https://github.com/fastapi/fastapi/pull/16648) by [@&#8203;pr-submit\[bot\]](https://github.com/apps/pr-submit). - 🌐 Update translations for zh (update-outdated). PR [#&#8203;16644](https://github.com/fastapi/fastapi/pull/16644) by [@&#8203;pr-submit\[bot\]](https://github.com/apps/pr-submit). - 🌐 Update translations for hi (update-outdated). PR [#&#8203;16647](https://github.com/fastapi/fastapi/pull/16647) by [@&#8203;pr-submit\[bot\]](https://github.com/apps/pr-submit). - 🌐 Update translations for es (update-outdated). PR [#&#8203;16645](https://github.com/fastapi/fastapi/pull/16645) by [@&#8203;pr-submit\[bot\]](https://github.com/apps/pr-submit). - 🌐 Update translations for ru (update-outdated). PR [#&#8203;16650](https://github.com/fastapi/fastapi/pull/16650) by [@&#8203;pr-submit\[bot\]](https://github.com/apps/pr-submit). ##### Internal - ⬆️ Bump pillow to 13.0.0 and dnspython to 2.9.2. PR [#&#8203;16685](https://github.com/fastapi/fastapi/pull/16685) by [@&#8203;YuriiMotov](https://github.com/YuriiMotov). - 📝 Update FastAPI Cloud docs banner for general availability. PR [#&#8203;16684](https://github.com/fastapi/fastapi/pull/16684) by [@&#8203;tiangolo](https://github.com/tiangolo). - 🔧 Update sponsors: add Encore. PR [#&#8203;16683](https://github.com/fastapi/fastapi/pull/16683) by [@&#8203;tiangolo](https://github.com/tiangolo). - 🔥 Remove conference rail component and related styles. PR [#&#8203;16679](https://github.com/fastapi/fastapi/pull/16679) by [@&#8203;alejsdev](https://github.com/alejsdev). - 👥 Update FastAPI People - Sponsors. PR [#&#8203;16656](https://github.com/fastapi/fastapi/pull/16656) by [@&#8203;pr-submit\[bot\]](https://github.com/apps/pr-submit). - 👥 Update FastAPI GitHub topic repositories. PR [#&#8203;16660](https://github.com/fastapi/fastapi/pull/16660) by [@&#8203;pr-submit\[bot\]](https://github.com/apps/pr-submit). - ⬆ Bump the github-actions group with 7 updates. PR [#&#8203;16658](https://github.com/fastapi/fastapi/pull/16658) by [@&#8203;dependabot\[bot\]](https://github.com/apps/dependabot). - ⬆ Bump pre-commit hooks. PR [#&#8203;16659](https://github.com/fastapi/fastapi/pull/16659) by [@&#8203;pr-submit\[bot\]](https://github.com/apps/pr-submit). - ⬆ Bump authlib from 1.7.2 to 1.9.1. PR [#&#8203;16637](https://github.com/fastapi/fastapi/pull/16637) by [@&#8203;dependabot\[bot\]](https://github.com/apps/dependabot). - 🔧 Update sponsors: add MicroAuth. PR [#&#8203;16641](https://github.com/fastapi/fastapi/pull/16641) by [@&#8203;tiangolo](https://github.com/tiangolo). - 🔧 Pin pytest below 9.2 for pytest-xdist compatibility. PR [#&#8203;16642](https://github.com/fastapi/fastapi/pull/16642) by [@&#8203;tiangolo](https://github.com/tiangolo). - ⬆ Bump graphql-core from 3.2.7 to 3.3.1. PR [#&#8203;16613](https://github.com/fastapi/fastapi/pull/16613) by [@&#8203;dependabot\[bot\]](https://github.com/apps/dependabot). - ⬆ Bump black from 26.5.1 to 26.10.1. PR [#&#8203;16611](https://github.com/fastapi/fastapi/pull/16611) by [@&#8203;dependabot\[bot\]](https://github.com/apps/dependabot). - ⬆ Bump gitpython from 3.1.62 to 3.2.1. PR [#&#8203;16612](https://github.com/fastapi/fastapi/pull/16612) by [@&#8203;dependabot\[bot\]](https://github.com/apps/dependabot). - ⬆ Bump opentelemetry-api from 1.44.0 to 1.45.1. PR [#&#8203;16610](https://github.com/fastapi/fastapi/pull/16610) by [@&#8203;dependabot\[bot\]](https://github.com/apps/dependabot). ### [`v0.162.0`](https://github.com/fastapi/fastapi/releases/tag/0.162.0) [Compare Source](https://github.com/fastapi/fastapi/compare/0.161.1...0.162.0) Omitted `bool` and `bool | None` form fields now use their declared defaults or produce missing-field errors, consistent with other fields and Pydantic behavior. FastAPI no longer infers `False` for omitted booleans. This applies to individual form parameters, form models, and unions of form models. Omitted boolean model fields are excluded from `model_dump(exclude_unset=True)`, and their defaults no longer count as submitted fields during union selection. Default factories and `validate_default` follow the usual rules. For HTML checkboxes, declare a boolean with a default of `False`. See [Boolean Form Fields](https://fastapi.tiangolo.com/tutorial/request-forms/#boolean-form-fields). ##### Breaking Changes - 🐛 Restore default handling for omitted boolean form fields. PR [#&#8203;16605](https://github.com/fastapi/fastapi/pull/16605) by [@&#8203;tiangolo](https://github.com/tiangolo). ### [`v0.161.1`](https://github.com/fastapi/fastapi/releases/tag/0.161.1) [Compare Source](https://github.com/fastapi/fastapi/compare/0.161.0...0.161.1) ##### Fixes - 🐛 Fix OpenAPI schemas for standalone nullable form unions. PR [#&#8203;16598](https://github.com/fastapi/fastapi/pull/16598) by [@&#8203;tiangolo](https://github.com/tiangolo). ### [`v0.161.0`](https://github.com/fastapi/fastapi/releases/tag/0.161.0) [Compare Source](https://github.com/fastapi/fastapi/compare/0.160.0...0.161.0) ##### Features - ✨ Add support for combining unions of form models. PR [#&#8203;16596](https://github.com/fastapi/fastapi/pull/16596) by [@&#8203;tiangolo](https://github.com/tiangolo). ### [`v0.160.0`](https://github.com/fastapi/fastapi/releases/tag/0.160.0) [Compare Source](https://github.com/fastapi/fastapi/compare/0.159.1...0.160.0) Query, header, cookie, and form parameter models now apply their `extra` configuration to all submitted fields in the same parameter location, consistent with Pydantic behavior. This includes fields declared in other models, individual parameters, or dependencies, which were previously excluded. With `extra="forbid"`, fields outside the model are rejected even if another parameter declares them. With `extra="allow"`, those fields are included as model extras. With the default `extra="ignore"`, they are ignored. ##### Breaking Changes - 🐛 Apply each parameter model's `extra` configuration to sibling fields. PR [#&#8203;16594](https://github.com/fastapi/fastapi/pull/16594) by [@&#8203;tiangolo](https://github.com/tiangolo). ##### Internal - ⬆ Bump certifi from 2026.1.4 to 2026.10.19. PR [#&#8203;16571](https://github.com/fastapi/fastapi/pull/16571) by [@&#8203;dependabot\[bot\]](https://github.com/apps/dependabot). ### [`v0.159.1`](https://github.com/fastapi/fastapi/releases/tag/0.159.1) [Compare Source](https://github.com/fastapi/fastapi/compare/0.159.0...0.159.1) ##### Features - ✨ Add support for optional unions of form models. PR [#&#8203;16586](https://github.com/fastapi/fastapi/pull/16586) by [@&#8203;tiangolo](https://github.com/tiangolo). ### [`v0.159.0`](https://github.com/fastapi/fastapi/releases/tag/0.159.0) [Compare Source](https://github.com/fastapi/fastapi/compare/0.158.2...0.159.0) ##### Features - ✨ Add support for optional query, header, and cookie parameter models. PR [#&#8203;16584](https://github.com/fastapi/fastapi/pull/16584) by [@&#8203;tiangolo](https://github.com/tiangolo). ### [`v0.158.2`](https://github.com/fastapi/fastapi/releases/tag/0.158.2) [Compare Source](https://github.com/fastapi/fastapi/compare/0.158.1...0.158.2) ##### Features - ✨ Add support for optional form models. PR [#&#8203;16582](https://github.com/fastapi/fastapi/pull/16582) by [@&#8203;tiangolo](https://github.com/tiangolo). ### [`v0.158.1`](https://github.com/fastapi/fastapi/releases/tag/0.158.1) [Compare Source](https://github.com/fastapi/fastapi/compare/0.158.0...0.158.1) ##### Fixes - 🐛 Preserve form media types in OpenAPI. PR [#&#8203;16579](https://github.com/fastapi/fastapi/pull/16579) by [@&#8203;tiangolo](https://github.com/tiangolo). ### [`v0.158.0`](https://github.com/fastapi/fastapi/releases/tag/0.158.0) [Compare Source](https://github.com/fastapi/fastapi/compare/0.157.0...0.158.0) ##### Features - ✨ Add support for combining form models. PR [#&#8203;16577](https://github.com/fastapi/fastapi/pull/16577) by [@&#8203;tiangolo](https://github.com/tiangolo). ### [`v0.157.0`](https://github.com/fastapi/fastapi/releases/tag/0.157.0) [Compare Source](https://github.com/fastapi/fastapi/compare/0.156.8...0.157.0) ##### Features - ✨ Add support for combining query, header, and cookie parameter models. PR [#&#8203;16573](https://github.com/fastapi/fastapi/pull/16573) by [@&#8203;tiangolo](https://github.com/tiangolo). ##### Docs - 📝 Clarify boolean query parameter parsing. PR [#&#8203;16569](https://github.com/fastapi/fastapi/pull/16569) by [@&#8203;tiangolo](https://github.com/tiangolo). - 📝 Clarify nullable query parameters and path parameter defaults. PR [#&#8203;16568](https://github.com/fastapi/fastapi/pull/16568) by [@&#8203;tiangolo](https://github.com/tiangolo). ##### Internal - 👷 Remove translation notifications and approval labeling. PR [#&#8203;16570](https://github.com/fastapi/fastapi/pull/16570) by [@&#8203;tiangolo](https://github.com/tiangolo). ### [`v0.156.8`](https://github.com/fastapi/fastapi/releases/tag/0.156.8) [Compare Source](https://github.com/fastapi/fastapi/compare/0.156.7...0.156.8) ##### Fixes - 🐛 Preserve uploaded file positions when converting to `bytes`. PR [#&#8203;16566](https://github.com/fastapi/fastapi/pull/16566) by [@&#8203;tiangolo](https://github.com/tiangolo). ### [`v0.156.7`](https://github.com/fastapi/fastapi/releases/tag/0.156.7) [Compare Source](https://github.com/fastapi/fastapi/compare/0.156.6...0.156.7) ##### Fixes - 🐛 Fix validation error locations for form and file `AliasChoices`. PR [#&#8203;16564](https://github.com/fastapi/fastapi/pull/16564) by [@&#8203;tiangolo](https://github.com/tiangolo). ### [`v0.156.6`](https://github.com/fastapi/fastapi/releases/tag/0.156.6) [Compare Source](https://github.com/fastapi/fastapi/compare/0.156.5...0.156.6) ##### Fixes - 🐛 Respect model alias settings for query, header, and cookie parameters. PR [#&#8203;16562](https://github.com/fastapi/fastapi/pull/16562) by [@&#8203;tiangolo](https://github.com/tiangolo). ### [`v0.156.5`](https://github.com/fastapi/fastapi/releases/tag/0.156.5) [Compare Source](https://github.com/fastapi/fastapi/compare/0.156.4...0.156.5) ##### Fixes - 🐛 Fix `AliasChoices` for path parameters. PR [#&#8203;16560](https://github.com/fastapi/fastapi/pull/16560) by [@&#8203;tiangolo](https://github.com/tiangolo). ### [`v0.156.4`](https://github.com/fastapi/fastapi/releases/tag/0.156.4) [Compare Source](https://github.com/fastapi/fastapi/compare/0.156.3...0.156.4) ##### Fixes - 🐛 Fix `AliasChoices` for named JSON body parameters. PR [#&#8203;16559](https://github.com/fastapi/fastapi/pull/16559) by [@&#8203;tiangolo](https://github.com/tiangolo). - 🐛 Fix `AliasChoices` extraction for form models. PR [#&#8203;16557](https://github.com/fastapi/fastapi/pull/16557) by [@&#8203;tiangolo](https://github.com/tiangolo). ### [`v0.156.3`](https://github.com/fastapi/fastapi/releases/tag/0.156.3) [Compare Source](https://github.com/fastapi/fastapi/compare/0.156.2...0.156.3) ##### Fixes - 🐛 Fix `AliasChoices` for query parameters, headers, and cookies. PR [#&#8203;16555](https://github.com/fastapi/fastapi/pull/16555) by [@&#8203;tiangolo](https://github.com/tiangolo). ### [`v0.156.2`](https://github.com/fastapi/fastapi/releases/tag/0.156.2) [Compare Source](https://github.com/fastapi/fastapi/compare/0.156.1...0.156.2) ##### Fixes - 🐛 Preserve Pydantic field metadata in inferred request parameters. PR [#&#8203;16553](https://github.com/fastapi/fastapi/pull/16553) by [@&#8203;tiangolo](https://github.com/tiangolo). ### [`v0.156.1`](https://github.com/fastapi/fastapi/releases/tag/0.156.1) [Compare Source](https://github.com/fastapi/fastapi/compare/0.156.0...0.156.1) ##### Fixes - 🐛 Preserve Pydantic field metadata when request options are omitted. PR [#&#8203;16549](https://github.com/fastapi/fastapi/pull/16549) by [@&#8203;tiangolo](https://github.com/tiangolo). ### [`v0.156.0`](https://github.com/fastapi/fastapi/releases/tag/0.156.0) [Compare Source](https://github.com/fastapi/fastapi/compare/0.155.0...0.156.0) ##### Fixes - 🐛 Preserve Pydantic `Field()` attributes in request parameters. PR [#&#8203;16547](https://github.com/fastapi/fastapi/pull/16547) by [@&#8203;tiangolo](https://github.com/tiangolo). ### [`v0.155.0`](https://github.com/fastapi/fastapi/releases/tag/0.155.0) [Compare Source](https://github.com/fastapi/fastapi/compare/0.154.0...0.155.0) The deprecated `**extra` keyword arguments have been removed from `Path`, `Query`, `Header`, `Cookie`, `Body`, `Form`, and `File`. Unknown keyword arguments now raise `TypeError`. For additional JSON Schema properties, replace, for example, `Query(custom="value")` with `Query(json_schema_extra={"custom": "value"})`. ##### Breaking Changes - 🔥 Remove deprecated `**extra` from request parameters. PR [#&#8203;16545](https://github.com/fastapi/fastapi/pull/16545) by [@&#8203;tiangolo](https://github.com/tiangolo). ### [`v0.154.0`](https://github.com/fastapi/fastapi/releases/tag/0.154.0) [Compare Source](https://github.com/fastapi/fastapi/compare/0.153.0...0.154.0) ##### Features - ✨ Add Pydantic validation options to request parameters. PR [#&#8203;16542](https://github.com/fastapi/fastapi/pull/16542) by [@&#8203;tiangolo](https://github.com/tiangolo). ### [`v0.153.0`](https://github.com/fastapi/fastapi/releases/tag/0.153.0) [Compare Source](https://github.com/fastapi/fastapi/compare/0.152.0...0.153.0) Unions of form models now apply the same browser form handling as individual models. Empty scalar fields use defaults or produce missing-field errors, empty list items are preserved, omitted boolean fields become `False`, and unselected files are treated as missing. JSON request bodies are unchanged. ##### Fixes - 🐛 Apply browser form handling to unions of Pydantic models. PR [#&#8203;16540](https://github.com/fastapi/fastapi/pull/16540) by [@&#8203;tiangolo](https://github.com/tiangolo). ### [`v0.152.0`](https://github.com/fastapi/fastapi/releases/tag/0.152.0) [Compare Source](https://github.com/fastapi/fastapi/compare/0.151.0...0.152.0) Validation errors for header parameter models now report the HTTP header name, such as `int-val`, instead of the Python field name, `int_val`. Explicit aliases, `Header(convert_underscores=False)`, and Pydantic models with `loc_by_alias=False` keep their existing behavior. ##### Fixes - 🐛 Fix header model validation errors to report HTTP header names. PR [#&#8203;16538](https://github.com/fastapi/fastapi/pull/16538) by [@&#8203;tiangolo](https://github.com/tiangolo). ### [`v0.151.0`](https://github.com/fastapi/fastapi/releases/tag/0.151.0) [Compare Source](https://github.com/fastapi/fastapi/compare/0.150.0...0.151.0) JSON request bodies now distinguish an explicit `null` from an omitted value. For individual `Body` parameters, `null` is validated as `None`: nullable types accept it, and non-nullable types reject it even when a default is defined. Defaults and default factories apply only when the value is omitted. This applies both to parameters inside JSON objects and to parameters representing the entire body. Clients that used `null` to request a default should omit the value instead. When a JSON object is expected because of `Body(embed=True)` or multiple body parameters, sending `null` as the entire body now returns a validation error. ##### Breaking Changes - 🐛 Distinguish JSON null from omitted body values. PR [#&#8203;16536](https://github.com/fastapi/fastapi/pull/16536) by [@&#8203;tiangolo](https://github.com/tiangolo). ### [`v0.150.0`](https://github.com/fastapi/fastapi/releases/tag/0.150.0) [Compare Source](https://github.com/fastapi/fastapi/compare/0.149.0...0.150.0) When no file is selected, browsers submit a file part with an empty filename and empty content. FastAPI now treats this as missing: required file fields return a validation error, and fields with defaults or default factories use them. Unselected inputs are ignored in lists of files. Named zero-byte files are still accepted. ##### Breaking Changes - 🐛 Treat unselected browser file inputs as missing. PR [#&#8203;16534](https://github.com/fastapi/fastapi/pull/16534) by [@&#8203;tiangolo](https://github.com/tiangolo). ### [`v0.149.0`](https://github.com/fastapi/fastapi/releases/tag/0.149.0) [Compare Source](https://github.com/fastapi/fastapi/compare/0.148.0...0.149.0) Browsers submit empty text inputs as empty strings (`""`). FastAPI now treats empty scalar form values as missing in form models, matching individual `Form` parameters. Required fields return a validation error. Fields with defaults or default factories use them and remain unset in `model_dump(exclude_unset=True)`. Empty strings inside lists are preserved. Omitted boolean form fields still become `False`. JSON requests and direct Pydantic validation are unchanged. ##### Breaking Changes - 🐛 Treat empty scalar values as missing in form models. PR [#&#8203;16529](https://github.com/fastapi/fastapi/pull/16529) by [@&#8203;tiangolo](https://github.com/tiangolo). ### [`v0.148.0`](https://github.com/fastapi/fastapi/releases/tag/0.148.0) [Compare Source](https://github.com/fastapi/fastapi/compare/0.147.0...0.148.0) Defaults for omitted `Query`, `Header`, `Cookie`, and `Form` parameters and model fields are no longer treated as user input. Defaults are not validated unless `validate_default=True` is enabled. If you rely on validators running for omitted values, enable default validation with `Field(validate_default=True)` for model fields or, for example, `Query(validate_default=True)` for individual parameters. `Body(validate_default=True)` is now honored too. For parameter models, applying a default no longer marks a field as explicitly set, so `model_dump(exclude_unset=True)` excludes it. Default factories run once, and validation errors no longer include injected defaults in `input`. Omitted boolean form fields still become `False` and count as explicitly set. ##### Breaking Changes - 🐛 Fix default handling for request parameters and models. PR [#&#8203;16527](https://github.com/fastapi/fastapi/pull/16527) by [@&#8203;tiangolo](https://github.com/tiangolo). ### [`v0.147.0`](https://github.com/fastapi/fastapi/releases/tag/0.147.0) [Compare Source](https://github.com/fastapi/fastapi/compare/0.146.0...0.147.0) Omitted `bool` and `bool | None` form fields are now interpreted as `False`, matching unchecked HTML checkboxes. This applies to individual `Form` parameters and form models, including required fields and fields with defaults of `True` or `None`. The inferred value is considered explicitly set, including in `model_dump(exclude_unset=True)`. JSON requests and direct Pydantic validation are unchanged. See [Boolean Form Fields](https://fastapi.tiangolo.com/tutorial/request-forms/#boolean-form-fields). ##### Breaking Changes - 🐛 Treat omitted boolean form fields as False. PR [#&#8203;16523](https://github.com/fastapi/fastapi/pull/16523) by [@&#8203;tiangolo](https://github.com/tiangolo). ##### Internal - ✅ Add tests for parameter defaults, nullability, and browser form behavior. PR [#&#8203;14829](https://github.com/fastapi/fastapi/pull/14829) by [@&#8203;YuriiMotov](https://github.com/YuriiMotov). ### [`v0.146.0`](https://github.com/fastapi/fastapi/releases/tag/0.146.0) [Compare Source](https://github.com/fastapi/fastapi/compare/0.145.0...0.146.0) The `root_path` parameter in `FastAPI()` is deprecated. Configure the server with `fastapi run --root-path /api/v1` instead. ##### Breaking Changes - 🗑️ Deprecate the `root_path` parameter in `FastAPI`. PR [#&#8203;16520](https://github.com/fastapi/fastapi/pull/16520) by [@&#8203;tiangolo](https://github.com/tiangolo). ### [`v0.145.0`](https://github.com/fastapi/fastapi/releases/tag/0.145.0) [Compare Source](https://github.com/fastapi/fastapi/compare/0.144.0...0.145.0) ##### Breaking Changes - 🔥 Remove deprecated `openapi_prefix` and unused `**extra` from `FastAPI`. PR [#&#8203;16518](https://github.com/fastapi/fastapi/pull/16518) by [@&#8203;tiangolo](https://github.com/tiangolo). ##### Docs - 📝 Document URL paths in templates. PR [#&#8203;16517](https://github.com/fastapi/fastapi/pull/16517) by [@&#8203;tiangolo](https://github.com/tiangolo). ### [`v0.144.0`](https://github.com/fastapi/fastapi/releases/tag/0.144.0) [Compare Source](https://github.com/fastapi/fastapi/compare/0.143.5...0.144.0) ##### Features - ✨ Add WebSocket support to security dependencies. PR [#&#8203;10147](https://github.com/fastapi/fastapi/pull/10147) by [@&#8203;mnixry](https://github.com/mnixry). ### [`v0.143.5`](https://github.com/fastapi/fastapi/releases/tag/0.143.5) [Compare Source](https://github.com/fastapi/fastapi/compare/0.143.4...0.143.5) ##### Fixes - 🐛 Fix handling of empty value for `byte` file list parameter. PR [#&#8203;9383](https://github.com/fastapi/fastapi/pull/9383) by [@&#8203;Viicos](https://github.com/Viicos). ### [`v0.143.4`](https://github.com/fastapi/fastapi/releases/tag/0.143.4) [Compare Source](https://github.com/fastapi/fastapi/compare/0.143.3...0.143.4) ##### Upgrades - ⬆️ Add httpx2 to optional dependencies. PR [#&#8203;16512](https://github.com/fastapi/fastapi/pull/16512) by [@&#8203;tiangolo](https://github.com/tiangolo). ### [`v0.143.3`](https://github.com/fastapi/fastapi/releases/tag/0.143.3) [Compare Source](https://github.com/fastapi/fastapi/compare/0.143.2...0.143.3) ##### Fixes - 🐛 Fix non-finite float serialization in JSONL and SSE streams. PR [#&#8203;16509](https://github.com/fastapi/fastapi/pull/16509) by [@&#8203;tiangolo](https://github.com/tiangolo). ##### Docs - 🎨 Update Python format in Markdown with Ruff. PR [#&#8203;16505](https://github.com/fastapi/fastapi/pull/16505) by [@&#8203;tiangolo](https://github.com/tiangolo). ### [`v0.143.2`](https://github.com/fastapi/fastapi/releases/tag/0.143.2) [Compare Source](https://github.com/fastapi/fastapi/compare/0.143.1...0.143.2) ##### Fixes - 🐛 Fix blocking frontend fallback file checks. PR [#&#8203;16503](https://github.com/fastapi/fastapi/pull/16503) by [@&#8203;tiangolo](https://github.com/tiangolo). ##### Translations - 🌐 Update translations for zh-hant (update-outdated). PR [#&#8203;16500](https://github.com/fastapi/fastapi/pull/16500) by [@&#8203;pr-submit\[bot\]](https://github.com/apps/pr-submit). - 🌐 Update translations for ja (update-outdated). PR [#&#8203;16499](https://github.com/fastapi/fastapi/pull/16499) by [@&#8203;pr-submit\[bot\]](https://github.com/apps/pr-submit). - 🌐 Update translations for zh (update-outdated). PR [#&#8203;16501](https://github.com/fastapi/fastapi/pull/16501) by [@&#8203;pr-submit\[bot\]](https://github.com/apps/pr-submit). - 🌐 Update translations for hi (update-outdated). PR [#&#8203;16498](https://github.com/fastapi/fastapi/pull/16498) by [@&#8203;pr-submit\[bot\]](https://github.com/apps/pr-submit). - 🌐 Update translations for es (update-outdated). PR [#&#8203;16497](https://github.com/fastapi/fastapi/pull/16497) by [@&#8203;pr-submit\[bot\]](https://github.com/apps/pr-submit). - 🌐 Update translations for fr (update-outdated). PR [#&#8203;16495](https://github.com/fastapi/fastapi/pull/16495) by [@&#8203;pr-submit\[bot\]](https://github.com/apps/pr-submit). - 🌐 Update translations for ko (update-outdated). PR [#&#8203;16496](https://github.com/fastapi/fastapi/pull/16496) by [@&#8203;pr-submit\[bot\]](https://github.com/apps/pr-submit). - 🌐 Update translations for de (update-outdated). PR [#&#8203;16493](https://github.com/fastapi/fastapi/pull/16493) by [@&#8203;pr-submit\[bot\]](https://github.com/apps/pr-submit). - 🌐 Update translations for uk (update-outdated). PR [#&#8203;16494](https://github.com/fastapi/fastapi/pull/16494) by [@&#8203;pr-submit\[bot\]](https://github.com/apps/pr-submit). - 🌐 Update translations for tr (update-outdated). PR [#&#8203;16490](https://github.com/fastapi/fastapi/pull/16490) by [@&#8203;pr-submit\[bot\]](https://github.com/apps/pr-submit). - 🌐 Update translations for pt (update-outdated). PR [#&#8203;16491](https://github.com/fastapi/fastapi/pull/16491) by [@&#8203;pr-submit\[bot\]](https://github.com/apps/pr-submit). - 🌐 Update translations for ru (update-outdated). PR [#&#8203;16492](https://github.com/fastapi/fastapi/pull/16492) by [@&#8203;pr-submit\[bot\]](https://github.com/apps/pr-submit). ##### Internal - ⬆ Bump pydantic-ai-slim from 2.49.0 to 2.53.0. PR [#&#8203;16487](https://github.com/fastapi/fastapi/pull/16487) by [@&#8203;dependabot\[bot\]](https://github.com/apps/dependabot). - ⬆ Bump werkzeug from 3.1.6 to 3.1.9. PR [#&#8203;16464](https://github.com/fastapi/fastapi/pull/16464) by [@&#8203;dependabot\[bot\]](https://github.com/apps/dependabot). ### [`v0.143.1`](https://github.com/fastapi/fastapi/releases/tag/0.143.1) [Compare Source](https://github.com/fastapi/fastapi/compare/0.143.0...0.143.1) ##### Fixes - 🐛 Fix included route metadata in `iter_route_contexts()`. PR [#&#8203;16484](https://github.com/fastapi/fastapi/pull/16484) by [@&#8203;tiangolo](https://github.com/tiangolo). ### [`v0.143.0`](https://github.com/fastapi/fastapi/releases/tag/0.143.0) [Compare Source](https://github.com/fastapi/fastapi/compare/0.142.4...0.143.0) Automatic OpenTelemetry exporter setup is now opt-in. If you rely on FastAPI to configure exporters from `OTEL_*` environment variables, set `FASTAPI_OTEL_AUTO_CONFIGURE=true` or use `FastAPI(telemetry={"auto_configure": True})` to retain the previous behavior. Applications that configure their own providers and exporters require no changes. FastAPI Cloud enables automatic setup for you. ##### Breaking Changes - 💥 Require opt-in for automatic OpenTelemetry exporter setup. PR [#&#8203;16476](https://github.com/fastapi/fastapi/pull/16476) by [@&#8203;tiangolo](https://github.com/tiangolo). ### [`v0.142.4`](https://github.com/fastapi/fastapi/releases/tag/0.142.4) [Compare Source](https://github.com/fastapi/fastapi/compare/0.142.3...0.142.4) ##### Fixes - 🐛 Isolate FastAPI telemetry for excluded requests. PR [#&#8203;16470](https://github.com/fastapi/fastapi/pull/16470) by [@&#8203;tiangolo](https://github.com/tiangolo). ### [`v0.142.3`](https://github.com/fastapi/fastapi/releases/tag/0.142.3) [Compare Source](https://github.com/fastapi/fastapi/compare/0.142.2...0.142.3) ##### Fixes - 🐛 Cache OpenTelemetry tracers to preserve warning deduplication. PR [#&#8203;16468](https://github.com/fastapi/fastapi/pull/16468) by [@&#8203;tiangolo](https://github.com/tiangolo). ##### Docs - 📝 Remove HTML title from newsletter to avoid the tooltip. PR [#&#8203;16461](https://github.com/fastapi/fastapi/pull/16461) by [@&#8203;tiangolo](https://github.com/tiangolo). - 📝 Embed the FastAPI and friends newsletter signup form. PR [#&#8203;16459](https://github.com/fastapi/fastapi/pull/16459) by [@&#8203;tiangolo](https://github.com/tiangolo). - 📝 Update skill, use Asyncer for blocking code in threads. PR [#&#8203;16420](https://github.com/fastapi/fastapi/pull/16420) by [@&#8203;tiangolo](https://github.com/tiangolo). ##### Translations - 🌐 Update translations for fr (add-missing). PR [#&#8203;16436](https://github.com/fastapi/fastapi/pull/16436) by [@&#8203;pr-submit\[bot\]](https://github.com/apps/pr-submit). - 🌐 Update translations for hi (add-missing). PR [#&#8203;16435](https://github.com/fastapi/fastapi/pull/16435) by [@&#8203;pr-submit\[bot\]](https://github.com/apps/pr-submit). - 🌐 Update translations for tr (add-missing). PR [#&#8203;16434](https://github.com/fastapi/fastapi/pull/16434) by [@&#8203;pr-submit\[bot\]](https://github.com/apps/pr-submit). - 🌐 Update translations for zh (add-missing). PR [#&#8203;16433](https://github.com/fastapi/fastapi/pull/16433) by [@&#8203;pr-submit\[bot\]](https://github.com/apps/pr-submit). - 🌐 Update translations for zh-hant (add-missing). PR [#&#8203;16432](https://github.com/fastapi/fastapi/pull/16432) by [@&#8203;pr-submit\[bot\]](https://github.com/apps/pr-submit). - 🌐 Update translations for pt (add-missing). PR [#&#8203;16431](https://github.com/fastapi/fastapi/pull/16431) by [@&#8203;pr-submit\[bot\]](https://github.com/apps/pr-submit). - 🌐 Update translations for de (add-missing). PR [#&#8203;16430](https://github.com/fastapi/fastapi/pull/16430) by [@&#8203;pr-submit\[bot\]](https://github.com/apps/pr-submit). - 🌐 Update translations for uk (add-missing). PR [#&#8203;16429](https://github.com/fastapi/fastapi/pull/16429) by [@&#8203;pr-submit\[bot\]](https://github.com/apps/pr-submit). - 🌐 Update translations for ja (add-missing). PR [#&#8203;16428](https://github.com/fastapi/fastapi/pull/16428) by [@&#8203;pr-submit\[bot\]](https://github.com/apps/pr-submit). - 🌐 Update translations for ko (add-missing). PR [#&#8203;16425](https://github.com/fastapi/fastapi/pull/16425) by [@&#8203;pr-submit\[bot\]](https://github.com/apps/pr-submit). - 🌐 Update translations for es (add-missing). PR [#&#8203;16426](https://github.com/fastapi/fastapi/pull/16426) by [@&#8203;pr-submit\[bot\]](https://github.com/apps/pr-submit). - 🌐 Update translations for ru (add-missing). PR [#&#8203;16427](https://github.com/fastapi/fastapi/pull/16427) by [@&#8203;pr-submit\[bot\]](https://github.com/apps/pr-submit). - 🌐 Update Russian LLM-prompt. PR [#&#8203;16449](https://github.com/fastapi/fastapi/pull/16449) by [@&#8203;YuriiMotov](https://github.com/YuriiMotov). ##### Internal - 👷 Fix deprecated command in `bump-pre-commit-hooks` workflow. PR [#&#8203;16463](https://github.com/fastapi/fastapi/pull/16463) by [@&#8203;YuriiMotov](https://github.com/YuriiMotov). - 🔧 Update sponsors: remove Render. PR [#&#8203;16457](https://github.com/fastapi/fastapi/pull/16457) by [@&#8203;tiangolo](https://github.com/tiangolo). - 🔨 Use `gpt-6-astra` model for translations. PR [#&#8203;16453](https://github.com/fastapi/fastapi/pull/16453) by [@&#8203;YuriiMotov](https://github.com/YuriiMotov). - ⬆ Bump the python-packages group across 1 directory with 14 updates. PR [#&#8203;16447](https://github.com/fastapi/fastapi/pull/16447) by [@&#8203;dependabot\[bot\]](https://github.com/apps/dependabot). - ⬆ Bump starlette from 1.6.0 to 1.7.0. PR [#&#8203;16440](https://github.com/fastapi/fastapi/pull/16440) by [@&#8203;dependabot\[bot\]](https://github.com/apps/dependabot). - ⬆ Bump pyjwt from 2.13.0 to 2.15.0. PR [#&#8203;16423](https://github.com/fastapi/fastapi/pull/16423) by [@&#8203;dependabot\[bot\]](https://github.com/apps/dependabot). - ⬆ Bump gitpython from 3.1.60 to 3.1.62. PR [#&#8203;16444](https://github.com/fastapi/fastapi/pull/16444) by [@&#8203;dependabot\[bot\]](https://github.com/apps/dependabot). - 👥 Update FastAPI GitHub topic repositories. PR [#&#8203;16443](https://github.com/fastapi/fastapi/pull/16443) by [@&#8203;pr-submit\[bot\]](https://github.com/apps/pr-submit). - 👥 Update FastAPI People - Sponsors. PR [#&#8203;16437](https://github.com/fastapi/fastapi/pull/16437) by [@&#8203;pr-submit\[bot\]](https://github.com/apps/pr-submit). - ⬆ Bump pre-commit hooks. PR [#&#8203;16442](https://github.com/fastapi/fastapi/pull/16442) by [@&#8203;pr-submit\[bot\]](https://github.com/apps/pr-submit). - ⬆ Bump urllib3 from 2.7.0 to 2.8.0. PR [#&#8203;16445](https://github.com/fastapi/fastapi/pull/16445) by [@&#8203;dependabot\[bot\]](https://github.com/apps/dependabot). - ⬆ Bump the github-actions group with 3 updates. PR [#&#8203;16438](https://github.com/fastapi/fastapi/pull/16438) by [@&#8203;dependabot\[bot\]](https://github.com/apps/dependabot). ### [`v0.142.2`](https://github.com/fastapi/fastapi/releases/tag/0.142.2) [Compare Source](https://github.com/fastapi/fastapi/compare/0.142.1...0.142.2) ##### Fixes - 🐛 Allow startup when automatic OpenTelemetry configuration fails. PR [#&#8203;16418](https://github.com/fastapi/fastapi/pull/16418) by [@&#8203;tiangolo](https://github.com/tiangolo). ### [`v0.142.1`](https://github.com/fastapi/fastapi/releases/tag/0.142.1) [Compare Source](https://github.com/fastapi/fastapi/compare/0.142.0...0.142.1) ##### Fixes - 🐛 Fix repeated endpoint wrapping in included routers. PR [#&#8203;16414](https://github.com/fastapi/fastapi/pull/16414) by [@&#8203;tiangolo](https://github.com/tiangolo). ### [`v0.142.0`](https://github.com/fastapi/fastapi/releases/tag/0.142.0) [Compare Source](https://github.com/fastapi/fastapi/compare/0.141.1...0.142.0) ##### Features - ✨ Add native OpenTelemetry support. PR [#&#8203;16403](https://github.com/fastapi/fastapi/pull/16403) by [@&#8203;tiangolo](https://github.com/tiangolo). ##### Refactors - 📱 Improve mobile responsiveness of conference rail. PR [#&#8203;16196](https://github.com/fastapi/fastapi/pull/16196) by [@&#8203;alejsdev](https://github.com/alejsdev). - ♻️ Remove conf section and add event banner. PR [#&#8203;16193](https://github.com/fastapi/fastapi/pull/16193) by [@&#8203;alejsdev](https://github.com/alejsdev). ##### Docs - 🔥 Remove unused image. PR [#&#8203;16195](https://github.com/fastapi/fastapi/pull/16195) by [@&#8203;alejsdev](https://github.com/alejsdev). - 🐛 Use buttons for Termynal controls. PR [#&#8203;16132](https://github.com/fastapi/fastapi/pull/16132) by [@&#8203;tiangolo](https://github.com/tiangolo). ##### Translations - 🌐 Update translations for hi (update-outdated). PR [#&#8203;16212](https://github.com/fastapi/fastapi/pull/16212) by [@&#8203;pr-submit\[bot\]](https://github.com/apps/pr-submit). - 🌐 Update translations for ru (update-outdated). PR [#&#8203;16210](https://github.com/fastapi/fastapi/pull/16210) by [@&#8203;pr-submit\[bot\]](https://github.com/apps/pr-submit). - 🌐 Update translations for zh-hant (update-outdated). PR [#&#8203;16211](https://github.com/fastapi/fastapi/pull/16211) by [@&#8203;pr-submit\[bot\]](https://github.com/apps/pr-submit). - 🌐 Update translations for uk (update-outdated). PR [#&#8203;16208](https://github.com/fastapi/fastapi/pull/16208) by [@&#8203;pr-submit\[bot\]](https://github.com/apps/pr-submit). - 🌐 Update translations for de (update-outdated). PR [#&#8203;16209](https://github.com/fastapi/fastapi/pull/16209) by [@&#8203;pr-submit\[bot\]](https://github.com/apps/pr-submit). - 🌐 Update translations for tr (update-outdated). PR [#&#8203;16207](https://github.com/fastapi/fastapi/pull/16207) by [@&#8203;pr-submit\[bot\]](https://github.com/apps/pr-submit). - 🌐 Update translations for ja (update-outdated). PR [#&#8203;16206](https://github.com/fastapi/fastapi/pull/16206) by [@&#8203;pr-submit\[bot\]](https://github.com/apps/pr-submit). - 🌐 Update translations for fr (update-outdated). PR [#&#8203;16205](https://github.com/fastapi/fastapi/pull/16205) by [@&#8203;pr-submit\[bot\]](https://github.com/apps/pr-submit). - 🌐 Update translations for zh (update-outdated). PR [#&#8203;16204](https://github.com/fastapi/fastapi/pull/16204) by [@&#8203;pr-submit\[bot\]](https://github.com/apps/pr-submit). - 🌐 Update translations for es (update-outdated). PR [#&#8203;16203](https://github.com/fastapi/fastapi/pull/16203) by [@&#8203;pr-submit\[bot\]](https://github.com/apps/pr-submit). - 🌐 Update translations for pt (update-outdated). PR [#&#8203;16202](https://github.com/fastapi/fastapi/pull/16202) by [@&#8203;pr-submit\[bot\]](https://github.com/apps/pr-submit). - 🌐 Update translations for ko (update-outdated). PR [#&#8203;16201](https://github.com/fastapi/fastapi/pull/16201) by [@&#8203;pr-submit\[bot\]](https://github.com/apps/pr-submit). - 🌐 Update translations for ko (update-outdated). PR [#&#8203;16171](https://github.com/fastapi/fastapi/pull/16171) by [@&#8203;pr-submit\[bot\]](https://github.com/apps/pr-submit). ##### Internal - ✅ Fix frontend test timeout with Starlette Git. PR [#&#8203;16408](https://github.com/fastapi/fastapi/pull/16408) by [@&#8203;YuriiMotov](https://github.com/YuriiMotov). - 🔧 Update sponsors: remove Permit.io. PR [#&#8203;16406](https://github.com/fastapi/fastapi/pull/16406) by [@&#8203;tiangolo](https://github.com/tiangolo). - ⬆ Bump anyio from 4.12.1 to 4.14.2. PR [#&#8203;16375](https://github.com/fastapi/fastapi/pull/16375) by [@&#8203;dependabot\[bot\]](https://github.com/apps/dependabot). - ⬆ Bump the python-packages group across 1 directory with 15 updates. PR [#&#8203;16285](https://github.com/fastapi/fastapi/pull/16285) by [@&#8203;dependabot\[bot\]](https://github.com/apps/dependabot). - ⬆ Bump starlette from 1.3.1 to 1.6.0. PR [#&#8203;16289](https://github.com/fastapi/fastapi/pull/16289) by [@&#8203;dependabot\[bot\]](https://github.com/apps/dependabot). - ⬆ Bump annotated-doc from 0.0.4 to 0.0.5. PR [#&#8203;16288](https://github.com/fastapi/fastapi/pull/16288) by [@&#8203;dependabot\[bot\]](https://github.com/apps/dependabot). - ⬆ Bump typing-inspection from 0.4.2 to 0.4.4. PR [#&#8203;16286](https://github.com/fastapi/fastapi/pull/16286) by [@&#8203;dependabot\[bot\]](https://github.com/apps/dependabot). - ⬆ Bump fastar from 0.11.0 to 0.12.0. PR [#&#8203;16287](https://github.com/fastapi/fastapi/pull/16287) by [@&#8203;dependabot\[bot\]](https://github.com/apps/dependabot). - ⬆ Bump the github-actions group with 5 updates. PR [#&#8203;16284](https://github.com/fastapi/fastapi/pull/16284) by [@&#8203;dependabot\[bot\]](https://github.com/apps/dependabot). - ⬆ Bump pre-commit hooks. PR [#&#8203;16290](https://github.com/fastapi/fastapi/pull/16290) by [@&#8203;pr-submit\[bot\]](https://github.com/apps/pr-submit). - 👥 Update FastAPI GitHub topic repositories. PR [#&#8203;16291](https://github.com/fastapi/fastapi/pull/16291) by [@&#8203;pr-submit\[bot\]](https://github.com/apps/pr-submit). - 👥 Update FastAPI People - Sponsors. PR [#&#8203;16282](https://github.com/fastapi/fastapi/pull/16282) by [@&#8203;pr-submit\[bot\]](https://github.com/apps/pr-submit). - ⬆️ Bump Typer min version to 0.26.1. PR [#&#8203;16252](https://github.com/fastapi/fastapi/pull/16252) by [@&#8203;YuriiMotov](https://github.com/YuriiMotov). - ⬆️ Bump `setup-uv` action to `10.0.1`. PR [#&#8203;16249](https://github.com/fastapi/fastapi/pull/16249) by [@&#8203;YuriiMotov](https://github.com/YuriiMotov). - 👷 Update translation PR branches with PR Push. PR [#&#8203;16224](https://github.com/fastapi/fastapi/pull/16224) by [@&#8203;tiangolo](https://github.com/tiangolo). - ⏪️ Restore `commit_in_place` input in `translate.yml`. PR [#&#8203;16216](https://github.com/fastapi/fastapi/pull/16216) by [@&#8203;YuriiMotov](https://github.com/YuriiMotov). - 👷 Migrate automatic labels to Latest Changes. PR [#&#8203;16185](https://github.com/fastapi/fastapi/pull/16185) by [@&#8203;tiangolo](https://github.com/tiangolo). - 👷 Fix branch name in `zizmor.yml` workflow (`main` -> `master`). PR [#&#8203;16178](https://github.com/fastapi/fastapi/pull/16178) by [@&#8203;YuriiMotov](https://github.com/YuriiMotov). - 👷 Remove legacy label check. PR [#&#8203;16180](https://github.com/fastapi/fastapi/pull/16180) by [@&#8203;tiangolo](https://github.com/tiangolo). - ⬆ Bump pymdown-extensions from 11.0 to 11.0.1. PR [#&#8203;16162](https://github.com/fastapi/fastapi/pull/16162) by [@&#8203;dependabot\[bot\]](https://github.com/apps/dependabot). - ⬆ Bump gitpython from 3.1.57 to 3.1.58. PR [#&#8203;16157](https://github.com/fastapi/fastapi/pull/16157) by [@&#8203;dependabot\[bot\]](https://github.com/apps/dependabot). - 👥 Update FastAPI People - Sponsors. PR [#&#8203;16175](https://github.com/fastapi/fastapi/pull/16175) by [@&#8203;pr-submit\[bot\]](https://github.com/apps/pr-submit). - 🐛 Fix Sponsors Git authentication. PR [#&#8203;16174](https://github.com/fastapi/fastapi/pull/16174) by [@&#8203;tiangolo](https://github.com/tiangolo). - 👥 Update FastAPI GitHub topic repositories. PR [#&#8203;16173](https://github.com/fastapi/fastapi/pull/16173) by [@&#8203;pr-submit\[bot\]](https://github.com/apps/pr-submit). - 🔐 Use PR Submit for automated updates. PR [#&#8203;16172](https://github.com/fastapi/fastapi/pull/16172) by [@&#8203;tiangolo](https://github.com/tiangolo). - 🔐 Use PR Submit for translations. PR [#&#8203;16168](https://github.com/fastapi/fastapi/pull/16168) by [@&#8203;tiangolo](https://github.com/tiangolo). - ⬆️ Raise pytest-xdist minimum. PR [#&#8203;16170](https://github.com/fastapi/fastapi/pull/16170) by [@&#8203;tiangolo](https://github.com/tiangolo). - 🔐 Use PR Submit for pull requests. PR [#&#8203;16167](https://github.com/fastapi/fastapi/pull/16167) by [@&#8203;tiangolo](https://github.com/tiangolo). - 👷 Use GitHub CLI for Git authentication. PR [#&#8203;16166](https://github.com/fastapi/fastapi/pull/16166) by [@&#8203;tiangolo](https://github.com/tiangolo). - 👷 Use PR Push commit identity. PR [#&#8203;16164](https://github.com/fastapi/fastapi/pull/16164) by [@&#8203;tiangolo](https://github.com/tiangolo). - 🔒 Replace pre-commit PAT with PR Push. PR [#&#8203;16161](https://github.com/fastapi/fastapi/pull/16161) by [@&#8203;tiangolo](https://github.com/tiangolo). - 👷 Disable saving Zensical's `.cache` in `build-docs.yml`. PR [#&#8203;16156](https://github.com/fastapi/fastapi/pull/16156) by [@&#8203;YuriiMotov](https://github.com/YuriiMotov). - 🔥 Remove the old Latest Changes workflow. PR [#&#8203;16148](https://github.com/fastapi/fastapi/pull/16148) by [@&#8203;tiangolo](https://github.com/tiangolo). - ⬆ Bump the python-packages group with 12 updates. PR [#&#8203;16121](https://github.com/fastapi/fastapi/pull/16121) by [@&#8203;dependabot\[bot\]](https://github.com/apps/dependabot). - ⬆ Bump cryptography from 48.0.1 to 50.0.0. PR [#&#8203;16142](https://github.com/fastapi/fastapi/pull/16142) by [@&#8203;dependabot\[bot\]](https://github.com/apps/dependabot). - ⬆ Bump gitpython from 3.1.54 to 3.1.57. PR [#&#8203;16141](https://github.com/fastapi/fastapi/pull/16141) by [@&#8203;dependabot\[bot\]](https://github.com/apps/dependabot). - ⬆ Bump the github-actions group with 6 updates. PR [#&#8203;16120](https://github.com/fastapi/fastapi/pull/16120) by [@&#8203;dependabot\[bot\]](https://github.com/apps/dependabot). - 👥 Update FastAPI GitHub topic repositories. PR [#&#8203;16122](https://github.com/fastapi/fastapi/pull/16122) by [@&#8203;tiangolo](https://github.com/tiangolo). - 👥 Update FastAPI People - Sponsors. PR [#&#8203;16119](https://github.com/fastapi/fastapi/pull/16119) by [@&#8203;tiangolo](https://github.com/tiangolo). ### [`v0.141.1`](https://github.com/fastapi/fastapi/releases/tag/0.141.1) [Compare Source](https://github.com/fastapi/fastapi/compare/0.141.0...0.141.1) ##### Fixes - 🐛 Fix support for background tasks and headers from dependencies in `app.frontend()`. PR [#&#8203;16105](https://github.com/fastapi/fastapi/pull/16105) by [@&#8203;tiangolo](https://github.com/tiangolo). ##### Docs - 📝 Document `FASTAPI_ENV` in FastAPI CLI guide. PR [#&#8203;16104](https://github.com/fastapi/fastapi/pull/16104) by [@&#8203;tiangolo](https://github.com/tiangolo). ### [`v0.141.0`](https://github.com/fastapi/fastapi/releases/tag/0.141.0) [Compare Source](https://github.com/fastapi/fastapi/compare/0.140.13...0.141.0) ##### Features - ✨ Add `app.frontend(check_dir="auto")`, to make local development more convenient with `fastapi dev`. PR [#&#8203;16102](https://github.com/fastapi/fastapi/pull/16102) by [@&#8203;tiangolo](https://github.com/tiangolo). ### [`v0.140.13`](https://github.com/fastapi/fastapi/releases/tag/0.140.13) [Compare Source](https://github.com/fastapi/fastapi/compare/0.140.12...0.140.13) ##### Fixes - 🐛 Fix `status_code` being ignored for SSE and JSONL streaming endpoints. PR [#&#8203;15937](https://github.com/fastapi/fastapi/pull/15937) by [@&#8203;SAURABHSALVE](https://github.com/SAURABHSALVE). ##### Docs - 📝 Fix `format_sse_event` docstring rendering of `\n\n` terminator. PR [#&#8203;15613](https://github.com/fastapi/fastapi/pull/15613) by [@&#8203;AshNicolus](https://github.com/AshNicolus). - 📝 Add API reference page for fastapi.sse. PR [#&#8203;15930](https://github.com/fastapi/fastapi/pull/15930) by [@&#8203;SAURABHSALVE](https://github.com/SAURABHSALVE). ### [`v0.140.12`](https://github.com/fastapi/fastapi/releases/tag/0.140.12) [Compare Source](https://github.com/fastapi/fastapi/compare/0.140.11...0.140.12) ##### Fixes - 🐛 Fix line splitting in `format_sse_event` to comply with SSE spec. PR [#&#8203;15515](https://github.com/fastapi/fastapi/pull/15515) by [@&#8203;Zawwarsami16](https://github.com/Zawwarsami16). ### [`v0.140.11`](https://github.com/fastapi/fastapi/releases/tag/0.140.11) [Compare Source](https://github.com/fastapi/fastapi/compare/0.140.10...0.140.11) ##### Fixes - 🐛 Fix `response_model_*` params ignored for non-generator endpoints with `Iterable[..]` return type. PR [#&#8203;15093](https://github.com/fastapi/fastapi/pull/15093) by [@&#8203;YuriiMotov](https://github.com/YuriiMotov). ### [`v0.140.10`](https://github.com/fastapi/fastapi/releases/tag/0.140.10) [Compare Source](https://github.com/fastapi/fastapi/compare/0.140.9...0.140.10) ##### Fixes - 🐛 Fix handling sequences with nested Annotated types. PR [#&#8203;14874](https://github.com/fastapi/fastapi/pull/14874) by [@&#8203;YuriiMotov](https://github.com/YuriiMotov). ##### Internal - 🐛 Accept any base test failure as regression. PR [#&#8203;16092](https://github.com/fastapi/fastapi/pull/16092) by [@&#8203;tiangolo](https://github.com/tiangolo). - 🐛 Preserve pytest exit code in regression check. PR [#&#8203;16091](https://github.com/fastapi/fastapi/pull/16091) by [@&#8203;tiangolo](https://github.com/tiangolo). - ✅ Test PR regressions against base code. PR [#&#8203;16090](https://github.com/fastapi/fastapi/pull/16090) by [@&#8203;tiangolo](https://github.com/tiangolo). ### [`v0.140.9`](https://github.com/fastapi/fastapi/releases/tag/0.140.9) [Compare Source](https://github.com/fastapi/fastapi/compare/0.140.8...0.140.9) ##### Fixes - 🐛 Fix `exclude_defaults` not propagated to dict keys and values in `jsonable_encoder`. PR [#&#8203;16043](https://github.com/fastapi/fastapi/pull/16043) by [@&#8203;MBGrao](https://github.com/MBGrao). ##### Internal - ⬆ Bump gitpython from 3.1.50 to 3.1.54. PR [#&#8203;16047](https://github.com/fastapi/fastapi/pull/16047) by [@&#8203;dependabot\[bot\]](https://github.com/apps/dependabot). - ⬆ Bump pymdown-extensions from 10.21.3 to 11.0. PR [#&#8203;16048](https://github.com/fastapi/fastapi/pull/16048) by [@&#8203;dependabot\[bot\]](https://github.com/apps/dependabot). - ⬆ Bump pyasn1 from 0.6.3 to 0.6.4. PR [#&#8203;16045](https://github.com/fastapi/fastapi/pull/16045) by [@&#8203;dependabot\[bot\]](https://github.com/apps/dependabot). ### [`v0.140.8`](https://github.com/fastapi/fastapi/releases/tag/0.140.8) [Compare Source](https://github.com/fastapi/fastapi/compare/0.140.7...0.140.8) ##### Fixes - 🐛 Fix stream item type lost when using `include_router()`. PR [#&#8203;15077](https://github.com/fastapi/fastapi/pull/15077) by [@&#8203;alex-raw](https://github.com/alex-raw). </details> <details> <summary>pydantic/pydantic-settings (pydantic-settings)</summary> ### [`v2.16.2`](https://github.com/pydantic/pydantic-settings/compare/v2.16.1...v2.16.2) [Compare Source](https://github.com/pydantic/pydantic-settings/compare/v2.16.1...v2.16.2) ### [`v2.16.1`](https://github.com/pydantic/pydantic-settings/releases/tag/v2.16.1) [Compare Source](https://github.com/pydantic/pydantic-settings/compare/v2.16.0...v2.16.1) #### Highlights This patch release fixes two CLI regressions introduced in 2.16.0. ##### Bug fixes **CLI** - Fixed-length tuple positionals such as `CliPositionalArg[tuple[int, int]]` and `NamedTuple`s are single-valued again ([#&#8203;1069](https://github.com/pydantic/pydantic-settings/pull/1069)). Since 2.16.0 they were treated as variadic, so a CLI either refused to start with a `SettingsError` or put the wrong argument into the tuple. Variable-length tuples (`tuple[int, ...]` and bare `Tuple`) are still variadic. - A field typed as an alias of a list of dicts, e.g. `type ListOfDict = list[dict[str, int]]`, accepts a JSON list again ([#&#8203;1049](https://github.com/pydantic/pydantic-settings/pull/1049)). Since 2.16.0, `--xx '[{"a":1},{"b":2}]'` was merged into the single dict `{"a": 1, "b": 2}` and failed validation. <details> <summary><b>All changes</b> (including dependency bumps and internal maintenance)</summary> #### What's Changed * Harden CI by @&#8203;Viicos in https://github.com/pydantic/pydantic-settings/pull/1044 * Keep list of dicts CLI values as lists by @&#8203;hramezani in https://github.com/pydantic/pydantic-settings/pull/1049 * Keep fixed-length tuple CLI positionals single-valued by @&#8203;hramezani in https://github.com/pydantic/pydantic-settings/pull/1069 * Prepare release 2.16.1 by @&#8203;hramezani in https://github.com/pydantic/pydantic-settings/pull/1087 * build(deps): bump the python-packages group with 3 updates by @&#8203;dependabot[bot] in https://github.com/pydantic/pydantic-settings/pull/1056 **Full Changelog**: <https://github.com/pydantic/pydantic-settings/compare/v2.16.0...v2.16.1> </details> ### [`v2.16.0`](https://github.com/pydantic/pydantic-settings/releases/tag/v2.16.0) [Compare Source](https://github.com/pydantic/pydantic-settings/compare/v2.15.0...v2.16.0) #### Highlights ##### Breaking changes and behavior changes - **Python 3.10 is no longer supported** ([#&#8203;1003](https://github.com/pydantic/pydantic-settings/pull/1003)). pydantic-settings now requires Python 3.11+, since 3.10 reaches end of life this month. The `tomli` fallback is gone in favor of stdlib `tomllib`; the `toml` extra is kept as an empty extra so `pip install pydantic-settings[toml]` keeps working. - **`python-dotenv>=1.2.2` is now required** ([#&#8203;971](https://github.com/pydantic/pydantic-settings/pull/971)) to pick up the fix for CVE-2026-28684. - **Aliases are ignored in every source when `validate_by_alias=False`** ([#&#8203;1033](https://github.com/pydantic/pydantic-settings/pull/1033)). Env vars, secrets, CLI flags and defaults now use only field names, matching pydantic. An env var named after the alias is now ignored instead of raising `extra_forbidden`, and the CLI exposes `--apple` rather than `--pomo`. - **`validation_alias` takes precedence over `alias`** ([#&#8203;1038](https://github.com/pydantic/pydantic-settings/pull/1038)). When the two differ, values from JSON/YAML/TOML files and the CLI were silently ignored; they now load. CLI help lists the `validation_alias` flag first, and `CliApp.serialize` emits it. - **CLI case-insensitivity only lowercases registered options** ([#&#8203;1036](https://github.com/pydantic/pydantic-settings/pull/1036)). With `case_sensitive=False`, args after `--` and those captured by `CliUnknownArgs` keep their case (`-Xmx4G` no longer becomes `-xmx4g`). Unrecognized options are now reported as typed (`--NOPE` instead of `--nope`). - **JSON and YAML config files are read as UTF-8 by default** ([#&#8203;955](https://github.com/pydantic/pydantic-settings/pull/955)) instead of the locale encoding, completing the secrets-file fix from 2.15.0. `json_file_encoding`/`yaml_file_encoding` still override it. - **Discriminated union defaults are partially updated again** ([#&#8203;997](https://github.com/pydantic/pydantic-settings/pull/997)). This reverts the 2.15.0 regression with `nested_model_default_partial_update=True`: the default is only dropped when the incoming value selects a *different* union member. ##### New features - **Python 3.15 and pydantic 2.14 support** ([#&#8203;1026](https://github.com/pydantic/pydantic-settings/pull/1026), [#&#8203;1029](https://github.com/pydantic/pydantic-settings/pull/1029), [#&#8203;1022](https://github.com/pydantic/pydantic-settings/pull/1022)). pydantic 2.14 broke `CliApp.run` and `validate_by_alias=False` handling; both are fixed. - **Cached settings instances** via `Settings.settings_cached()` and `Settings.settings_clear_cache()` ([#&#8203;952](https://github.com/pydantic/pydantic-settings/pull/952)). These give you a process-local singleton per settings class without hand-rolling `lru_cache` wrappers. Calling the class directly still builds a fresh instance. - **AWS Systems Manager Parameter Store source** — `AWSSystemsManagerSettingsSource` ([#&#8203;941](https://github.com/pydantic/pydantic-settings/pull/941)). It recursively reads every parameter under an `ssm_path`, with `/` mapping onto nested models. Install it with the new `aws-systems-manager` extra. - **`env_file_depth`** ([#&#8203;940](https://github.com/pydantic/pydantic-settings/pull/940)) lets a relative `env_file` be found in parent directories, mirroring `pyproject_toml_depth`. This is useful when scripts run from a subdirectory of a monorepo. It defaults to `0`, which keeps the current behavior. - **`CliVariadicArg` for named variadic options** ([#&#8203;949](https://github.com/pydantic/pydantic-settings/pull/949), [#&#8203;958](https://github.com/pydantic/pydantic-settings/pull/958)). It accepts `--param a b c` in addition to repeated `--param a --param b`. Required fields need at least one value. ##### Bug fixes **CLI** - `CliApp.serialize` output now round-trips through `CliApp.run` for enums, tuples, dates and `Decimal`s ([#&#8203;988](https://github.com/pydantic/pydantic-settings/pull/988)), explicit `None` values ([#&#8203;981](https://github.com/pydantic/pydantic-settings/pull/981)), empty containers ([#&#8203;1008](https://github.com/pydantic/pydantic-settings/pull/1008)), `CliVariadicArg` values ([#&#8203;976](https://github.com/pydantic/pydantic-settings/pull/976)) and populated `CliUnknownArgs` fields, which previously raised `IndexError` ([#&#8203;992](https://github.com/pydantic/pydantic-settings/pull/992)). - Empty JSON arrays (`--items []`) now give an empty list instead of `['']` ([#&#8203;994](https://github.com/pydantic/pydantic-settings/pull/994)). - Tuples, `frozenset`, `MutableSequence` and other collection subtypes are now treated as repeatable/variadic options ([#&#8203;972](https://github.com/pydantic/pydantic-settings/pull/972)), and so are named collection type aliases such as `TypeAliasType('Addrs', list[IPvAnyAddress])` ([#&#8203;1032](https://github.com/pydantic/pydantic-settings/pull/1032)). - `cli_exit_on_error=False` is now honored in `CliSubCommand` parsers, which raise `SettingsError` instead of exiting ([#&#8203;977](https://github.com/pydantic/pydantic-settings/pull/977)). - `CliSubCommand` aliases keep their case with `case_sensitive=False` ([#&#8203;989](https://github.com/pydantic/pydantic-settings/pull/989)). - Each `CliUnknownArgs` field now receives only its own subcommand's leftover args ([#&#8203;1004](https://github.com/pydantic/pydantic-settings/pull/1004)). - `CliApp.format_help` no longer crashes when `cli_prefix` is set in `model_config` ([#&#8203;945](https://github.com/pydantic/pydantic-settings/pull/945)). **Type aliases and parsing** - Named union type aliases (`TypeAliasType('V', list[int] | str)`) now decode like their inline equivalents in env and dotenv sources, including under `Optional`, `Annotated` and custom validation aliases ([#&#8203;1006](https://github.com/pydantic/pydantic-settings/pull/1006), [#&#8203;1030](https://github.com/pydantic/pydantic-settings/pull/1030), [#&#8203;1041](https://github.com/pydantic/pydantic-settings/pull/1041)). - Resolving a named `Annotated` type alias no longer mutates shared `FieldInfo` metadata, which made validators run twice on subclasses or after `model_rebuild()` ([#&#8203;979](https://github.com/pydantic/pydantic-settings/pull/979)). - A bare single-segment `AliasPath('SOME_KEY')` no longer tries to JSON-decode plain string values ([#&#8203;980](https://github.com/pydantic/pydantic-settings/pull/980)). - `collections.abc.Set`/`MutableSet`/`typing.AbstractSet` fields now JSON-decode env values ([#&#8203;973](https://github.com/pydantic/pydantic-settings/pull/973)). - A bare `typing.Dict` field with `env_nested_delimiter` no longer raises `IndexError`, which was a regression in 2.13.0 ([#&#8203;1009](https://github.com/pydantic/pydantic-settings/pull/1009)). - Case-insensitive matching now works for nested pydantic dataclasses ([#&#8203;1010](https://github.com/pydantic/pydantic-settings/pull/1010)). **Dotenv, secrets and config files** - With `extra='allow'`, a non-lowercase `env_prefix` is now stripped from dotenv extras ([#&#8203;959](https://github.com/pydantic/pydantic-settings/pull/959), [#&#8203;968](https://github.com/pydantic/pydantic-settings/pull/968)). - `secrets_case_sensitive=True` is now honored on Windows ([#&#8203;1001](https://github.com/pydantic/pydantic-settings/pull/1001)). - An empty JSON config file is treated as an empty mapping instead of crashing ([#&#8203;947](https://github.com/pydantic/pydantic-settings/pull/947)), matching YAML and TOML. - TOML table headers: `~` paths are now expanded when checking that the file exists ([#&#8203;1034](https://github.com/pydantic/pydantic-settings/pull/1034)), and an explicit `toml_table_header=()` now overrides the model config to read the file root ([#&#8203;1027](https://github.com/pydantic/pydantic-settings/pull/1027)). **Cloud sources** - Azure Key Vault and GCP Secret Manager now honor `env_parse_none_str` ([#&#8203;1019](https://github.com/pydantic/pydantic-settings/pull/1019), [#&#8203;1040](https://github.com/pydantic/pydantic-settings/pull/1040)). - Azure Key Vault: `dash_to_underscore=True` now works for nested model fields ([#&#8203;1025](https://github.com/pydantic/pydantic-settings/pull/1025)). - `NestedSecretsSettingsSource` now validates its specific constructor arguments ([#&#8203;975](https://github.com/pydantic/pydantic-settings/pull/975)). - `DotenvFiltering` is exported from `pydantic_settings.sources.types` ([#&#8203;944](https://github.com/pydantic/pydantic-settings/pull/944)). ##### Documentation - Document that runtime validation arguments (`strict`, `extra`, `context`) passed to `model_validate()` are not applied to `BaseSettings`, and give a workaround ([#&#8203;1017](https://github.com/pydantic/pydantic-settings/pull/1017)). - Explain why `extra='forbid'` doesn't reject misspelled top-level env vars ([#&#8203;986](https://github.com/pydantic/pydantic-settings/pull/986)). - Clarify alias plus nested model env lookup with `populate_by_name` ([#&#8203;933](https://github.com/pydantic/pydantic-settings/pull/933)), and add a nested model example for `env_prefix_target` ([#&#8203;953](https://github.com/pydantic/pydantic-settings/pull/953)). - Fix assorted typos ([#&#8203;942](https://github.com/pydantic/pydantic-settings/pull/942), [#&#8203;964](https://github.com/pydantic/pydantic-settings/pull/964)). <details> <summary><b>All changes</b> (including dependency bumps and internal maintenance)</summary> #### What's Changed * Bump boto3 from 1.43.60 to 1.43.66 in the python-packages group by @&#8203;dependabot[bot] in https://github.com/pydantic/pydantic-settings/pull/936 * docs: clarify alias + nested model env lookup with populate_by_name by @&#8203;pranjalm37 in https://github.com/pydantic/pydantic-settings/pull/933 * lint: enable flake8-bugbear and fix the issues it found by @&#8203;hramezani in https://github.com/pydantic/pydantic-settings/pull/931 * Bump the python-packages group with 6 updates by @&#8203;dependabot[bot] in https://github.com/pydantic/pydantic-settings/pull/943 * docs: improve ENV_FILE_SENTINEL comment phrasing in sources/types.py by @&#8203;aoright in https://github.com/pydantic/pydantic-settings/pull/942 * fix(types): include DotenvFiltering in __all__ in sources.types by @&#8203;aoright in https://github.com/pydantic/pydantic-settings/pull/944 * Add env_file_depth for parent directory env file lookup by @&#8203;dmi03 in https://github.com/pydantic/pydantic-settings/pull/940 * Add an AWS Systems Manager Parameter Store settings source by @&#8203;ChrisJr404 in https://github.com/pydantic/pydantic-settings/pull/941 * fix: use self.cli_prefix instead of cli_prefix in CliSettingsSource constructor by @&#8203;RomainL972 in https://github.com/pydantic/pydantic-settings/pull/945 * Bump the python-packages group with 6 updates by @&#8203;dependabot[bot] in https://github.com/pydantic/pydantic-settings/pull/948 * fix: treat empty JSON config file as empty mapping instead of crashing by @&#8203;sneha4175 in https://github.com/pydantic/pydantic-settings/pull/947 * Expand ruff rule selection by @&#8203;hramezani in https://github.com/pydantic/pydantic-settings/pull/950 * Enable ruff's flake8-return (RET) rules by @&#8203;hramezani in https://github.com/pydantic/pydantic-settings/pull/951 * docs: add nested model alias example for env_prefix_target by @&#8203;MohammedAlkindi in https://github.com/pydantic/pydantic-settings/pull/953 * Add cached settings instances by @&#8203;tiangolo in https://github.com/pydantic/pydantic-settings/pull/952 * Bump the github-actions group with 3 updates by @&#8203;dependabot[bot] in https://github.com/pydantic/pydantic-settings/pull/954 * Bump the python-packages group with 4 updates by @&#8203;dependabot[bot] in https://github.com/pydantic/pydantic-settings/pull/957 * Add CliVariadicArg for named variadic CLI options by @&#8203;gyanu2507 in https://github.com/pydantic/pydantic-settings/pull/949 * Fix CliVariadicArg empty-value handling for named options by @&#8203;hramezani in https://github.com/pydantic/pydantic-settings/pull/958 * fix: read JSON and YAML config as UTF-8, not the locale encoding by @&#8203;MohammedAlkindi in https://github.com/pydantic/pydantic-settings/pull/955 * Reach 100% test coverage by @&#8203;hramezani in https://github.com/pydantic/pydantic-settings/pull/963 * docs: fix three small wording/typo errors by @&#8203;simpleqt in https://github.com/pydantic/pydantic-settings/pull/964 * fix: strip a case-normalized env_prefix from dotenv extras by @&#8203;MohammedAlkindi in https://github.com/pydantic/pydantic-settings/pull/959 * fix: slice the case-normalized prefix in dotenv match_prefix by @&#8203;hramezani in https://github.com/pydantic/pydantic-settings/pull/968 * Bump the python-packages group with 3 updates by @&#8203;dependabot[bot] in https://github.com/pydantic/pydantic-settings/pull/966 * fix: address CVE-2026-28684 in python-dotenv dependency by @&#8203;jmartens in https://github.com/pydantic/pydantic-settings/pull/971 * build(deps): bump the python-packages group with 3 updates by @&#8203;dependabot[bot] in https://github.com/pydantic/pydantic-settings/pull/978 * Verify `NestedSecretsSettingsSource` specific arguments by @&#8203;makukha in https://github.com/pydantic/pydantic-settings/pull/975 * Fix abstract Set annotations not being treated as complex by @&#8203;mmdverse in https://github.com/pydantic/pydantic-settings/pull/973 * Fix CLI append-action detection for collection subtypes by @&#8203;mmdverse in https://github.com/pydantic/pydantic-settings/pull/972 * Honor cli_exit_on_error=False in CliSubCommand parsers by @&#8203;glaziermag in https://github.com/pydantic/pydantic-settings/pull/977 * Preserve CliVariadicArg values in CliApp.serialize argparse/env styles by @&#8203;glaziermag in https://github.com/pydantic/pydantic-settings/pull/976 * Avoid mutating field metadata when resolving type aliases by @&#8203;jakezwang in https://github.com/pydantic/pydantic-settings/pull/979 * fix: bare AliasPath complexity keyed off name length, not path length by @&#8203;ishan-1010 in https://github.com/pydantic/pydantic-settings/pull/980 * docs: clarify extra validation for environment variables by @&#8203;hulkbig in https://github.com/pydantic/pydantic-settings/pull/986 * build(deps): bump the python-packages group with 2 updates by @&#8203;dependabot[bot] in https://github.com/pydantic/pydantic-settings/pull/990 * Preserve explicit None values in CLI serialization by @&#8203;mtcd001-tech in https://github.com/pydantic/pydantic-settings/pull/981 * Make `CliApp.serialize` output parseable for enum and non-JSON values by @&#8203;SulimanAbdulrazzaq in https://github.com/pydantic/pydantic-settings/pull/988 * Preserve CliSubCommand alias case with case_sensitive=False by @&#8203;glaziermag in https://github.com/pydantic/pydantic-settings/pull/989 * Fix Path.is_mount type-checking error on win32 platform by @&#8203;truecallerabreham in https://github.com/pydantic/pydantic-settings/pull/982 * build(deps): bump astral-sh/setup-uv from 10.0.1 to 10.2.0 in the github-actions group by @&#8203;dependabot[bot] in https://github.com/pydantic/pydantic-settings/pull/998 * build(deps): bump the python-packages group with 3 updates by @&#8203;dependabot[bot] in https://github.com/pydantic/pydantic-settings/pull/999 * Fix `CliApp.serialize` for models with `CliUnknownArgs` fields by @&#8203;truecallerabreham in https://github.com/pydantic/pydantic-settings/pull/992 * Honor `secrets_case_sensitive` on Windows by overriding `_load_env_vars` by @&#8203;hramezani in https://github.com/pydantic/pydantic-settings/pull/1001 * Fix empty JSON arrays in CLI list arguments by @&#8203;hansu650 in https://github.com/pydantic/pydantic-settings/pull/994 * Bump `samuelcolvin/check-python-version` action to v5.1 by @&#8203;Viicos in https://github.com/pydantic/pydantic-settings/pull/1014 * build(deps): bump the python-packages group with 7 updates by @&#8203;dependabot[bot] in https://github.com/pydantic/pydantic-settings/pull/1015 * Only skip partial updates for discriminated unions selecting another type by @&#8203;SammyTourani in https://github.com/pydantic/pydantic-settings/pull/997 * fix: handle bare typing.Dict in EnvSettingsSource.next_field (#&#8203;1007) by @&#8203;DawnofGenX in https://github.com/pydantic/pydantic-settings/pull/1009 * Apply case-insensitive field matching to nested pydantic dataclasses by @&#8203;sungbin1015 in https://github.com/pydantic/pydantic-settings/pull/1010 * Document that runtime validation arguments are not applied to BaseSettings by @&#8203;hramezani in https://github.com/pydantic/pydantic-settings/pull/1017 * Fix named union alias parsing in environment sources by @&#8203;hulkbig in https://github.com/pydantic/pydantic-settings/pull/1006 * Drop support for Python 3.10 by @&#8203;hramezani in https://github.com/pydantic/pydantic-settings/pull/1003 * Add support for Python 3.15 by @&#8203;hramezani in https://github.com/pydantic/pydantic-settings/pull/1026 * Give each CliUnknownArgs field only its own parser leftovers by @&#8203;fhgffy in https://github.com/pydantic/pydantic-settings/pull/1004 * Preserve empty containers in CLI serialization by @&#8203;fallintoplace in https://github.com/pydantic/pydantic-settings/pull/1008 * Honor env_parse_none_str for Azure Key Vault secrets by @&#8203;fhgffy in https://github.com/pydantic/pydantic-settings/pull/1019 * Fix nested Azure Key Vault dash translation by @&#8203;goudan789 in https://github.com/pydantic/pydantic-settings/pull/1025 * Support pydantic 2.14 by @&#8203;hramezani in https://github.com/pydantic/pydantic-settings/pull/1029 * Read field names when `validate_by_alias=False` on pydantic 2.14 by @&#8203;maharanay22 in https://github.com/pydantic/pydantic-settings/pull/1022 * Ignore aliases in every source when `validate_by_alias=False` by @&#8203;hramezani in https://github.com/pydantic/pydantic-settings/pull/1033 * Honor explicit empty TOML table header overrides by @&#8203;xiehuanyi in https://github.com/pydantic/pydantic-settings/pull/1027 * Fix CLI parsing for named collection type aliases by @&#8203;JackyHsu-X in https://github.com/pydantic/pydantic-settings/pull/1032 * Fix JSON decoding for optional named union aliases by @&#8203;hulkbig in https://github.com/pydantic/pydantic-settings/pull/1030 * Decode optional Annotated named union aliases by @&#8203;hramezani in https://github.com/pydantic/pydantic-settings/pull/1041 * Expand home paths when checking TOML table headers by @&#8203;JunaidAhamed-7777 in https://github.com/pydantic/pydantic-settings/pull/1034 * Fix config file and CLI values being ignored when alias differs from validation_alias by @&#8203;hzmsh in https://github.com/pydantic/pydantic-settings/pull/1038 * Honor env_parse_none_str for GCP Secret Manager by @&#8203;Ganesh1729-ui in https://github.com/pydantic/pydantic-settings/pull/1040 * Simplify alias resolution branch and test alias with AliasChoices/AliasPath by @&#8203;hramezani in https://github.com/pydantic/pydantic-settings/pull/1042 * Keep case of non-option CLI args when case_sensitive=False by @&#8203;hzmsh in https://github.com/pydantic/pydantic-settings/pull/1036 * Prepare release 2.16.0 by @&#8203;hramezani in https://github.com/pydantic/pydantic-settings/pull/1043 #### New Contributors * @&#8203;pranjalm37 made their first contribution in https://github.com/pydantic/pydantic-settings/pull/933 * @&#8203;aoright made their first contribution in https://github.com/pydantic/pydantic-settings/pull/942 * @&#8203;dmi03 made their first contribution in https://github.com/pydantic/pydantic-settings/pull/940 * @&#8203;ChrisJr404 made their first contribution in https://github.com/pydantic/pydantic-settings/pull/941 * @&#8203;RomainL972 made their first contribution in https://github.com/pydantic/pydantic-settings/pull/945 * @&#8203;sneha4175 made their first contribution in https://github.com/pydantic/pydantic-settings/pull/947 * @&#8203;MohammedAlkindi made their first contribution in https://github.com/pydantic/pydantic-settings/pull/953 * @&#8203;tiangolo made their first contribution in https://github.com/pydantic/pydantic-settings/pull/952 * @&#8203;gyanu2507 made their first contribution in https://github.com/pydantic/pydantic-settings/pull/949 * @&#8203;simpleqt made their first contribution in https://github.com/pydantic/pydantic-settings/pull/964 * @&#8203;jmartens made their first contribution in https://github.com/pydantic/pydantic-settings/pull/971 * @&#8203;mmdverse made their first contribution in https://github.com/pydantic/pydantic-settings/pull/973 * @&#8203;glaziermag made their first contribution in https://github.com/pydantic/pydantic-settings/pull/977 * @&#8203;jakezwang made their first contribution in https://github.com/pydantic/pydantic-settings/pull/979 * @&#8203;ishan-1010 made their first contribution in https://github.com/pydantic/pydantic-settings/pull/980 * @&#8203;hulkbig made their first contribution in https://github.com/pydantic/pydantic-settings/pull/986 * @&#8203;mtcd001-tech made their first contribution in https://github.com/pydantic/pydantic-settings/pull/981 * @&#8203;SulimanAbdulrazzaq made their first contribution in https://github.com/pydantic/pydantic-settings/pull/988 * @&#8203;truecallerabreham made their first contribution in https://github.com/pydantic/pydantic-settings/pull/982 * @&#8203;hansu650 made their first contribution in https://github.com/pydantic/pydantic-settings/pull/994 * @&#8203;SammyTourani made their first contribution in https://github.com/pydantic/pydantic-settings/pull/997 * @&#8203;DawnofGenX made their first contribution in https://github.com/pydantic/pydantic-settings/pull/1009 * @&#8203;sungbin1015 made their first contribution in https://github.com/pydantic/pydantic-settings/pull/1010 * @&#8203;fhgffy made their first contribution in https://github.com/pydantic/pydantic-settings/pull/1004 * @&#8203;fallintoplace made their first contribution in https://github.com/pydantic/pydantic-settings/pull/1008 * @&#8203;goudan789 made their first contribution in https://github.com/pydantic/pydantic-settings/pull/1025 * @&#8203;maharanay22 made their first contribution in https://github.com/pydantic/pydantic-settings/pull/1022 * @&#8203;xiehuanyi made their first contribution in https://github.com/pydantic/pydantic-settings/pull/1027 * @&#8203;JackyHsu-X made their first contribution in https://github.com/pydantic/pydantic-settings/pull/1032 * @&#8203;JunaidAhamed-7777 made their first contribution in https://github.com/pydantic/pydantic-settings/pull/1034 * @&#8203;hzmsh made their first contribution in https://github.com/pydantic/pydantic-settings/pull/1038 * @&#8203;Ganesh1729-ui made their first contribution in https://github.com/pydantic/pydantic-settings/pull/1040 **Full Changelog**: <https://github.com/pydantic/pydantic-settings/compare/v2.15.0...v2.16.0> </details> ### [`v2.15.0`](https://github.com/pydantic/pydantic-settings/releases/tag/v2.15.0) [Compare Source](https://github.com/pydantic/pydantic-settings/compare/v2.14.2...v2.15.0) #### Highlights ##### Behavior changes - **`case_sensitive` now applies to init kwargs and config-file sources** ([#&#8203;900](https://github.com/pydantic/pydantic-settings/pull/900)). `InitSettingsSource` and the JSON/TOML/YAML config sources previously ignored `case_sensitive`. Since it defaults to `False`, **case-insensitive matching is now the default** for these sources — e.g. `Settings(TeSt=...)` now populates a `test` field where it previously did not. Nested keys are still matched case-sensitively. - **Fields with unresolved forward references now emit a warning** ([#&#8203;901](https://github.com/pydantic/pydantic-settings/pull/901)). Settings sources can silently fail to resolve such fields; they now raise `IncompleteFieldDefinitionWarning` telling you to call `model_rebuild()`. If you have `filterwarnings = error` configured, this may surface as a new failure. - **Non-JSON env values for strict fields now raise `ValidationError`** ([#&#8203;926](https://github.com/pydantic/pydantic-settings/pull/926)) instead of a less specific error. ##### New features - **Show environment variable names in CLI help** via `cli_show_env_vars=True` ([#&#8203;860](https://github.com/pydantic/pydantic-settings/pull/860)), so generated `--help` output doubles as configuration documentation. - **`PYDANTIC_SETTINGS_DEBUG` for debugging settings resolution** ([#&#8203;906](https://github.com/pydantic/pydantic-settings/pull/906), [#&#8203;913](https://github.com/pydantic/pydantic-settings/pull/913)). Set it to a truthy value with `DEBUG` logging enabled to see each source's contribution in priority order, which source won for each value, and which `env_file`/secret files were probed, loaded, or skipped — the long-standing "why isn't my `.env` being picked up?" question. - **`toml_table_header` for regular TOML files** ([#&#8203;882](https://github.com/pydantic/pydantic-settings/pull/882), [#&#8203;886](https://github.com/pydantic/pydantic-settings/pull/886), [#&#8203;887](https://github.com/pydantic/pydantic-settings/pull/887)), letting you root settings at a nested table in any TOML file, not just `pyproject.toml`. - **`Traversable` support for JSON/TOML/YAML file sources** ([#&#8203;902](https://github.com/pydantic/pydantic-settings/pull/902)), so you can load config packaged inside a distribution — including files inside a zip or wheel — via `importlib.resources.files(...)` without casting to `Path`. - **GCP: `project_id` can come from an earlier settings source** ([#&#8203;878](https://github.com/pydantic/pydantic-settings/pull/878)), rather than only from the constructor or `GOOGLE_CLOUD_PROJECT`. ##### Bug fixes - Fix env vars not loading on Windows with `case_sensitive=True` ([#&#8203;894](https://github.com/pydantic/pydantic-settings/pull/894)). Windows upper-cases `os.environ` keys, so fields raised `Field required` instead of picking up their values. - Read secret files as UTF-8 instead of the platform locale encoding ([#&#8203;917](https://github.com/pydantic/pydantic-settings/pull/917)). On Windows code pages such as cp1252 this silently corrupted non-ASCII secrets. - Fix `AliasPath` on nested model fields not JSON-decoding env values ([#&#8203;898](https://github.com/pydantic/pydantic-settings/pull/898)). - Fix case-insensitive matching for **optional** nested models ([#&#8203;905](https://github.com/pydantic/pydantic-settings/pull/905)). - Fix dotenv extras being wrongly claimed by a complex field sharing a name prefix ([#&#8203;912](https://github.com/pydantic/pydantic-settings/pull/912)) — e.g. `dbx_token` being swallowed by a `db: dict` field. - Fix `nested_model_default_partial_update=True` corrupting discriminated unions ([#&#8203;876](https://github.com/pydantic/pydantic-settings/pull/876)). - Fix `Secret` subclasses crashing when loaded from the environment ([#&#8203;920](https://github.com/pydantic/pydantic-settings/pull/920)). - Fix enum names not parsing through nested annotations such as `Optional[Annotated[MyEnum, ...]]` with `env_parse_enums=True` ([#&#8203;910](https://github.com/pydantic/pydantic-settings/pull/910)). - An empty `yaml_config_section` now falls back to defaults instead of raising `AttributeError: 'NoneType' object has no attribute 'keys'` ([#&#8203;914](https://github.com/pydantic/pydantic-settings/pull/914)). - `NestedSecretsSettingsSource` no longer follows symlinks pointing outside `secrets_dir` ([#&#8203;889](https://github.com/pydantic/pydantic-settings/pull/889)). - GCP: skip the `list_secrets` call when `case_sensitive=True` ([#&#8203;862](https://github.com/pydantic/pydantic-settings/pull/862)), lowering the required IAM permissions to just `roles/secretmanager.secretAccessor`. - AWS: `types-boto3[secretsmanager]` is no longer required at runtime ([#&#8203;880](https://github.com/pydantic/pydantic-settings/pull/880)). ##### Documentation - Document JSON parsing of complex env values, plus a comma-separated-values recipe ([#&#8203;919](https://github.com/pydantic/pydantic-settings/pull/919)). - Recommend an async settings loading pattern ([#&#8203;908](https://github.com/pydantic/pydantic-settings/pull/908)). - Clarify behavior when an unprefixed value is present in a dotenv file ([#&#8203;895](https://github.com/pydantic/pydantic-settings/pull/895)). - Clarify environment variable helper descriptions ([#&#8203;867](https://github.com/pydantic/pydantic-settings/pull/867)) and fix assorted typos ([#&#8203;904](https://github.com/pydantic/pydantic-settings/pull/904)). <details> <summary><b>All changes</b> (including dependency bumps and internal maintenance)</summary> #### What's Changed * Update documentation link for Pydantic settings by @&#8203;hramezani in https://github.com/pydantic/pydantic-settings/pull/863 * Bump the python-packages group with 4 updates by @&#8203;dependabot[bot] in https://github.com/pydantic/pydantic-settings/pull/865 * docs: clarify environment variable helper descriptions by @&#8203;vip892766gma in https://github.com/pydantic/pydantic-settings/pull/867 * Bump the python-packages group with 4 updates by @&#8203;dependabot[bot] in https://github.com/pydantic/pydantic-settings/pull/870 * Bump the python-packages group with 4 updates by @&#8203;dependabot[bot] in https://github.com/pydantic/pydantic-settings/pull/875 * Skip list_secrets call when case_sensitive=True by @&#8203;ecerulm in https://github.com/pydantic/pydantic-settings/pull/862 * GoogleSecretManagerSettingsSource: read project_id from previous sources by @&#8203;ecerulm in https://github.com/pydantic/pydantic-settings/pull/878 * Bump the python-packages group with 3 updates by @&#8203;dependabot[bot] in https://github.com/pydantic/pydantic-settings/pull/883 * fix: move SecretsManagerClient type import under TYPE_CHECKING by @&#8203;gavin913-lss in https://github.com/pydantic/pydantic-settings/pull/880 * Skip partial update merging for discriminated union fields by @&#8203;hramezani in https://github.com/pydantic/pydantic-settings/pull/876 * Support using a table header as root when reading a TOML file by @&#8203;whyscream in https://github.com/pydantic/pydantic-settings/pull/882 * Bump the python-packages group with 4 updates by @&#8203;dependabot[bot] in https://github.com/pydantic/pydantic-settings/pull/885 * Don't complain about missing table headers in a TOML file that isn't there by @&#8203;whyscream in https://github.com/pydantic/pydantic-settings/pull/886 * Address issues in toml table header implementation by @&#8203;whyscream in https://github.com/pydantic/pydantic-settings/pull/887 * Bump the python-packages group with 2 updates by @&#8203;dependabot[bot] in https://github.com/pydantic/pydantic-settings/pull/888 * Prevent NestedSecretsSettingsSource from following symlinks outside secrets_dir by @&#8203;hramezani in https://github.com/pydantic/pydantic-settings/pull/889 * Add 'Part of the Pydantic Stack' footer to README by @&#8203;strawgate in https://github.com/pydantic/pydantic-settings/pull/891 * Bump the python-packages group with 3 updates by @&#8203;dependabot[bot] in https://github.com/pydantic/pydantic-settings/pull/893 * Add support for showing environment variable names in CLI help text by @&#8203;brad-alexander in https://github.com/pydantic/pydantic-settings/pull/860 * Fix loading env vars on Windows with case_sensitive=True by @&#8203;hramezani in https://github.com/pydantic/pydantic-settings/pull/894 * Bump the github-actions group with 3 updates by @&#8203;dependabot[bot] in https://github.com/pydantic/pydantic-settings/pull/896 * Bump the python-packages group with 3 updates by @&#8203;dependabot[bot] in https://github.com/pydantic/pydantic-settings/pull/897 * Add explicit callout for the case where the unprefixed value is in dotenv by @&#8203;martinky24 in https://github.com/pydantic/pydantic-settings/pull/895 * Fix AliasPath on nested model fields not decoding env values (#&#8203;670) by @&#8203;hramezani in https://github.com/pydantic/pydantic-settings/pull/898 * Support case_sensitive in InitSettingsSource and config file sources by @&#8203;hramezani in https://github.com/pydantic/pydantic-settings/pull/900 * Warn when using fields not fully resolved at instantiation by @&#8203;Viicos in https://github.com/pydantic/pydantic-settings/pull/901 * Support Traversable for json/toml/yaml config file sources (#&#8203;299) by @&#8203;hramezani in https://github.com/pydantic/pydantic-settings/pull/902 * docs: fix typos in docs and source comments by @&#8203;maxtaran2010 in https://github.com/pydantic/pydantic-settings/pull/904 * Apply case-insensitive field matching to optional nested models (#&#8203;903) by @&#8203;hramezani in https://github.com/pydantic/pydantic-settings/pull/905 * Bump boto3 from 1.43.36 to 1.43.40 in the python-packages group by @&#8203;dependabot[bot] in https://github.com/pydantic/pydantic-settings/pull/907 * Add PYDANTIC_SETTINGS_DEBUG for debugging settings sources (#&#8203;538) by @&#8203;hramezani in https://github.com/pydantic/pydantic-settings/pull/906 * docs: recommend async settings loading pattern by @&#8203;w3lld1 in https://github.com/pydantic/pydantic-settings/pull/908 * fix: parse enum names through nested annotations by @&#8203;Sanjays2402 in https://github.com/pydantic/pydantic-settings/pull/910 * Fix dotenv extras being claimed by complex fields sharing a name prefix by @&#8203;ritsth in https://github.com/pydantic/pydantic-settings/pull/912 * Add debug logging for env_file and secret file resolution by @&#8203;hramezani in https://github.com/pydantic/pydantic-settings/pull/913 * docs: document JSON parsing of complex env values + comma-separated recipe by @&#8203;hrithvikakb in https://github.com/pydantic/pydantic-settings/pull/919 * fix: coerce empty yaml_config_section to an empty mapping instead of crashing by @&#8203;chuenchen309 in https://github.com/pydantic/pydantic-settings/pull/914 * Bump the python-packages group with 3 updates by @&#8203;dependabot[bot] in https://github.com/pydantic/pydantic-settings/pull/915 * fix: read secret files as UTF-8 instead of the locale encoding by @&#8203;dchaudhari7177 in https://github.com/pydantic/pydantic-settings/pull/917 * Bump the python-packages group with 4 updates by @&#8203;dependabot[bot] in https://github.com/pydantic/pydantic-settings/pull/921 * Bump the github-actions group with 4 updates by @&#8203;dependabot[bot] in https://github.com/pydantic/pydantic-settings/pull/925 * Bump the python-packages group with 4 updates by @&#8203;dependabot[bot] in https://github.com/pydantic/pydantic-settings/pull/924 * fix: treat Secret subclasses as non-complex fields (#&#8203;716) by @&#8203;Rony-ZenAlden in https://github.com/pydantic/pydantic-settings/pull/920 * fix: raise ValidationError for non-JSON env values on strict fields by @&#8203;shuvamk in https://github.com/pydantic/pydantic-settings/pull/926 * test: move function-local imports to the top of test modules by @&#8203;hramezani in https://github.com/pydantic/pydantic-settings/pull/927 * Bump the python-packages group with 4 updates by @&#8203;dependabot[bot] in https://github.com/pydantic/pydantic-settings/pull/929 * Prepare release 2.15.0 by @&#8203;hramezani in https://github.com/pydantic/pydantic-settings/pull/930 #### New Contributors * @&#8203;vip892766gma made their first contribution in https://github.com/pydantic/pydantic-settings/pull/867 * @&#8203;ecerulm made their first contribution in https://github.com/pydantic/pydantic-settings/pull/862 * @&#8203;gavin913-lss made their first contribution in https://github.com/pydantic/pydantic-settings/pull/880 * @&#8203;whyscream made their first contribution in https://github.com/pydantic/pydantic-settings/pull/882 * @&#8203;strawgate made their first contribution in https://github.com/pydantic/pydantic-settings/pull/891 * @&#8203;brad-alexander made their first contribution in https://github.com/pydantic/pydantic-settings/pull/860 * @&#8203;martinky24 made their first contribution in https://github.com/pydantic/pydantic-settings/pull/895 * @&#8203;maxtaran2010 made their first contribution in https://github.com/pydantic/pydantic-settings/pull/904 * @&#8203;w3lld1 made their first contribution in https://github.com/pydantic/pydantic-settings/pull/908 * @&#8203;Sanjays2402 made their first contribution in https://github.com/pydantic/pydantic-settings/pull/910 * @&#8203;ritsth made their first contribution in https://github.com/pydantic/pydantic-settings/pull/912 * @&#8203;hrithvikakb made their first contribution in https://github.com/pydantic/pydantic-settings/pull/919 * @&#8203;chuenchen309 made their first contribution in https://github.com/pydantic/pydantic-settings/pull/914 * @&#8203;dchaudhari7177 made their first contribution in https://github.com/pydantic/pydantic-settings/pull/917 * @&#8203;Rony-ZenAlden made their first contribution in https://github.com/pydantic/pydantic-settings/pull/920 * @&#8203;shuvamk made their first contribution in https://github.com/pydantic/pydantic-settings/pull/926 **Full Changelog**: <https://github.com/pydantic/pydantic-settings/compare/v2.14.1...v2.15.0> </details> </details> <details> <summary>pytest-dev/pytest (pytest)</summary> ### [`v9.2.0`](https://github.com/pytest-dev/pytest/releases/tag/9.2.0) [Compare Source](https://github.com/pytest-dev/pytest/compare/9.1.1...9.2.0) ### pytest 9.2.0 (2026-10-27) #### Removals and backward incompatible breaking changes - [#&#8203;14716](https://github.com/pytest-dev/pytest/issues/14716): `-c` now raises a usage error for a path that does not exist, is a directory, or is in a format pytest has no loader for. Such paths were previously either ignored or reported as an unhandled `FileNotFoundError`. - [#&#8203;8593](https://github.com/pytest-dev/pytest/issues/8593): The `indirect`, `ids` and `scope` arguments of `Metafunc.parametrize() <pytest.Metafunc.parametrize>` -- and therefore of `@pytest.mark.parametrize <pytest.mark.parametrize ref>` -- are now keyword-only. Passing them positionally was a common source of confusing errors, e.g. `parametrize("arg1", "arg2", [(1, 2)])` made the argvalues land in `indirect` and failed with `indirect fixture '(1, 2)' doesn't exist`; such mistakes now fail with an understandable `TypeError`. The type annotations have always declared these arguments as keyword-only. - [#&#8203;993](https://github.com/pytest-dev/pytest/issues/993): Plugin import failures at startup are now reported and classified instead of escaping as a raw traceback with the accidental exit code `1`: - a plugin that cannot be found -- via `-p`, `pytest_plugins` or `PYTEST_PLUGINS` -- exits with `pytest.ExitCode` `USAGE_ERROR` (`4`), like a `conftest.py` that fails to import; - a plugin that is found but raises while importing -- including a broken `pytest11` entry point or a missing plugin dependency -- exits with `pytest.ExitCode` `INTERNAL_ERROR` (`3`), with the traceback preserved. `pytest.main` now returns these codes instead of raising `ImportError`. Also fixed an `IndexError` from pytest's own internals when the plugin raised an exception with no arguments. #### Deprecations (removal in next major release) - [#&#8203;14742](https://github.com/pytest-dev/pytest/issues/14742): The private `_pytest.python.CallSpec2` name has been renamed to `CallSpec`. The old `CallSpec2` alias remains available for now and will be removed in pytest 10 or 11. - [#&#8203;14755](https://github.com/pytest-dev/pytest/issues/14755): Schedule *yield\_fixture* decorator for removal in pytest 10 or 11. - [#&#8203;14774](https://github.com/pytest-dev/pytest/issues/14774): Similarly to the deprecation of class-scoped fixtures defined as instance methods in pytest 9.1, *all* higher-scoped fixtures (`module`, `package`, and `session`) defined as instance methods are now deprecated. They suffer from the same issue the original deprecation only fixed for class-scoped fixtures, see `10819` and `14011`. - [#&#8203;14808](https://github.com/pytest-dev/pytest/issues/14808): Passing a non-string value to a `string`-typed ini option now emits a `pytest.PytestRemovedIn10Warning`. This affects `[tool.pytest.ini_options]` in `pyproject.toml`. In pytest 10 this will raise a `TypeError`, matching the behavior of the corresponding TOML config path. - [#&#8203;7323](https://github.com/pytest-dev/pytest/issues/7323): Passing `bytes` to `TerminalReporter.write_line()` is now deprecated, pass a `str` instead. #### New features - [#&#8203;14743](https://github.com/pytest-dev/pytest/issues/14743): <span class="title-ref">Full diff:</span> now contains a legend explaining the <span class="title-ref">+</span> & <span class="title-ref">-</span> symbols in diff output. - [#&#8203;2781](https://github.com/pytest-dev/pytest/issues/2781): When `strict_markers` is enabled, marker names used in `-m` expressions are now validated against registered markers. - [#&#8203;6881](https://github.com/pytest-dev/pytest/issues/6881): Added the `parametrize_long_str_id_strategy` configuration option to control how long `str`/`bytes` parameter values are handled in auto-generated test IDs. Explicit IDs set via `ids=[...]` or `pytest.param(..., id=...)` are not affected. Available strategies: `short` (default, values over 100 chars fall back to `argname+index`), `sha256` (SHA-256 hex digest), `legacy` (keep full value), and `disallow` (error requesting explicit IDs). #### Improvements in existing functionality - [#&#8203;10745](https://github.com/pytest-dev/pytest/issues/10745): A `RecursionError` whose recursion origin cannot be located now shows only the first and last 10 stack frames, matching what pytest already did when locating the origin failed outright. Previously the full traceback -- often around a thousand near-identical frames -- was rendered, which was both slow and unreadable. Pass `--full-trace` to see every frame. - [#&#8203;10745](https://github.com/pytest-dev/pytest/issues/10745): The line numbers of a module's statements are now computed once per traceback instead of once per traceback entry, which noticeably speeds up rendering failures raised from large test modules. - [#&#8203;11418](https://github.com/pytest-dev/pytest/issues/11418): The cached rewritten modules in `__pycache__` are now invalidated by a hash of the source instead of its modification time, using the checked-hash pyc format from `552`. Timestamps make the cache useless wherever source files get fresh modification times, most notably in CI: a checkout gives every file a new mtime, so a restored cache is discarded in full and every test module is rewritten again. Hashing the source costs roughly 15 microseconds per file and makes the cache survive that. Existing timestamp based caches are ignored and rewritten once. - [#&#8203;12624](https://github.com/pytest-dev/pytest/issues/12624): The `pytest_plugins` variable and the `PYTEST_PLUGINS` environment variable now also accept entry point names of installed plugins (e.g. `xdist`), in addition to importable module names, matching the behavior of the `-p` command-line option. As part of this change, plugins specified by entry point name through these mechanisms are now also listed in the `plugins:` line of the terminal header (`12615`). Based on the original implementation by Marcel Telka in `12616`. - [#&#8203;12697](https://github.com/pytest-dev/pytest/issues/12697): Warnings emitted while importing plugins through `-p`, `PYTEST_PLUGINS`, or entry point autoloading are now captured, filtered, and reported like other warnings. - [#&#8203;12860](https://github.com/pytest-dev/pytest/issues/12860): Assertion diffs for `dict.items()` and `dict.keys()` comparisons (`>=`, `<=`, `>`, `<`, `==`) now show which items are missing, the same way set comparisons do. - [#&#8203;13354](https://github.com/pytest-dev/pytest/issues/13354): `Node.get_closest_marker <_pytest.nodes.Node.get_closest_marker>` now also accepts a `~pytest.MarkDecorator` as its `default`, for example `item.get_closest_marker("foo", pytest.mark.foo(1))`, and returns the wrapped `~pytest.Mark`. Previously the only way to build a `default` was to instantiate `~pytest.Mark` directly, which is private and warns. - [#&#8203;13369](https://github.com/pytest-dev/pytest/issues/13369): Improved the error from `pytest.RunResult.assert_outcomes` when a plugin changes or removes pytest's standard terminal summary, and documented how to isolate output-changing plugins. - [#&#8203;13431](https://github.com/pytest-dev/pytest/issues/13431): Exposed `pytest.ParameterSet` as the type of the return value of `pytest.param()`. This can be used in type annotations and `isinstance` checks. - [#&#8203;13564](https://github.com/pytest-dev/pytest/issues/13564): Issue a warning when fixtures are wrapped with a decorator that prevents correct discovery, including `@classmethod` above `@pytest.fixture` and `@staticmethod` above `@pytest.fixture`. Put `@pytest.fixture` above those decorators on test classes. - [#&#8203;14164](https://github.com/pytest-dev/pytest/issues/14164): Exposed `pytest.Approx` as the type of the return value of `pytest.approx()`. This can be used in type annotations and `isinstance` checks. - [#&#8203;14463](https://github.com/pytest-dev/pytest/issues/14463): Assertion diffs for mappings now match up keys the way the compared mappings match them themselves. Key comparison goes through the mappings' key views instead of plain sets of their keys, so a mapping with its own notion of key equivalence, such as case-insensitive header mappings, no longer reports its common keys as missing on either side. - [#&#8203;14523](https://github.com/pytest-dev/pytest/issues/14523): Large assertion comparison diffs are now built lazily and capped to the truncation budget, so a huge diff is no longer formatted in full just to be truncated. As a consequence, the truncation footer no longer reports the exact number of hidden lines. - [#&#8203;14687](https://github.com/pytest-dev/pytest/issues/14687): The default fd-level output capturing (`--capture=fd`) now skips reading the capture buffer for tests which produce no output, reducing per-test overhead in large test suites. - [#&#8203;14724](https://github.com/pytest-dev/pytest/issues/14724): `--no-summary` now only applies directly to pytest's own summary. The flag no longer skips the `pytest_terminal_summary` hook, so third-party plugins (for example coverage) can still write their terminal summaries. - [#&#8203;14751](https://github.com/pytest-dev/pytest/issues/14751): `parser.addini <pytest.Parser.addini>` now also accepts type expressions for its `type` argument, in addition to the existing string tags: the plain Python types `str`, `bool`, `int`, `float`, a `Literal` of strings, and unions of these (for example `int | str` or `int | Literal["auto"]`). - [#&#8203;14754](https://github.com/pytest-dev/pytest/issues/14754): `pytest.approx()` now rejects infinite relative tolerances for `datetime.timedelta` values with a clear `ValueError` instead of raising `OverflowError`. - [#&#8203;14791](https://github.com/pytest-dev/pytest/issues/14791): The `junit_family`, `junit_logging`, `junit_duration_report`, `console_output_style`, `empty_parameter_set_mark`, `assertion_text_diff_style` and `tmp_path_retention_policy` configuration options are now registered with the set of values they accept: an invalid value now fails with a clean usage error instead of being silently ignored or crashing later, and `pytest --help` lists the accepted values. `config.getini <pytest.Config.getini>` now raises `pytest.UsageError` instead of `TypeError` or `ValueError` when the value read from the configuration file does not match the registered type, so a bad value is always reported as a short usage error message instead of an internal error traceback. Asking for an option name that was never registered still raises `ValueError`. - [#&#8203;15006](https://github.com/pytest-dev/pytest/issues/15006): `pytest.approx` now emits `pytest.PytestApproxDecimalToleranceWarning` when a `rel` or `abs` tolerance is given as a `float` that cannot be represented exactly for a `~decimal.Decimal` comparison, since such a tolerance is widened to the float's exact binary value. - [#&#8203;14675](https://github.com/pytest-dev/pytest/issues/14675), [#&#8203;14953](https://github.com/pytest-dev/pytest/issues/14953), [#&#8203;15153](https://github.com/pytest-dev/pytest/issues/15153), [#&#8203;15132](https://github.com/pytest-dev/pytest/issues/15132): The `truncation_limit_lines`, `truncation_limit_chars`, `max_warnings`, `verbosity_assertions`, `verbosity_test_cases`, `verbosity_subtests`, `tmp_path_retention_count`, `log_level`, `log_cli_level`, `log_file_level`,`log_auto_indent` and `faulthandler_timeout` configuration options now accept native integer (and, for `log_auto_indent`, boolean) values in TOML configuration files, while still accepting strings for backward compatibility. `log_file_mode` now reports invalid values as a usage error. - [#&#8203;15254](https://github.com/pytest-dev/pytest/issues/15254): `tmp_path` and `TempPathFactory.mktemp <pytest.TempPathFactory.mktemp>` no longer list the whole base temporary directory on every call, which made sessions with many temporary directories quadratically slow. Numbers are now handed out from a per-prefix counter, skipping names that already exist. - [#&#8203;4569](https://github.com/pytest-dev/pytest/issues/4569): `Node.add_marker <_pytest.nodes.Node.add_marker>` now stores a `~pytest.Mark` in `node.keywords`, matching what marks applied during collection store. Previously it stored a `~pytest.MarkDecorator`. - [#&#8203;9436](https://github.com/pytest-dev/pytest/issues/9436): Avoided formatting tracebacks for tests marked with `xfail(run=False)`. #### Bug fixes - [#&#8203;10128](https://github.com/pytest-dev/pytest/issues/10128): Configured warning filters now apply to warnings emitted by `pytest_configure` hooks. - [#&#8203;10210](https://github.com/pytest-dev/pytest/issues/10210): `pytest.approx` now raises a `TypeError` for any nested container, not only for one of the same type as its parent. Previously `approx([{"k": 1}])` and `approx({"k": [1]})` were accepted and then compared unequal to every value, silently ignoring the tolerance, while `approx([[1]])` correctly reported that nesting is unsupported. - [#&#8203;10644](https://github.com/pytest-dev/pytest/issues/10644): `monkeypatch.setattr()` no longer leaves a new entry in the instance `__dict__` when it patches an attribute that the instance inherits from its class. Previously `undo()` assigned the inherited value onto the instance, which shadowed the class attribute -- permanently freezing the result for descriptors that resolve dynamically. - [#&#8203;1139](https://github.com/pytest-dev/pytest/issues/1139): Fixed tracebacks showing `???` instead of source lines for code compiled with a filename relative to a directory other than the current working directory -- e.g. compiled Cython modules, when running pytest from a subdirectory of the project root. The source lookup now falls back to searching `sys.path` for such filenames, as the standard `traceback` module does. - [#&#8203;11502](https://github.com/pytest-dev/pytest/issues/11502): The `rootdir` is no longer derived from a configuration file that is not a regular file, such as `--config-file=/dev/null`. - [#&#8203;11783](https://github.com/pytest-dev/pytest/issues/11783): Plugins installed in editable mode (`660`) are marked for assertion rewriting again. Such installs do not record the package's Python files in the distribution metadata, so pytest found nothing to rewrite and assertions inside the plugin lost their introspection. The plugin's entry point is now used to locate the package in that case. - [#&#8203;11933](https://github.com/pytest-dev/pytest/issues/11933): `pytest.warns` no longer re-emits unmatched warnings with `module="warnings"`, which caused `module`-based warning filters to be applied to the wrong warnings. Since `warnings.WarningMessage` does not record the module a warning was emitted with, re-emitted warnings now use the standard `warnings.warn_explicit` default of deriving the module from the warning's filename. - [#&#8203;12175](https://github.com/pytest-dev/pytest/issues/12175): `ExceptionInfo.exconly(tryshort=True) <pytest.ExceptionInfo.exconly>` now strips the `AssertionError:` prefix of failed `assert` statements for `~pytest.ExceptionInfo` objects created by `pytest.raises`, and failures inside `unittest.TestCase.subTest` report the same short crash line as regular tests. - [#&#8203;12223](https://github.com/pytest-dev/pytest/issues/12223): The `message` attribute of `<failure>` and `<error>` elements in `--junitxml` reports is now shortened to whole lines within 500 characters. When something is dropped, it ends with a note pointing to the element text, which still holds the full report. Previously, very verbose assertion output (e.g. with `-vv`) produced attributes tens of thousands of characters long, which some XML parsers fail on. - [#&#8203;12307](https://github.com/pytest-dev/pytest/issues/12307): Fixed truncation of long collections (lists, dicts, sets, etc.) in the "message" part of failed assertions (as in `assert condition, msg`) when using `-vv`: the message now uses the same unlimited repr as the rest of the assertion output, instead of eliding collection elements with `...`. - [#&#8203;12824](https://github.com/pytest-dev/pytest/issues/12824): Custom command-line options now fail with a clear error when their implicit destination conflicts with an existing option, avoiding silent overrides of built-in options such as `-k`. - [#&#8203;13292](https://github.com/pytest-dev/pytest/issues/13292): Fixed a stale rewritten module being used when a test file is modified twice within the same second without changing its size -- the pyc header could only record whole-second timestamps. The cache is now keyed on a hash of the source. - [#&#8203;14036](https://github.com/pytest-dev/pytest/issues/14036): `__tracebackhide__` is now respected in `ExceptionGroup` tracebacks, both for the group itself and for its sub-exceptions. - [#&#8203;14189](https://github.com/pytest-dev/pytest/issues/14189): Nested usage of `caplog.filtering <pytest.LogCaptureFixture.filtering>` no longer removes filters early if they were already present. - [#&#8203;14412](https://github.com/pytest-dev/pytest/issues/14412): Fixed incorrect timing information for subtests and parent tests when `console_output_style = "times"`. - [#&#8203;14445](https://github.com/pytest-dev/pytest/issues/14445): Assertion rewriting no longer evaluates walrus operator (`:=`) expressions more than once, which reported results the test never computed when the expression had side effects. An operand evaluated before a later walrus is now reported with the value it actually saw, so `assert value != identity(value := value.lower())` keeps Python's left-to-right order. - [#&#8203;14552](https://github.com/pytest-dev/pytest/issues/14552): Fixed stale `co_filename` values after a test module or directory is moved. Assertion-rewrite caches are reused when the source hash still matches, and in-memory code objects are pointed at the current path. - [#&#8203;14586](https://github.com/pytest-dev/pytest/issues/14586): Negative values passed to `log_auto_indent` now correctly fall back to no indentation, matching the documented behavior. - [#&#8203;14619](https://github.com/pytest-dev/pytest/issues/14619): Fixed a crash in `pytest.mark.parametrize` when a non-sequence value is passed for a parameter set. It now provides a clear error message during collection. - [#&#8203;14635](https://github.com/pytest-dev/pytest/issues/14635): Fixed fixture resolution failures when specifying multiple test paths on the command line that share common parent directories. Parametrized fixtures defined in a `conftest.py` could be silently dropped depending on the order of the specified paths. - [#&#8203;14637](https://github.com/pytest-dev/pytest/issues/14637): Pytest now correctly skips identical trailing characters in assertion text diffs even when the compared strings differ at the beginning. - [#&#8203;14638](https://github.com/pytest-dev/pytest/issues/14638): Top-level options in `pytest.toml` and `.pytest.toml` files now raise an error instead of being silently ignored when no `[pytest]` table is present. - [#&#8203;14683](https://github.com/pytest-dev/pytest/issues/14683): Fixed a regression in pytest 9.1 where a conftest.py located in the rootdir was no longer visible to tests and doctests collected from *outside* the rootdir (for example when passing a parent directory of the rootdir as a collection argument, or setting `--rootdir` to a subdirectory). As a result, fixtures defined in such a conftest -- including `doctest_namespace` injections -- were not available, causing errors such as `NameError` in doctests. - [#&#8203;14700](https://github.com/pytest-dev/pytest/issues/14700): Fixed an internal error on Python 3.12 when a doctest on a fixture-decorated function was skipped. - [#&#8203;14705](https://github.com/pytest-dev/pytest/issues/14705): TOML configuration files passed via `-c` now also read their configuration from the `[pytest]` table, the one pytest's own configuration files use. The `[tool.pytest]` and `[tool.pytest.ini_options]` tables such files were previously restricted to keep working; using both styles in one file is an error. - [#&#8203;14828](https://github.com/pytest-dev/pytest/issues/14828): Exception groups raised from another exception now print their cause chain only once in the traceback output. - [#&#8203;14864](https://github.com/pytest-dev/pytest/issues/14864): Fixed collection on Windows collecting the whole suite instead of the given path, on file systems which do not support file IDs (`st_ino` is `0` for every file, as seen for example on `sshfs-win`/WinFsp mounts). - [#&#8203;14884](https://github.com/pytest-dev/pytest/issues/14884): `Cache.get()`, `Cache.set()` and `Cache.mkdir()` now reject keys that resolve outside the cache directory, and `--cache-show` ignores glob matches outside it. - [#&#8203;14909](https://github.com/pytest-dev/pytest/issues/14909): Fixed `MonkeyPatch.delattr <pytest.MonkeyPatch.delattr>`, `MonkeyPatch.setitem <pytest.MonkeyPatch.setitem>` and `MonkeyPatch.delitem <pytest.MonkeyPatch.delitem>` recording a stale undo entry when the underlying mutation failed, which could cause spurious errors during teardown. The undo entry is now recorded only after the mutation succeeds, matching the behavior of `MonkeyPatch.setattr <pytest.MonkeyPatch.setattr>`. - [#&#8203;14912](https://github.com/pytest-dev/pytest/issues/14912): `~pytest.PytestWarning` instances defined in `_pytest.deprecated` are no longer reused across `warnings.warn` calls, so warnings raised as errors (e.g. with `-W error`) no longer accumulate stale traceback frames from previous raises. - [#&#8203;14942](https://github.com/pytest-dev/pytest/issues/14942): Fixed a regression in 9.1.0 that made collection very slow (quadratic) when many fixtures are defined with the same name. This can happen particularly when many tests are defined in separate classes which inherit from a base class which defines fixtures (the fixtures are repeated per class). - [#&#8203;15005](https://github.com/pytest-dev/pytest/issues/15005): `pytest.approx` no longer treats finite `~decimal.Decimal` values outside the `float` range (such as `Decimal("1e400")`) as infinite, which made in-tolerance comparisons fail. - [#&#8203;15006](https://github.com/pytest-dev/pytest/issues/15006): Restored the tolerance shown by `pytest.approx` for `~decimal.Decimal` values, which since 9.0 displayed `???` for the default tolerance and reported the raw `rel` ratio instead of the absolute tolerance actually compared against. - [#&#8203;15006](https://github.com/pytest-dev/pytest/issues/15006): The failure message for `pytest.approx` comparisons of `~decimal.Decimal` collections no longer reports `Max absolute difference: -inf`, or crashes for mappings, when the `decimal.FloatOperation` trap is set. - [#&#8203;15006](https://github.com/pytest-dev/pytest/issues/15006): `pytest.approx` no longer raises `AttributeError` when comparing `numpy.ndarray` instances with `object` dtype, such as arrays of `~decimal.Decimal`. - [#&#8203;15032](https://github.com/pytest-dev/pytest/issues/15032): Help texts for command-line options and configuration options now keep their indentation and blank lines. Previously each line was stripped before wrapping, so a wrapped list item was indistinguishable from a new one and blank lines were dropped; configuration option help lost its line breaks entirely. - [#&#8203;15043](https://github.com/pytest-dev/pytest/issues/15043): Cache writes now emit `pytest.PytestCacheWarning` when writing or closing the cache file fails, consistent with errors opening the file. - [#&#8203;15052](https://github.com/pytest-dev/pytest/issues/15052): Fixed possible off-by-one line numbers in `--fixtures` and `--fixtures-per-test` output. - [#&#8203;15145](https://github.com/pytest-dev/pytest/issues/15145): With `console_output_style` set to `times`, durations just below a unit boundary are now shown in the next unit (e.g. `1.000ms` instead of `1000.0us`). - [#&#8203;15172](https://github.com/pytest-dev/pytest/issues/15172): Assertion diffs now pretty-print the built-in `frozendict` (Python 3.15+) across multiple lines, similarly to how `dict` is displayed. - [#&#8203;4569](https://github.com/pytest-dev/pytest/issues/4569): `-k` no longer matches attributes that end up in a test function's `__dict__` without being meant as keywords, such as pytest's own `pytestmark` attribute and the bookkeeping left behind by `functools.wraps` and `functools.lru_cache`. - [#&#8203;6750](https://github.com/pytest-dev/pytest/issues/6750): Fix fixture argument discovery for custom collectors that pass bound methods to `pytest.Function`. - [#&#8203;6997](https://github.com/pytest-dev/pytest/issues/6997): XFAIL reports from teardown phases now include the phase in the short test summary. - [#&#8203;7940](https://github.com/pytest-dev/pytest/issues/7940): Fixed cleanup of temporary directories failing when subdirectories have their execute permission removed. - [#&#8203;8321](https://github.com/pytest-dev/pytest/issues/8321): Fixed exception chains being duplicated in the traceback output when an exception in the chain (`__cause__`/`__context__`) has no traceback of its own, and that exception is itself linked to further exceptions. - [#&#8203;8914](https://github.com/pytest-dev/pytest/issues/8914): Tests parametrized with higher-than-function scope are now reordered by parameter *value* rather than by parameter *index*, so that items using equal parameter values are grouped together and share a single fixture setup, even when they are parametrized by separate `@pytest.mark.parametrize <pytest.mark.parametrize ref>` calls. Previously, an expensive higher-scoped fixture could be set up and torn down repeatedly for the same parameter value. Unhashable parameter values (e.g. dicts) keep the previous index-based grouping behavior. As a consequence, the order in which parametrized tests run may change (fixture setup/teardown counts can only decrease, not increase). - [#&#8203;9924](https://github.com/pytest-dev/pytest/issues/9924): Fixed doctest option flags leaking between docstrings after a failure, skip, or expected failure. #### Improved documentation - [#&#8203;10721](https://github.com/pytest-dev/pytest/issues/10721): Replaced `setup.py` usage with `pyproject.toml` in `writing-plugins`. - [#&#8203;12658](https://github.com/pytest-dev/pytest/issues/12658): Moved the fixture setup and finalizer hooks to the test running hooks section in the reference documentation. - [#&#8203;12857](https://github.com/pytest-dev/pytest/issues/12857): Documented how `--confcutdir` affects initial `conftest.py` discovery. - [#&#8203;14157](https://github.com/pytest-dev/pytest/issues/14157): Added the `pytest-flakefighters` plugin to the list of flaky test plugins in `plugins.rst`. Added flaky test papers published on the [Test FLARE](https://test-flare.github.io/) project to the list of flaky papers in `plugins.rst`. - [#&#8203;15127](https://github.com/pytest-dev/pytest/issues/15127): Added guidance on typing yield fixtures, including annotating fixture functions with their generator type and fixture consumers with the yielded value type. - [#&#8203;15242](https://github.com/pytest-dev/pytest/issues/15242): The `installation instructions <installation>` and `install-package-with-pip` now show how to install pytest into a virtual environment with venv and pip, uv or virtualenv, and explain the `externally-managed-environment` error. - [#&#8203;4569](https://github.com/pytest-dev/pytest/issues/4569): `pytest --help`, the `-k` reference entry and `select-tests` no longer describe `-k` as a Python expression matched against test names only; `keyword expressions` now shows marker names being matched as well. The examples that looked up a marker use `Node.get_closest_marker <_pytest.nodes.Node.get_closest_marker>` rather than `item.keywords`. - [#&#8203;9614](https://github.com/pytest-dev/pytest/issues/9614): Clarified that `session.items` and `session.testscollected` exclude deselected tests in the `pytest_collection` documentation. #### Packaging updates and notes for downstreams - [#&#8203;11680](https://github.com/pytest-dev/pytest/issues/11680): Source archives of arbitrary commits -- the tarballs GitHub serves under `/archive/`, not just the ones for tags -- can now be built into an sdist or a wheel with a correct version. A `.git_archival.txt` file, expanded by `git archive` via `export-subst`, carries the describe output that `setuptools-scm` would otherwise have to ask `git` for. The archival file deliberately omits `ref-names`. Recording it would make the content of an archive -- and therefore its checksum -- change whenever a branch that points at the archived commit is moved afterwards, which is how the equivalent tarballs of tagged releases became unstable for other projects. Describe output alone depends only on the commit and on the tags reachable from it. The archival file is not shipped in the sdist -- an sdist carries its version in its metadata, and the template is only ever expanded by `git archive`. Building pytest from a git checkout now requires `setuptools-scm >= 10.1`. - [#&#8203;9236](https://github.com/pytest-dev/pytest/issues/9236): `pluggy>=1.6` is now required. Older pluggy versions stopped running the remaining hook wrapper teardowns once an old-style `hookwrapper` raised in its own teardown. The logging plugin's wrapper was left suspended, and when it was finalised later it detached the handler that `caplog` of a subsequent test was recording through, so that test saw no records. #### Contributor-facing changes - [#&#8203;14813](https://github.com/pytest-dev/pytest/issues/14813): Added a systematic coverage matrix for assertion rewriting. - [#&#8203;14921](https://github.com/pytest-dev/pytest/issues/14921): Added <span class="title-ref">scripts/diff-assert-rewrite.py</span>, which diffs the assert-rewritten form of a snippet between the plain source, this checkout and released pytest versions. - [#&#8203;15190](https://github.com/pytest-dev/pytest/issues/15190): Fixed the documentation build with Pluggy 1.7 by ignoring a reference to its undocumented `DistFacade` compatibility class. #### Miscellaneous internal changes - [#&#8203;13888](https://github.com/pytest-dev/pytest/issues/13888): `FixtureRequest.node <pytest.FixtureRequest.node>` is now explicitly annotated as returning `Any`, so strict pyright no longer reports it as `Unknown`. The return type stays deliberately broad, see `13888`. - [#&#8203;14758](https://github.com/pytest-dev/pytest/issues/14758): Internal node ids (the `::`-separated strings identifying collected items, e.g. `path/to/test_file.py::TestClass::test_method[param]`) are now represented internally by a single structured `~_pytest.nodeid.NodeId` dataclass instead of being repeatedly re-parsed as plain strings. The public `nodeid: str` attribute on nodes and reports is unchanged and remains fully backward compatible for plugins. </details> <details> <summary>theskumar/python-dotenv (python-dotenv)</summary> ### [`v1.2.4`](https://github.com/theskumar/python-dotenv/blob/HEAD/CHANGELOG.md#124---2026-10-01) [Compare Source](https://github.com/theskumar/python-dotenv/compare/v1.2.3...v1.2.4) ##### Fixed - `dotenv get` no longer exits with code 1 for empty string values (`KEY=`) by \[[@&#8203;ShamikOfficial](https://github.com/ShamikOfficial)] in \[[#&#8203;700](https://github.com/theskumar/python-dotenv/issues/700)] - An unquoted empty value followed by an inline comment (e.g. `KEY= # comment`) is now parsed as an empty string instead of the comment text by \[[@&#8203;Noethix55555](https://github.com/Noethix55555)] in \[[#&#8203;663](https://github.com/theskumar/python-dotenv/issues/663)] - `dotenv run --no-override` now expands variable references with the same precedence as `load_dotenv(override=False)`, so a value like `${BASE}/suffix` uses the existing `BASE` from the environment instead of the one from the `.env` file by \[[@&#8203;ROTl24](https://github.com/ROTl24)] in \[[#&#8203;698](https://github.com/theskumar/python-dotenv/issues/698)] ### [`v1.2.3`](https://github.com/theskumar/python-dotenv/blob/HEAD/CHANGELOG.md#123---2026-08-16) [Compare Source](https://github.com/theskumar/python-dotenv/compare/v1.2.2...v1.2.3) ##### Fixed - Strip a leading UTF-8 BOM from `.env` file contents so the first variable is no longer silently lost when the file is saved with BOM (e.g. by some JetBrains IDEs on Windows) by \[[@&#8203;h1whelan](https://github.com/h1whelan)] in \[[#&#8203;640](https://github.com/theskumar/python-dotenv/issues/640)] - `set_key` now escapes backslashes, so values containing them (Windows paths, regular expressions) survive a write/read round-trip. Quoted values ending in an escaped backslash are no longer mis-parsed as an escaped quote, which used to swallow the following lines by \[[@&#8203;dchaudhari7177](https://github.com/dchaudhari7177)] in \[[#&#8203;680](https://github.com/theskumar/python-dotenv/issues/680)] - `dotenv run` now prints a friendly error instead of a traceback when no command is given by \[[@&#8203;bbc2](https://github.com/bbc2)] in \[[#&#8203;606](https://github.com/theskumar/python-dotenv/issues/606)] - Cache the parsed result for empty `.env` files so repeated `dotenv_values`/`load_dotenv` calls no longer re-read the file by \[[@&#8203;ReinerBRO](https://github.com/ReinerBRO)] in \[[#&#8203;638](https://github.com/theskumar/python-dotenv/issues/638)] </details> <details> <summary>Kludex/python-multipart (python-multipart)</summary> ### [`v0.0.33`](https://github.com/Kludex/python-multipart/blob/HEAD/CHANGELOG.md#0033-2026-10-31) [Compare Source](https://github.com/Kludex/python-multipart/compare/0.0.32...0.0.33) - Drop Python 3.10 support [#&#8203;329](https://github.com/Kludex/python-multipart/pull/329). - Add Python 3.15 support [#&#8203;350](https://github.com/Kludex/python-multipart/pull/350). - Add opt-in field-count and field-size limits for URL-encoded forms in `FormParser` [#&#8203;333](https://github.com/Kludex/python-multipart/pull/333). - Normalize the content type returned by `parse_options_header` when the header has parameters [#&#8203;287](https://github.com/Kludex/python-multipart/pull/287). - Finalize `Content-Transfer-Encoding` decoding before invoking field and file callbacks [#&#8203;336](https://github.com/Kludex/python-multipart/pull/336). - Keep only the incomplete escape when quoted-printable data is split across writes [#&#8203;355](https://github.com/Kludex/python-multipart/pull/355). - Handle nameless uploads when `UPLOAD_KEEP_FILENAME` or `UPLOAD_KEEP_EXTENSIONS` is set [#&#8203;343](https://github.com/Kludex/python-multipart/pull/343). - Accept a `str` `UPLOAD_DIR` when `UPLOAD_KEEP_FILENAME` is set [#&#8203;335](https://github.com/Kludex/python-multipart/pull/335). - Speed up parser state lookups [#&#8203;330](https://github.com/Kludex/python-multipart/pull/330). - Speed up opening boundary matching [#&#8203;328](https://github.com/Kludex/python-multipart/pull/328). - Speed up querystring callback dispatch [#&#8203;316](https://github.com/Kludex/python-multipart/pull/316). </details> <details> <summary>astral-sh/ruff (ruff)</summary> ### [`v0.17.4`](https://github.com/astral-sh/ruff/blob/HEAD/CHANGELOG.md#0174) [Compare Source](https://github.com/astral-sh/ruff/compare/0.17.3...0.17.4) Released on 2026-11-05. ##### Preview features - \[`flake8-logging-format`] Avoid behavior changes and syntax errors in fixes (`G004`) ([#&#8203;27419](https://github.com/astral-sh/ruff/pull/27419)) - \[`security`] Implement `tarfile-ignore-zeros-true` ([#&#8203;28680](https://github.com/astral-sh/ruff/pull/28680)) ##### Bug fixes - Accept a bare raise before a semicolon ([#&#8203;29761](https://github.com/astral-sh/ruff/pull/29761)) - Allow match identifiers after a semicolon ([#&#8203;29760](https://github.com/astral-sh/ruff/pull/29760)) - Fix panic on BOM-prefixed files in diagnostic renderer ([#&#8203;30017](https://github.com/astral-sh/ruff/pull/30017)) - \[`flake8-simplify`] Report collapsible `elif` clauses after a multi-statement `if` branch (`SIM102`) ([#&#8203;29814](https://github.com/astral-sh/ruff/pull/29814)) ##### Rule changes - Show more nonprinting characters in diagnostic fix diffs ([#&#8203;30062](https://github.com/astral-sh/ruff/pull/30062)) ##### Performance - Coalesce source slices when formatting attributes ([#&#8203;29841](https://github.com/astral-sh/ruff/pull/29841)) - Collect return statements with a statement-only visitor ([#&#8203;29911](https://github.com/astral-sh/ruff/pull/29911)) - \[`pyflakes`] Defer value comparisons for repeated dictionary keys (`F601`, `F602`) ([#&#8203;29739](https://github.com/astral-sh/ruff/pull/29739)) - Format node fields directly when comment handling is unnecessary ([#&#8203;29853](https://github.com/astral-sh/ruff/pull/29853)) - Reduce formatter source-slice overhead ([#&#8203;29855](https://github.com/astral-sh/ruff/pull/29855)) - Reuse a callee's qualified name across lint rules ([#&#8203;29916](https://github.com/astral-sh/ruff/pull/29916)) - Skip invalid string character checks when the source contains none ([#&#8203;29883](https://github.com/astral-sh/ruff/pull/29883)) - Use a Bloom filter for formatter comment lookups ([#&#8203;29852](https://github.com/astral-sh/ruff/pull/29852)) - Use a concrete buffer for ordinary writes ([#&#8203;29819](https://github.com/astral-sh/ruff/pull/29819)) ##### CLI - Give `NO_COLOR` precedence in Ruff and ty diagnostics ([#&#8203;29898](https://github.com/astral-sh/ruff/pull/29898)) - Honor `CLICOLOR=0` in Ruff and ty diagnostics ([#&#8203;29910](https://github.com/astral-sh/ruff/pull/29910)) ##### Documentation - Correct the documented `version` and `src` defaults for `ruff-action` ([#&#8203;29880](https://github.com/astral-sh/ruff/pull/29880)) - \[`flake8-bugbear`] Make `B014` example error out-of-the-box ([#&#8203;29941](https://github.com/astral-sh/ruff/pull/29941)) - \[`flake8-no-pep420`] Document preview behavior (`INP001`) ([#&#8203;29764](https://github.com/astral-sh/ruff/pull/29764)) - \[`isort`] Expand `I001` documentation ([#&#8203;29843](https://github.com/astral-sh/ruff/pull/29843)) ##### Other changes - \[syntax-errors] Extend `__debug__` write check to attribute targets ([#&#8203;27908](https://github.com/astral-sh/ruff/pull/27908)) ##### Contributors - [@&#8203;fixfon](https://github.com/fixfon) - [@&#8203;hirehamir](https://github.com/hirehamir) - [@&#8203;MichaReiser](https://github.com/MichaReiser) - [@&#8203;saberoueslati](https://github.com/saberoueslati) - [@&#8203;mangod12](https://github.com/mangod12) - [@&#8203;Sacrimento](https://github.com/Sacrimento) - [@&#8203;AlexWaygood](https://github.com/AlexWaygood) - [@&#8203;mulaihonglixihonglixi-web](https://github.com/mulaihonglixihonglixi-web) - [@&#8203;adarrevah](https://github.com/adarrevah) - [@&#8203;charliermarsh](https://github.com/charliermarsh) - [@&#8203;shan3520](https://github.com/shan3520) - [@&#8203;halcyon-past](https://github.com/halcyon-past) ### [`v0.17.3`](https://github.com/astral-sh/ruff/blob/HEAD/CHANGELOG.md#0173) [Compare Source](https://github.com/astral-sh/ruff/compare/0.17.2...0.17.3) Released on 2026-10-26. ##### Preview features - \[`suspicious`] Add `shared-clock-mock` ([#&#8203;29074](https://github.com/astral-sh/ruff/pull/29074)) ##### Bug fixes - \[`pyupgrade`] Avoid incorrect conversions to f-strings (`UP032`) ([#&#8203;25485](https://github.com/astral-sh/ruff/pull/25485)) ##### Performance - Buffer stdout in `ruff format` ([#&#8203;29631](https://github.com/astral-sh/ruff/pull/29631)) - Specialize ASCII identifier lexing ([#&#8203;29503](https://github.com/astral-sh/ruff/pull/29503)) - Speed up identifier and keyword lexing ([#&#8203;29463](https://github.com/astral-sh/ruff/pull/29463)) ##### Documentation - \[`flake8-bandit`] Describe what the rule actually checks for `httpx` (`S113`) ([#&#8203;27936](https://github.com/astral-sh/ruff/pull/27936)) ##### Contributors - [@&#8203;itsvedantkumar](https://github.com/itsvedantkumar) - [@&#8203;charliermarsh](https://github.com/charliermarsh) - [@&#8203;anishgirianish](https://github.com/anishgirianish) ### [`v0.17.2`](https://github.com/astral-sh/ruff/blob/HEAD/CHANGELOG.md#0172) [Compare Source](https://github.com/astral-sh/ruff/compare/0.17.1...0.17.2) Released on 2026-10-22. ##### Preview features - \[`complexity`] Add `unnecessary-regular-expression-compile` ([#&#8203;25533](https://github.com/astral-sh/ruff/pull/25533)) ##### Bug fixes - Avoid syntax errors for type variables with starred constraints (`UP040`, `UP046`, `UP047`, `RUF053`) ([#&#8203;28362](https://github.com/astral-sh/ruff/pull/28362)) - \[`pydocstyle`] Treat backslash-escaped `*args` and `**kwargs` as documented (`D417`) ([#&#8203;29536](https://github.com/astral-sh/ruff/pull/29536)) - \[`pylint`] Avoid false positive on starred elements (`PLE0643`) ([#&#8203;29483](https://github.com/astral-sh/ruff/pull/29483)) - \[`pylint`] Mark fixes unsafe when deleting comments (`PLR5501`, `PLW0120`) ([#&#8203;29414](https://github.com/astral-sh/ruff/pull/29414)) - \[`pyupgrade`] Mark fix unsafe when deleting comments (`UP035`) ([#&#8203;29413](https://github.com/astral-sh/ruff/pull/29413)) ##### Performance - Avoid intermediate names in lint name resolution ([#&#8203;29506](https://github.com/astral-sh/ruff/pull/29506)) - Prefilter bidirectional Unicode checks by UTF-8 leading bytes ([#&#8203;29561](https://github.com/astral-sh/ruff/pull/29561)) - Share postfix parsing and reduce expression copies ([#&#8203;29480](https://github.com/astral-sh/ruff/pull/29480)) ##### Configuration - \[`pylint`] Add a configurable allowlist for `magic-value-comparison` (`PLR2004`) ([#&#8203;18961](https://github.com/astral-sh/ruff/pull/18961)) ##### Documentation - Clarify documentation and correct stale guidance ([#&#8203;29374](https://github.com/astral-sh/ruff/pull/29374)) - \[`pyupgrade`] Remove mentions of variance related to fix safety (`UP040`, `UP047`) ([#&#8203;29592](https://github.com/astral-sh/ruff/pull/29592)) ##### Contributors - [@&#8203;fixfon](https://github.com/fixfon) - [@&#8203;MichaReiser](https://github.com/MichaReiser) - [@&#8203;zaniebot](https://github.com/zaniebot) - [@&#8203;FrancescoPezzella](https://github.com/FrancescoPezzella) - [@&#8203;anishgirianish](https://github.com/anishgirianish) - [@&#8203;rajveer3x](https://github.com/rajveer3x) - [@&#8203;charliermarsh](https://github.com/charliermarsh) - [@&#8203;LckyLike](https://github.com/LckyLke) - [@&#8203;DaniBodor](https://github.com/DaniBodor) ### [`v0.17.1`](https://github.com/astral-sh/ruff/blob/HEAD/CHANGELOG.md#0171) [Compare Source](https://github.com/astral-sh/ruff/compare/0.17.0...0.17.1) Released on 2026-10-15. ##### Preview features - \[`pycodestyle`] Don't treat `None`, `True`, or `False` as keywords (`E271`-`E274`) ([#&#8203;29322](https://github.com/astral-sh/ruff/pull/29322)) ##### Bug fixes - Fix dedent with multiple leading comments ([#&#8203;29382](https://github.com/astral-sh/ruff/pull/29382)) - \[`flake8-pyi`] Detect legacy positional-only parameters in `__new__` methods (`PYI063`) ([#&#8203;28502](https://github.com/astral-sh/ruff/pull/28502)) - \[`flake8-pyi`] Fix false positives on quoted annotations (`PYI036`) ([#&#8203;29274](https://github.com/astral-sh/ruff/pull/29274)) - \[`perflint`] Avoid invalid comprehension suggestions (`PERF401`, `PERF403`) ([#&#8203;29366](https://github.com/astral-sh/ruff/pull/29366)) ##### Rule changes - Treat more `collections` and `weakref` containers as mutable ([#&#8203;29213](https://github.com/astral-sh/ruff/pull/29213)) ##### Documentation - \[`flake8-import-conventions`] Update default and example `aliases` ([#&#8203;29333](https://github.com/astral-sh/ruff/pull/29333)) ##### Contributors - [@&#8203;fixfon](https://github.com/fixfon) - [@&#8203;mmaxjr](https://github.com/mmaxjr) - [@&#8203;joshuavetos](https://github.com/joshuavetos) - [@&#8203;nekomario28](https://github.com/nekomario28) - [@&#8203;ntBre](https://github.com/ntBre) - [@&#8203;shan3520](https://github.com/shan3520) ### [`v0.17.0`](https://github.com/astral-sh/ruff/blob/HEAD/CHANGELOG.md#0170) [Compare Source](https://github.com/astral-sh/ruff/compare/0.16.10...0.17.0) Released on 2026-10-09. The executables in our macOS and Windows release archives and `ruff` wheels are now code-signed. macOS executables are signed with an Apple Developer ID certificate and notarized by Apple. Windows executables have timestamped Authenticode signatures from Azure Artifact Signing. This enables verification of the release publisher and binary integrity, supports publisher-based allowlisting, and should reduce security warnings and antivirus false positives. ##### Breaking changes - Update the default and latest Python versions for 3.15 ([#&#8203;28792](https://github.com/astral-sh/ruff/pull/28792)) Ruff now defaults to Python 3.11 instead of 3.10 when no Python version is configured through [`target-version`](https://docs.astral.sh/ruff/settings/#target-version) or [`requires-python`](https://docs.astral.sh/ruff/configuration/#inferring-the-python-version). When checking for syntax errors without a configured Python version, Ruff now defaults to Python 3.15 instead of 3.14. - Update the default rule set ([#&#8203;28786](https://github.com/astral-sh/ruff/pull/28786)) Several of the `flake8-datetimez` rules ([`DTZ001`](https://docs.astral.sh/ruff/rules/call-datetime-without-tzinfo/), [`DTZ005`](https://docs.astral.sh/ruff/rules/call-datetime-now-without-tzinfo/), [`DTZ006`](https://docs.astral.sh/ruff/rules/call-datetime-fromtimestamp/), [`DTZ007`](https://docs.astral.sh/ruff/rules/call-datetime-strptime-without-zone/), [`DTZ011`](https://docs.astral.sh/ruff/rules/call-date-today/), [`DTZ012`](https://docs.astral.sh/ruff/rules/call-date-fromtimestamp/), and [`DTZ901`](https://docs.astral.sh/ruff/rules/datetime-min-max/)) are no longer enabled by default, while [`undefined-local-with-nested-import-star-usage`](https://docs.astral.sh/ruff/rules/undefined-local-with-nested-import-star-usage/) (`F406`), which corresponds to a syntax error, is now enabled by default. - Update Rust crate quick-junit to 0.8.0 ([#&#8203;27295](https://github.com/astral-sh/ruff/pull/27295)) JUnit output now uses a `skipped` attribute instead of `disabled` on `<testsuite>` elements and includes a `skipped` attribute on the root `<testsuites>` element. - \[`flake8-import-conventions`] Add `datetime as dt` as a conventional alias (`ICN001`) ([#&#8203;28790](https://github.com/astral-sh/ruff/pull/28790)) - Support Unicode dummy variable names ([#&#8203;28722](https://github.com/astral-sh/ruff/pull/28722)) The default [`lint.dummy-variable-rgx`](https://docs.astral.sh/ruff/settings/#lint_dummy-variable-rgx) now recognizes underscore-prefixed Unicode names, such as `_次`, as dummy variables. - Update to Unicode 17 ([#&#8203;21229](https://github.com/astral-sh/ruff/pull/21229), [#&#8203;28784](https://github.com/astral-sh/ruff/pull/28784)) Ruff now uses Unicode 17 data for identifier normalization and named character escapes (`"\N{...}"`). - Always show unsafe and display-only fixes in the CLI ([#&#8203;27810](https://github.com/astral-sh/ruff/pull/27810)) The default `full` output format now shows unsafe fixes and suggestions requiring manual review, regardless of the [`unsafe-fixes`](https://docs.astral.sh/ruff/settings/#unsafe-fixes) setting. Actually applying unsafe fixes still requires explicit opt-in. - Remove the Python dependency from conda-forge builds ([conda-forge/ruff-feedstock#361](https://github.com/conda-forge/ruff-feedstock/pull/361)) The conda-forge build no longer depends on Python, now supports linux-riscv64, win-arm64, and linux-ppc64le platforms, and now includes shell completions. However, no longer depending on Python means that `python -m ruff` and `import ruff` will no longer work. Use `ruff` directly from `PATH` instead. PyPI installations and those from the standalone installer are unaffected. - Remove support for ruff-lsp ([#&#8203;28750](https://github.com/astral-sh/ruff/pull/28750)) Support for `ruff-lsp`, the legacy Python language server [deprecated in Ruff v0.9.5](https://github.com/astral-sh/ruff/releases/tag/0.9.5), has been removed. The Ruff VS Code extension now always uses the native language server; `ruff.nativeServer` is deprecated and ignored. See the [migration guide](https://docs.astral.sh/ruff/editors/migration/). ##### Stabilization The following rules have been stabilized and are no longer in preview: - [`lazy-import-mismatch`](https://docs.astral.sh/ruff/rules/lazy-import-mismatch) (`TID254`) - [`lazy-import-immediately-resolved`](https://docs.astral.sh/ruff/rules/lazy-import-immediately-resolved) (`TID255`) - [`os-path-commonprefix`](https://docs.astral.sh/ruff/rules/os-path-commonprefix) (`RUF071`) The following behaviors have been stabilized: - The formatter, [`unsorted-imports`](https://docs.astral.sh/ruff/rules/unsorted-imports/) (`I001`), [`line-too-long`](https://docs.astral.sh/ruff/rules/line-too-long/) (`E501`), and [`doc-line-too-long`](https://docs.astral.sh/ruff/rules/doc-line-too-long/) (`W505`) now consistently ignore trailing pragma comments when computing line length. This resolved several bugs involving interactions between these rules ([#&#8203;27313](https://github.com/astral-sh/ruff/pull/27313)) but may also cause existing imports to be reformatted and was thus classified as a breaking change. ##### Preview features - \[`flake8-bugbear`] Report the method name and a more precise range (`B005`) ([#&#8203;27050](https://github.com/astral-sh/ruff/pull/27050)) - \[`refurb`] Mark fix unsafe and move to `suspicious` (`FURB152`) ([#&#8203;28405](https://github.com/astral-sh/ruff/pull/28405)) - \[`ruff`] Allow docstrings in strict mode (`RUF067`) ([#&#8203;28679](https://github.com/astral-sh/ruff/pull/28679)) ##### Bug fixes - \[`flake8-builtins`] Expand checks in class scopes (`A001`) ([#&#8203;29076](https://github.com/astral-sh/ruff/pull/29076)) - \[`flake8-self`] Allow private access on `object.__new__(cls)` instances (`SLF001`) ([#&#8203;29001](https://github.com/astral-sh/ruff/pull/29001)) - \[`flake8-tidy-imports`] Skip `lazy-import-mismatch` in stubs (`TID254`) ([#&#8203;29095](https://github.com/astral-sh/ruff/pull/29095)) - \[`flake8-type-checking`] Add the notion of runtime-ambiguous references ([#&#8203;26508](https://github.com/astral-sh/ruff/pull/26508)) - \[`flake8-type-checking`] Never flag annotations in function scopes ([#&#8203;29183](https://github.com/astral-sh/ruff/pull/29183)) - \[`pyflakes`] Mark the fix as unsafe when it creates a docstring (`F541`) ([#&#8203;28258](https://github.com/astral-sh/ruff/pull/28258)) - \[`pylint`] Preserve trailing comments in `useless-return` fix (`PLR1711`) ([#&#8203;29180](https://github.com/astral-sh/ruff/pull/29180)) - \[`ruff`] Avoid false positive when `pytest.raises` is used in a `with` statement (`RUF061`) ([#&#8203;28186](https://github.com/astral-sh/ruff/pull/28186)) ##### Rule changes - \[`pyupgrade`] Suggest `typing.TypeForm` on Python 3.15 (`UP035`) ([#&#8203;29084](https://github.com/astral-sh/ruff/pull/29084)) ##### Contributors - [@&#8203;DeviousCardi](https://github.com/DeviousCardi) - [@&#8203;hugehoo](https://github.com/hugehoo) - [@&#8203;nekomario28](https://github.com/nekomario28) - [@&#8203;Daverball](https://github.com/Daverball) - [@&#8203;Viicos](https://github.com/Viicos) - [@&#8203;DebadityaHait](https://github.com/DebadityaHait) - [@&#8203;saberoueslati](https://github.com/saberoueslati) - [@&#8203;baltasarblanco](https://github.com/baltasarblanco) - [@&#8203;yxshee](https://github.com/yxshee) - [@&#8203;lognd](https://github.com/lognd) - [@&#8203;dor-sr](https://github.com/dor-sr) </details> <details> <summary>Kludex/starlette (starlette)</summary> ### [`v1.10.0`](https://github.com/Kludex/starlette/releases/tag/1.10.0): Version 1.10.0 [Compare Source](https://github.com/Kludex/starlette/compare/1.9.0...1.10.0) #### 📝 Leaner URL-encoded form parsing Starlette 1.10.0 parses URL-encoded forms with less memory and CPU, no longer drops the last field when a stream ends early, and lets you compare `FormData` that holds several uploads under one key. ```console uv pip install starlette==1.10.0 ``` - **Forms with many fields parse faster and use less memory** ([#&#8203;3724](https://github.com/Kludex/starlette/pull/3724)). `FormParser` builds each field in the parser callbacks instead of queueing every event and replaying it. On CodSpeed, 1000 fields went from 42.8 ms to 34.9 ms and from 63.5 KB to 54.5 KB, and the `max_fields` limit case went from 6,880 B to 864 B. - **The last field is kept when the request stream ends without an empty chunk** ([#&#8203;3599](https://github.com/Kludex/starlette/pull/3599)). The parser is now finalized once the stream is exhausted, so custom streams that never yield a final `b""` no longer lose their last field. - **`FormData` with repeated uploads can be compared** ([#&#8203;3619](https://github.com/Kludex/starlette/pull/3619)). Comparing two `FormData` objects with several `UploadFile` values under the same key used to raise `TypeError`. #### ⚠️ Behaviour changes - **Multidict equality keeps the order of values under a repeated key** ([#&#8203;3619](https://github.com/Kludex/starlette/pull/3619)). Keys can still appear in any order, but `QueryParams("a=1&a=2")` and `QueryParams("a=2&a=1")` are no longer equal, matching what `getlist()` returns. - **`starlette.formparsers.FormMessage` is deprecated** ([#&#8203;3724](https://github.com/Kludex/starlette/pull/3724)). The parser no longer uses it, and `FormParser.messages` is gone. Calling `FormMessage(...)` emits a `StarletteDeprecationWarning`. #### 🧭 Routing and URL generation - **Path parameter values that look like a placeholder are kept as they are** ([#&#8203;3725](https://github.com/Kludex/starlette/pull/3725)). `url_path_for("route", category="{id}", id="42")` on `/{category}/{id}` now returns `/{id}/42` instead of `/42/42`. Substitution also got faster, from 549 ns to 520 ns with two parameters and from 1,078 ns to 779 ns with five. - **Route matching does less work per request** ([#&#8203;3665](https://github.com/Kludex/starlette/pull/3665), [#&#8203;3722](https://github.com/Kludex/starlette/pull/3722)). `Match` members are compared by identity, cutting up to 4.9% of the instructions per dispatch in the routing benchmarks. - **`WSGIMiddleware` strips `root_path` only at a path segment boundary** ([#&#8203;3718](https://github.com/Kludex/starlette/pull/3718)). A request to `/application` under a `root_path` of `/app` no longer becomes `/lication`. - **`FloatConvertor` reports NaN and infinity correctly** ([#&#8203;3716](https://github.com/Kludex/starlette/pull/3716)). NaN was reported as a negative float. #### 🛡️ Middleware, responses and config - **Handled exceptions no longer keep requests alive** ([#&#8203;3205](https://github.com/Kludex/starlette/pull/3205)). Starlette clears the traceback after an exception handler runs, so an exception instance reused across requests, such as a module-level `HTTPException`, no longer pins per-request objects in memory. - **Middlewares accept `http.response.start` without `headers`** ([#&#8203;3721](https://github.com/Kludex/starlette/pull/3721)). `BaseHTTPMiddleware`, `GZipMiddleware` and `SessionMiddleware` default the omitted field to an empty list instead of raising `KeyError`. - **`FileResponse` ignores `Range` on methods other than `GET` and `HEAD`** ([#&#8203;3679](https://github.com/Kludex/starlette/pull/3679)). A `POST` endpoint that returns a file now sends the full file, as RFC 9110 requires. - **`Config` strips one pair of matching outer quotes from env file values** ([#&#8203;3720](https://github.com/Kludex/starlette/pull/3720)). `KEY='say "hi"'` now reads as `say "hi"` instead of `say "hi`. **Full changelog:** [1.9.0...1.10.0](https://github.com/Kludex/starlette/compare/1.9.0...1.10.0) ### [`v1.9.0`](https://github.com/Kludex/starlette/releases/tag/1.9.0): Version 1.9.0 [Compare Source](https://github.com/Kludex/starlette/compare/1.8.0...1.9.0) This release streams `TestClient` response bodies, so `client.stream()` returns before the application finishes. It also escapes path delimiters when building URLs, matches host names case-insensitively, and keeps every existing `Vary` header. #### Changed - Stream `TestClient` response bodies, so `client.stream()` returns before the application finishes. Closing an unfinished streamed response now cancels the application [#&#8203;3491](https://github.com/Kludex/starlette/pull/3491). #### Fixed - Percent-encode `?`, `#`, `\` and a leading `//` in the request path when building `request.url`, and `\` and a leading `//` in `url_path_for` [#&#8203;3671](https://github.com/Kludex/starlette/pull/3671). - Use the byte length for `Content-Length` when the response body is a typed or multidimensional `memoryview` [#&#8203;3622](https://github.com/Kludex/starlette/pull/3622). - Include `HEAD` in the `Allow` header of `HTTPEndpoint` 405 responses when `GET` is defined [#&#8203;3585](https://github.com/Kludex/starlette/pull/3585). - Match host names case-insensitively in `Host` routing and `TrustedHostMiddleware` [#&#8203;3542](https://github.com/Kludex/starlette/pull/3542). - Preserve every existing `Vary` header in `MutableHeaders.add_vary_header()`, used by `GZipMiddleware` and `SessionMiddleware` [#&#8203;3675](https://github.com/Kludex/starlette/pull/3675). **Full changelog:** [1.8.0...1.9.0](https://github.com/Kludex/starlette/compare/1.8.0...1.9.0) </details> <details> <summary>jannikmi/timezonefinder (timezonefinder)</summary> ### [`v8.3.0`](https://github.com/jannikmi/timezonefinder/blob/HEAD/CHANGELOG.rst#830-2026-08-19) [Compare Source](https://github.com/jannikmi/timezonefinder/compare/8.2.5...8.3.0) New features: - The dataset version is now exposed at runtime. `TimezoneFinder().data_version` (and `TimezoneFinderL().data_version`) return the timezone-boundary-builder release the packaged data was built from, read from a `data_version.txt` stamp that `scripts/file_converter.py` writes into the data directory it generates and that ships in the wheel. Previously an installed `timezonefinder` could not state it at all: the release tag lived only in a repo-root file that is not packaged. Which release a parse is stamped with comes from the input's filename (`combined-with-oceans-2026c.json`, which `update_data.sh` now produces), or from `scripts/file_converter.py --data-version` for an input that cannot carry it; your own GeoJSON is stamped `"unknown"`, and an unpacked release archive that lost its tag is refused rather than compiled into data that could never say where it came from. `timezonefinder.__version__` is now exposed as well, read from the installed distribution metadata. Solves issue [#&#8203;498](https://github.com/jannikmi/timezonefinder/issues/498). - The command line script gained a `--stdin` streaming mode: it reads delimited rows from standard input and writes each back out with a `timezone` column appended, building the finder once instead of paying full initialisation per coordinate. Which columns hold the coordinates is read off the header by name, or stated with `--lng-col`/`--lat-col`, and never inferred from their position - a swapped pair is still a valid coordinate for any longitude between -90 and 90, so guessing would answer with a real but wrong timezone instead of failing. Every input row produces exactly one output row, and a row that cannot be used warns on stderr and makes the run exit non-zero rather than ending the stream. Whether the first row is a header is worked out from the row, or stated with `--header`/`--no-header`. New flags `-d`/`--delimiter` and `--in-memory` apply to the whole stream. See the `usage documentation <https://timezonefinder.readthedocs.io/en/latest/1_usage.html#looking-up-many-coordinates-at-once>`**. Solves issue [#&#8203;504](https://github.com/jannikmi/timezonefinder/issues/504). Thanks to `weed33834 <https://github.com/weed33834>`** for the PR [#&#8203;516](https://github.com/jannikmi/timezonefinder/issues/516). Changed: - Polygon coordinates are now stored one axis at a time in the packaged `coordinates.bin` files - all x values followed by all y values per polygon, instead of interleaved. The point in polygon test scans a single axis per iteration, so contiguous per-axis blocks halve the cache lines it touches: \~1.6x faster on a median polygon and \~2.5x faster on the largest ones via the C extension, 14-25% faster via Numba. The bundled data was regenerated accordingly, and the layout is described in the `data format documentation <https://timezonefinder.readthedocs.io/en/latest/data_format.html>`\_\_. - Every packaged FlatBuffers file now carries a file identifier and a layout version, and `TimezoneFinder` raises a `ValueError` naming the offending file when either does not match - previously such a directory was read without complaint and produced wrong timezones. For `coordinates.bin` the version records how the coordinates are encoded and which polygons the file holds. The hybrid shortcut binaries get an identifier that differs per zone id width, because the uint8 and uint16 schemas differ only in the width of a zone id and each parses cleanly as the other; the width is now read from the buffer instead of being guessed from the file name, so a renamed or mispaired shortcut file fails loudly rather than returning wrong zones. If you compile your own data and point `bin_file_location` at it, regenerate it once with `scripts/file_converter.py`, since the coordinate layout, the hole storage, the shortcut container and the file names all changed in this release. The markers track what a file holds rather than the package version, so this is not a per-release obligation. Solves issue [#&#8203;458](https://github.com/jannikmi/timezonefinder/issues/458). - The hybrid shortcut loader no longer keeps the entire shortcut binary in memory. The polygon id arrays it returns were zero-copy views onto the \~1.5 MB file buffer, so \~47 KB of live data pinned the whole thing for the lifetime of every `TimezoneFinder` / `TimezoneFinderL` instance. They are now disjoint read-only slices of a single compact array, cutting the shortcut mapping's footprint from \~7.4 MB to \~4.7 MB per instance, and every finder's resident set by \~2 MB, at unchanged initialisation time - which matters most for concurrent workloads, where the recommended one-instance-per-thread pattern multiplied the waste. - Holes that duplicate a timezone boundary polygon are no longer stored twice. Almost every hole is an enclave, cut into the surrounding zone with exactly the ring the upstream data also emits as the enclosed zone's own boundary polygon - the same geometry under two IDs. The packaged hole coordinate file now holds only the rings with no such twin (27 of 756 in the current data), and a new `holes/poly_ref.npy` records per hole which boundary polygon to read instead. Hole data drops from \~2.0 MiB to \~0.16 MiB, and `in_memory=True` saves the same amount of RAM, since those holes now resolve into the boundary arrays rather than materialising a second copy. Matching is exact - rings are compared as integer coordinates in a canonical form, with bounding boxes used only to narrow the search - so every timezone lookup returns what it did before. One visible consequence: `get_geometry()` may hand back a deduplicated hole ring starting at a different vertex or winding the other way than it used to, tracing the same closed path. The encoding is described in the `data format documentation <https://timezonefinder.readthedocs.io/en/latest/data_format.html>`\_\_. - The timezone boundary data now ships as its own distribution, `timezonefinder-data`. `pip install timezonefinder` is unchanged - it is a hard dependency and is installed automatically - but the dataset can now be pinned on its own (`pip install timezonefinder "timezonefinder-data==1.2026.3"`), where previously holding a dataset meant pinning an old `timezonefinder` and forfeiting every code fix since. Every release used to carry the whole \~65 MB dataset in three platform wheels plus an sdist to distinguish a few kilobytes of compiled code, which had already exhausted the PyPI project storage quota once. A data update is consequently no longer a `timezonefinder` release at all: it publishes `timezonefinder-data` under its own tag namespace and is recorded in that package's README rather than here. Its version reads `<format>.<year>.<letter>` - `1.2026.3` is data format generation 1 built from timezone-boundary-builder `2026c` - and `timezonefinder` requires `timezonefinder-data>=…,<2`: no ceiling on the data axis, so a dataset update needs no code release, and a hard one on the format axis, so code paired with data it cannot read fails when resolving rather than at the first lookup. `DATA_LICENSE` moves with the database it covers and now ships inside the data wheel, and a compiled data directory additionally carries a `schemas/` copy of the FlatBuffers definitions its binaries were written by, so it can be read back without the package that wrote it. Solves the first part of issue [#&#8203;446](https://github.com/jannikmi/timezonefinder/issues/446). - The packaged FlatBuffers binaries are now named `.bin` rather than `.fbs`: `boundaries/coordinates.bin`, `holes/coordinates.bin` and `hybrid_shortcuts_uint16.bin`. `.fbs` is the FlatBuffers *schema* extension, and the data directory now ships actual schemas next to the buffers, so one extension was naming two unrelated kinds of file. Each buffer already states what it is through the file identifier in its first bytes, which is what a rename or a mispaired copy cannot forge - the name never carried that meaning. The bytes are unchanged. Bug fixes: - Fixed a `BufferError: cannot close exported pointers exist` raised during resource cleanup in file mode (`in_memory=False`). A coordinate array obtained from `coords_of()` is a zero-copy view onto the memory-mapped file, and `mmap.close()` refuses to unmap while one is alive, so an array outliving its `TimezoneFinder` raised on cleanup. The mapping now stays valid instead of leaving the views dangling, and `FileCoordAccessor.cleanup()` releases its own references so the deferred close happens as soon as the last view is dropped. The accessor must not be used after `cleanup()`. Documentation: - The memory footprint of every finder configuration is now measured and published in a new `memory report <https://timezonefinder.readthedocs.io/en/latest/benchmark_results_memory.html>`\_\_, separating what a configuration allocates (`tracemalloc`) from what it makes resident (RSS, which additionally counts memory-mapped pages). The distinction is the point: the default mode maps the coordinate data instead of reading it, so it allocates an order of magnitude less than the in-memory mode, and only the pages a lookup actually touches become resident. This replaces documentation claiming a 40MB process ceiling and a 41MB data directory, both long out of date. - Restructured the two entry points a reader actually arrives at - `README.rst` and the `documentation landing page <https://timezonefinder.readthedocs.io/en/latest/>`\_\_ - so both state what the package is and how it works instead of only what it is called. The README opens with the project banner and a one-sentence statement of what the package is for, then the badges, then the quick guide - and adds three short sections that were missing entirely: *How it works* (the lookup pipeline and the no-simplification trade-off), *Performance* (a concrete throughput figure with its configuration named, the three point-in-polygon backends and the pure-Python fallback), and *Engineering notes* linking the architecture, data format and benchmarking methodology pages. The maintainers-wanted notice moves from the first heading after the intro into a new `Contributing` section at the bottom, which also links `CONTRIBUTING.md` for the first time. The badge block is corrected along the way: the `code style: black` badge named a formatter this project has never used and is replaced by `ruff`, and a supported-Python-versions badge was added. The banner is referenced by absolute URL, since PyPI serves the long description without the repository and a `docs/…` path renders as a broken image there. The landing page gains the same *How it works* summary, the no-simplification trade-off and the ocean-zone consequence for `timezone_at()`, and its flat seventeen-entry table of contents is grouped into *Using it*, *Design*, *Performance* and *Project*, so the sidebar says what kind of project this is rather than listing pages in the order they were written. - Rewrote the `package comparison <https://timezonefinder.readthedocs.io/en/latest/alternatives.html>`\_\_ page. It now states its position in prose before the first table - border correctness is what this package optimises for, speed is the constraint that work happens under - and says plainly when `tzfpy` is the better choice. Every quantitative cell names what it measures and links its source, and the speed row is deliberately qualitative on both sides, with a note explaining that the two packages have never been benchmarked under one harness. The decision table drops the rows on which the two packages do not differ. - Two new documentation pages: `Architecture <https://timezonefinder.readthedocs.io/en/latest/architecture.html>`\_\_ describes the lookup pipeline, the three point-in-polygon backends and the memory modes, and states the ceilings this package deliberately does not exceed - unsimplified geometry, \~1 cm coordinate resolution, no general-purpose spatial code. It also documents how the package is built and shipped, which was previously described nowhere outside the workflow YAML: why one abi3 wheel per target replaces one wheel per Python version and what `abi3audit` is guarding, why three libc targets are built, why the end-to-end job installs the built wheel and asserts the C extension loaded rather than merely importing the package, and why a tag pushed from outside `master` aborts the release. The testing section gained the property-based suite and the reason the tox matrix is a matrix - the acceleration paths are bound at import time, so a passing run describes one configuration only. Both sections are linked from the README's *Engineering notes*. `Benchmarking Methodology <https://timezonefinder.readthedocs.io/en/latest/benchmarking_methodology.html>`\_\_ documents how the published numbers are produced and what they can and cannot tell you: `ubuntu-latest` pins the runner image and not the CPU, which is why a pull request is measured against its own merge base on the same runner and why every alert threshold is derived from measured noise. It was previously addressed only to contributors, in the second half of `CONTRIBUTING.md`, which now keeps the operational instructions and links to it. - The H3 resolution choice in the `data format documentation <https://timezonefinder.readthedocs.io/en/latest/data_format.html>`\_\_ is no longer asserted to "offer a good balance" but reports the study behind it (`prototypes/single_resolution_bench.py`): resolution 3 keeps the hybrid index at a small fraction of the packaged polygon data, while resolution 4 would exceed 10 % of it for gains that do not justify the increase. - The hand-written documentation no longer restates exact figures that belong to the generated pages - dataset vertex, polygon and hole counts, index and distribution sizes, memory footprints, lookup throughput. Those change with every data update and with code that shifts a footprint, which silently left the copies wrong: the memory figures had already gone stale in four places. The prose now states the magnitude that survives a data update and links `the data report <https://timezonefinder.readthedocs.io/en/latest/data_report.html>`\_\_ or the relevant `benchmark report <https://timezonefinder.readthedocs.io/en/latest/7_performance.html>`\_\_, which are regenerated from the packaged data and are always current. - The three weakest hand-written documentation pages no longer answer a question by pointing at a file the reader has to open. The `performance page <https://timezonefinder.readthedocs.io/en/latest/7_performance.html>`\_\_ now opens with the four benchmark reports and the trend chart instead of a bullet list of adjectives about the binary format, and its C extension and Numba sections are cut to what a user does - which call reports the active backend - with the explanation left to the architecture page that already carried a more precise version of it. *Getting started* lists the four runtime dependencies and what each is for, where it previously said to consult `pyproject.toml`, which remains linked as the authoritative source for version ranges. The use case pages carry runnable snippets for building an aware `datetime` and reading a UTC offset, with the `examples/` scripts as the follow-up rather than the whole answer; the snippets use the standard library's `zoneinfo`, so neither needs an optional dependency. - The shortcut entry distributions in the `data report <https://timezonefinder.readthedocs.io/en/latest/data_report.html>`\_\_ no longer report three quarters of all H3 cells as holding `0` polygons, which is impossible for data whose ocean zones cover the globe. Those cells are covered by a single timezone and store its id directly, so a lookup there needs no point-in-polygon test at all - the column is now *Polygons to test* and the row reads *none (unique zone)*. The tables are introduced by a sentence on what they measure, including why no cell ever needs exactly one test. - The usage examples in `README.rst` and the `usage documentation <https://timezonefinder.readthedocs.io/en/latest/1_usage.html>`\_\_ now show the result the packaged data actually returns. Every snippet queries the same Berlin coordinates and annotated the answer as `'Europe/Paris'`, which is the value from the reduced `timezones-now` dataset, where `Europe/Berlin` is merged into `Europe/Paris` - not from the full dataset the package ships by default. All eleven annotations now read `'Europe/Berlin'`, verified against the packaged data for each of `timezone_at()`, `timezone_at_land()`, `certain_timezone_at()`, `unique_timezone_at()` and `TimezoneFinderL`, and the `get_geometry()` call in the opening example asks for that same zone instead of a different one. `tests/test_documented_contracts.py` now re-runs each of those documented lookups, so a data update that moves the example coordinate's zone fails there rather than leaving every snippet on both pages quietly wrong again. Internal: - The release pipeline refuses to publish `timezonefinder` unless a compatible `timezonefinder-data` already exists on PyPI. The two distributions release independently, and on a data format change the order is fixed - data first, then the code requiring it - because a code wheel whose declared data version does not exist yet is uninstallable for everyone until it does, and the version number cannot be reused to fix it. The check reads the requirement out of the built wheel rather than out of `pyproject.toml`, and asks the index the same question a user's resolver will, so a yanked release does not count as one that satisfies it. It runs before the GitHub Release, which is the first step of the release that cannot be taken back. - Pull requests are opened against a template (`.github/pull_request_template.md`) prompting for the change, its motivation and the checks that were run. - `update_data.sh` resolves the timezone-boundary-builder release tag before downloading and fetches that release's asset, instead of fetching `releases/latest/download/` and separately asking the API what `latest` was - two independent questions that a release landing between them answered differently, attributing one release's data to the other. The tag now names the downloaded archive and the GeoJSON as well, so a leftover file from another release or another dataset variant cannot satisfy the "already downloaded" checks and be parsed in place of what was asked for. - Names and docstrings now describe what the code does. `TimezoneFinder.timezone_at` documents the optimisation it actually performs: once no other zone can be matched the last remaining zone is returned *without* a point in polygon test, which is always correct against the packaged data - the ocean zones cover the globe, so every point lies within one of the candidate polygons - but not against custom data that leaves areas uncovered, where a point inside none of the candidates is still attributed to that zone and `certain_timezone_at` is the method that tests every candidate. Three tests were named after something other than what they do: `test_rectify_coords_valid`/`_invalid` were named for a `rectify_coords` that exists nowhere in the package and both call `validate_coordinates`, and the first was subsumed entirely by `test_validate_coordinates_accepts_finite_values`, which covers all four of its distinct corners and additionally asserts the return value where the older test asserted only "does not raise"; and `test_single_element_arrays_should_not_occur` asserted that they *do* occur (`assert single_element_count == 2`) under a triple-quoted string placed after the first statement, making it a discarded expression rather than a docstring - so it reached neither `--collect-only` nor a failure report, which is where the contradicting name was the only thing a reader saw. A stale comment duplicated across the last two lines of `tests/main_test.py`, reading as a to-do for something `TestTimezonefinderClassTestMEM` already does, is gone. - Added `DATA_VERSION` file tracking which timezone-boundary-builder release the packaged data was generated from, written automatically by the data update script after a successful parse. Thanks to `Lucas Hemkemeier <https://github.com/hemkdev>`\_\_ for the PR [#&#8203;429](https://github.com/jannikmi/timezonefinder/issues/429). - The packaged data now updates itself: a weekly workflow compares `DATA_VERSION` against the latest timezone-boundary-builder release, regenerates the data and opens a ready-to-review update PR, which is merged and released automatically once its CI passes - the version tag is pushed with a GitHub App token, since the default one would not trigger the release pipeline. The tag lives in its own `data-v*` namespace, which the code release pipeline excludes at its trigger and again on the job that creates the GitHub Release, and the data stream publishes by PyPI Trusted Publishing from its own deployment environment rather than with a shared token. It refuses to release when the squash it produced did not land on the `master` it checked, so the tag names a tree that was actually built. Failed CI takes the same manual-attention path and falls back to the previous notification issue. Each cause labels the PR `automation-failed` and leaves one comment naming that cause and linking the run, deduplicated per cause so re-running CI neither repeats a notice nor hides a second one; a failure past the merge is a cause of its own, since that leaves master carrying the update with no tag pushed and only a hand-pushed tag still releases it. The manual release path drops the stop condition it carried for an out-of-order `CHANGELOG.rst`: the automation can no longer produce one, and the test suite asserts the committed file's section order if anything else does (issues [#&#8203;273](https://github.com/jannikmi/timezonefinder/issues/273), [#&#8203;167](https://github.com/jannikmi/timezonefinder/issues/167) and [#&#8203;510](https://github.com/jannikmi/timezonefinder/issues/510)). Thanks to `Lucas Hemkemeier <https://github.com/hemkdev>`\_\_ for the PRs [#&#8203;434](https://github.com/jannikmi/timezonefinder/issues/434) and [#&#8203;436](https://github.com/jannikmi/timezonefinder/issues/436), and to `Nice6042 <https://github.com/Nice6042>`\_\_ for the PR [#&#8203;518](https://github.com/jannikmi/timezonefinder/issues/518). - `update_data.sh` (renamed from `parse_data.sh`) is CI-ready: interactive prompts replaced by flags (`--dataset=full|same-since-now`, `--with-oceans`, `--rm-tmp`), the release note for a data update written automatically into the data package's README, no redundant `tox` run, and a `make reports` at the end so the benchmark and data reports cannot go stale relative to the data an update PR ships. A standalone `make parse`/`make testparse` still needs a manual `make reports` (issues [#&#8203;167](https://github.com/jannikmi/timezonefinder/issues/167) and [#&#8203;510](https://github.com/jannikmi/timezonefinder/issues/510)). Thanks to `Lucas Hemkemeier <https://github.com/hemkdev>`\_\_ for the PRs [#&#8203;432](https://github.com/jannikmi/timezonefinder/issues/432) and [#&#8203;434](https://github.com/jannikmi/timezonefinder/issues/434). - Added property-based tests (`hypothesis`) for coordinate validation (solves issue [#&#8203;143](https://github.com/jannikmi/timezonefinder/issues/143)). Thanks to `Lu Yicheng <https://github.com/01luyicheng>`\_\_ for the PRs [#&#8203;431](https://github.com/jannikmi/timezonefinder/issues/431) and [#&#8203;433](https://github.com/jannikmi/timezonefinder/issues/433). - Replaced the hand-rolled `timeit` timing in `scripts/check_speed_*.py` with `pytest-benchmark` suites under `benchmarks/`, excluded from `make test`/`make testall` via `testpaths`. Both they and the memory harness run over deterministic committed fixtures (`tests/fixtures/benchmarks/`), so two runs of the same commit execute the exact same workload; the loader rejects fixtures that no longer match the checkout. Measurement and rendering are decoupled, so `docs/benchmark_results_*.rst` can be regenerated from a stored JSON without re-measuring. Run via `make speedtest`, `make benchmarks`, `make memory` or `make reports`. - Memory is measured by its own harness (`scripts/measure_memory.py`, `make memory`) rather than by `pytest-benchmark`, which times code and would have its timings distorted by allocation tracking. It emits pytest-benchmark-shaped JSON, so the existing normalisation, noise and comparison tooling works on it unchanged given a `--metric`. `tests/test_memory_footprint.py` fails if a mode's allocation leaves its order of magnitude - the regression that would make `in_memory=False` stop being the low-memory option. - Added continuous benchmarking on CI (solves issue [#&#8203;150](https://github.com/jannikmi/timezonefinder/issues/150)), deliberately kept out of the release pipeline in `build.yml`: the tracked core subset and the memory harness run on every pull request and every push to `master`, publishing `trend charts <https://jannikmi.github.io/timezonefinder/dev/bench/>`\_\_ to `gh-pages` and posting a same-runner base/head comparison on the pull request. The comparison reports added or removed benchmark IDs without trying to ratio unmatched measurements, which lets the trusted default-branch consumer remain compatible while the suite evolves. A pull request is measured against its own merge base in the same job rather than against a stored baseline, because `runs-on: ubuntu-latest` pins the runner image and not the CPU. The measurement design, the tracked estimator and every alert threshold are documented in the new `benchmarking methodology <https://timezonefinder.readthedocs.io/en/latest/benchmarking_methodology.html>`\_\_ page. The measuring job holds no write permissions and no secrets, so branch and fork pull requests behave identically; the comment is posted by a separate, privileged workflow via `workflow_run`. - Guarded the benchmark plumbing against silent drift: `tests/test_benchmark_names.py` and `tests/test_memory_metric_names.py` pin the node ids and metric names that join a measurement to its chart history, so a rename fails loudly instead of starting an empty chart beside the orphaned old one; `tests/test_benchmark_workflows.py` asserts that the constants duplicated across the two workflows agree, where a one-sided edit previously had no failure mode at all, and that the cross-machine trend chart cannot creep back into the pull request comparison; and every generated report page states the inputs it describes - `docs/benchmark_results_*.rst` the fixture and timezone data versions they were measured against, `docs/data_report.rst` the timezone data version its figures were derived from. Both stamps are covered by tests: one renders each report and fails if a renderer stops emitting it, another checks the committed pages against the current fixture metadata and `DATA_VERSION`, so regenerating fixtures or updating the data without re-rendering fails loudly instead of leaving a page whose numbers are all plausible and all stale. - Every generator now emits output that is already pre-commit-clean, so regenerating and diffing compares like with like: `write_json` sorts keys the way `pretty-format-json` does, and neither `scripts/reporting.py` nor `BenchmarkReporter` emits trailing whitespace on empty cells or a trailing blank line. Previously every `make parse`/`make reports` left its outputs looking modified until the hooks had run, which masked whether a regeneration had actually changed anything. - Every generated benchmark report now opens with its headline figure and the configuration behind it, above the tables: how long a lookup takes and how many per second, the per-check cost across polygon sizes, construction time, footprint per mode - all derived from the same parsed JSON as the tables, never hardcoded. The banner beneath states which acceleration path and platform produced the numbers, and says whether that is the configuration CI tracks: the committed reports are rendered from a developer machine with Numba enabled, while CI measures the C extension without Numba, so their figures were never comparable to the trend chart and now say so. - `make flatbuf` no longer overwrites hand-maintained `__init__.py` files. `flatc` derives its output path from the schema namespace and writes an empty `__init__.py` at every level of it, so generating in place wiped the `__all__` in `timezonefinder/__init__.py` - the whole public API. The target now generates into a scratch tree, copies back only the generated packages, and runs the formatters on the result so a regeneration diff shows the codegen change rather than formatting churn. - Mypy now type-checks the whole package except the `flatc`-generated bindings. `ignore_errors` previously covered roughly 800 lines of hand-written code as well, where a blatantly wrong return type still reported "Success"; they all pass once the exemption is lifted, bar two genuine findings now fixed. `tests/test_mypy_config.py` keeps the list restricted to generated code, so silencing a module is a reviewed decision rather than a one-line edit. - The hybrid shortcut reader and writer now select their FlatBuffers schema from a single registry (`SHORTCUT_SCHEMAS` in `timezonefinder/flatbuf/io/hybrid_shortcuts.py`) instead of dispatching on the zone id width in three places, each keyed differently. One `ShortcutSchema` per width owns the width, the file name, the `uintN` marker and the maximum zone id, which were previously written down across five places with nothing tying them together. Verified behaviour-preserving down to the bytes: re-writing the shipped shortcut binary produces a byte-identical file. - Each distribution's build is now asserted to contain exactly what it should. The data wheel's payload is compared against the committed dataset as a set, in both directions: a missing binary fails on first use and gets reported, but an extra one ships silently - setuptools copies package data into `build/lib` and never prunes it, so a file renamed in the source tree keeps being zipped into every later wheel built from that checkout, which is how a 63 MB `coordinates.fbs` was still shipping next to the `coordinates.bin` that replaced it and doubling the wheel whose size is the reason the distribution was split out. The wheel builders clear that directory first, so a local build matches the fresh checkout CI builds from, and the code sdist's checks cover its grafted test fixtures again. - The packaged data is additionally held to a floor on how much hole deduplication achieves - the test suite fails if fewer than 90% of its holes match a boundary polygon (96.4% currently), because a future upstream release that stopped emitting enclaves as shared rings would still compile and still return correct timezones, just with the shipped data quietly re-inflated. The floor applies to that dataset and nothing else: compiling your own GeoJSON with `scripts/file_converter.py` is a supported use case, holes that are ordinary interior rings rather than enclaves are stored inline and answer correctly, and the converter only reports the ratio rather than refusing to compile. `prototypes/hole_boundary_redundancy.py` is the study behind the threshold: it reads the upstream GeoJSON, so re-running it against a new release re-verifies the assumption rather than restating it. `prototypes/hole_removal_impact.py` is the study behind keeping the unmatched holes stored inline rather than dropping them, which is the obvious next step and does not work: dropping holes and re-running the lookups changes answers, wrongly, because being covered by another zone only puts that zone among the shortcut candidates and says nothing about it being tested first (issue [#&#8203;513](https://github.com/jannikmi/timezonefinder/issues/513)). - Removed constructs that provably did nothing, and gave two vacuous tests real assertions. Most consequentially, four `__slots__` entries were declared but assigned by nothing, which silently re-permitted the very attributes `__slots__` is there to forbid - assigning those names now raises `AttributeError`, and `test_declared_slots_are_assigned` keeps the list honest. - `get_corrected_hex_boundaries` exists once again. An earlier refactor left two verbatim copies of the antimeridian and pole clipping rules with nothing keeping them in sync; the copy without callers is deleted, and the survivor is now covered by `tests/hex_utils_test.py` - it previously had no direct tests at all. `scripts/configs.py` no longer declares `MAX_LAT`/`MAX_LNG` as a second pair of names for `timezonefinder.configs`'s constants. - `prototypes/` has a `README.md` saying what the three scripts there are: exploratory studies behind committed design decisions, run by hand, outside the package and the test suite. One of them is the measurement that chose H3 resolution 3 - the central algorithmic parameter of the package, already cited from the data format page - and another is the evidence for not building a hierarchical index. `MANIFEST.in` now excludes the whole directory from the source distribution rather than only its `*.py` files. - `plans/` is git-ignored alongside `tmp/` and `.venv/`: implementation plans written while working on a change are local scratch, and leaving the directory untracked-but-unignored made it noise in every `git status` and a candidate for an over-broad `git add`. - Failing paths now report the input that failed. `tests/auxiliaries.py`'s `run_command` assembled the child's stdout and stderr into a message and then raised a *fresh* `CalledProcessError` that never used it, with `from None` discarding the original too, so a packaging failure under `make testint` reported an exit code and nothing about the cause; it now echoes the captured streams and re-raises the original exception with its traceback intact. `scripts/reporting.py` passes the coordinate file paths into `get_polygon_collection`, whose optional `file_path` exists precisely so an incompatible-layout `ValueError` can say which of the two files was stale - `make reports` against an outdated data directory previously could not. `Boundaries.overlaps` names the type it rejected instead of raising a bare `TypeError`, and the `RuntimeError` for missing `original_polygons` names the polygon and resolution it was computing. The two re-raises ruff flags under `B904` now say `from None` explicitly, so a deliberately dropped exception chain is distinguishable from a forgotten one, and `timezonefinder/command_line.py` drops `FileNotFoundError` from an `except` tuple that already caught its base class `OSError`. `tests/test_error_diagnostics.py` pins what each of these messages must contain. - The command line interface no longer routes its own output through a temporary file. `main` redirected stdout to a `mkstemp` file for the duration of the lookup and then, in verbose mode, reopened it to read back a string it still held in a local variable - nothing inside the redirected block ever wrote to stdout, since the lookup functions return their result rather than printing it. The context manager, the read-back, its warning path and the file cleanup are gone, and the lookup function is now resolved once per invocation instead of twice, so `-f 3`/`-f 4` under `-v` no longer construct a second `TimezoneFinderL` and reload its shortcut data just to read a function name. Output is unchanged character for character, across every function id in both modes. `tests/cli_test.py` gains the coverage that makes that checkable - verbose mode, the empty line printed when no timezone is found, and the rejected function id had none - and asserts the printed name verbatim instead of passing it through `rstrip("\n\x1b[0m")`, which strips a *set* of characters rather than a suffix and so truncates 12 of the packaged zone names (`Europe/Amsterdam` -> `Europe/Amsterda`). - Docstrings now describe the code that exists. Six documented something the implementation contradicts: `AbstractTimezoneFinder.__init__` called `in_memory` inert and "kept for API compatibility" when it is what selects memory-mapped against in-memory coordinate access - the claim `help(TimezoneFinder)` surfaces, and the opposite of what the usage docs say; both `get_geometry` docstrings pointed at a `timezone_names.json` that does not exist under that name; `read_zone_names` promised an empty list where it raises `FileNotFoundError`, and illustrated itself with a hardcoded zone count that the packaged data had since outgrown; and `zone_id_of` / `zone_name_from_id` each advertised an exception type they convert away, sending callers to write handlers that can never fire. Five further `:param:`/`Args:` entries in `scripts/` and `tests/` documented arguments that were removed along with the parallel shortcut compilation they belonged to. `tests/test_documented_contracts.py` pins the exception types and the coordinate access mode, so those promises now rest on something besides prose. - The test and benchmark suites no longer contain checks that cannot fail. Eighteen calls sat inside four shared `pytest.raises` blocks in `tests/main_test.py`, and execution leaves such a block at the first statement to raise - so one out-of-range coordinate, one positional call shape and one rejected `get_geometry` input were verified while the remaining fifteen were unreachable. Each is a test case of its own now: every coordinate just outside the WGS84 range, every positional call shape of every keyword-only lookup method, and the unknown-zone-name, past-the-end and negative zone id rejections of `get_geometry`. The `__del__` cleanup test binds its exception per iteration rather than closing over the loop variable, which decided what a garbage-collected instance would raise long after the loop had moved on. On the benchmark side, `pip_inputs_by_stratum` validated only the strata the fixture happened to contain, so one missing from it altogether passed and surfaced later as a bare `KeyError` inside a benchmark, and the points and their labels were paired from two files with a non-strict `zip` that truncates silently. That grouping now lives in `tests/auxiliaries.py` as `group_pip_inputs_by_stratum`, checks against the declared `PIP_STRATA` - which the generator no longer keeps a second copy of - and has tests for each way the two fixture files can disagree. - Both point-in-polygon acceleration paths are now covered by a local test run, whichever one the environment happens to bind. The implementation is selected at import time and Numba wins whenever it is importable - which the documented setup (`uv sync --all-groups`) makes it - so the C extension was reached only by direct-kernel tests on hand-built arrays, and everything about how real polygon buffers arrive at it, including the read-only memory-mapped views, was first exercised in CI's non-numba tox environments: the configuration a plain `pip install timezonefinder` produces. `tests/test_acceleration_paths.py` now rebinds `utils.inside_polygon` and drives the full lookup stack through both implementations, asserting that they agree across the real boundary data, that the C path returns the known-correct answers, and that the point-in-polygon stage was reached at all rather than short-circuited by the shortcut layer (issue [#&#8203;482](https://github.com/jannikmi/timezonefinder/issues/482)). - The packaging guard in `tests/test_package_contents.py` no longer names files that do not exist. It asserts that nothing in the built sdist and wheel matches a list of unwanted paths, which passes just as readily when a pattern matches nothing at all: `.github` lacked the trailing slash that directory patterns need, `Agents.*` stopped matching when the file was renamed to `AGENTS.md`, and `readthedocs.yaml` never matched `readthedocs.yml` - so the CI configuration and both of those files were unguarded while the suite stayed green. The patterns are corrected, the provider stubs, `contributing/`, `.agents/`, `.claude/` and `.cursor/` are covered to match what `MANIFEST.in` excludes, and `test_every_unwanted_pattern_matches_a_project_file` now fails on any hand-written pattern that matches no path in the checkout, so the next rename cannot silently disarm one. It carries the `unit` marker rather than the module's former blanket `integration` mark, since it needs no build: a mistyped pattern surfaces in `make test`. `.gitignore` re-include lines (`!…`) are also no longer read as exclusions, which had produced one more parametrised case that could never fail. The converse direction is checked too: `test_every_manifest_exclusion_is_guarded` parses the `exclude`/`recursive-exclude`/`prune`/`global-exclude` directives out of `MANIFEST.in` and fails when one of them keeps a path out of the build that no pattern here names - previously such a line was enforced by the build and verified by nothing, so deleting it would have shipped the file with the suite still green. The two lists are hand-maintained statements of one intent and had drifted before, in both directions. The `architecture page <https://timezonefinder.readthedocs.io/en/latest/architecture.html>`\_\_ describes the guard from both sides: among the tests that exist to give an invariant a failure mode, and under *How it ships* as the check on what the built artifacts actually contain. - The distributions built by the test suite are now built for the interpreter running it. `uv build` was invoked without `--python`, so it targeted the newest interpreter on the machine, while `tests/test_integration.py` creates its throwaway venv from `sys.executable`: on a checkout whose `.venv` is older than the newest installed Python, `make testint` produced a `cp314` wheel and failed with pip's "not a supported wheel on this platform". Every tox environment offers a single interpreter, so the two agreed by accident in CI and the mismatch only ever hit developer machines, where the workaround was to pin `UV_PYTHON`. `test_build_commands_pin_the_running_interpreter` keeps the pin in place; it needs no build, so it fails in `make test` rather than waiting on a CI environment that cannot reproduce the mismatch. - Two tests no longer leak numpy's global error state into whatever pytest collects next. `np.seterr` and the warning filters are process-global, and `test_overflow` (`tests/main_test.py`) plus `test_inside_polygon` (`tests/utils_test.py`, six parametrisations) each set them and never restored them - so every later test in the same process ran with `under` promoted from `ignore` to `warn`, and which of the two modules pytest collected first decided the state the other ran under. The filters were undone only incidentally, by pytest's per-test `catch_warnings()`, not by the tests themselves. `benchmarks/conftest.py` already had the correct pattern; it now lives in `tests/auxiliaries.py` as the `strict_numpy_errors` context manager plus a thin `strict_numpy_warnings` fixture, re-exported through the conftest of each suite, and both call sites request it. The context manager form is what makes the restore directly testable - a leaked global otherwise surfaces only as an unrelated later failure that depends on collection order, which is the hardest kind to attribute. - The zone id invariants in `scripts/timezone_data.py` are each enforced in exactly one place, and now have tests. `ZoneCollection.validate_structure` and `zone_positions` each walked `poly_zone_ids` element by element checking it was non-decreasing and each raised the same message built from its own locals; the scan moves into one `_validate_non_decreasing` helper and `zone_positions` drops its copy, which could only ever have fired if a caller mutated the array in place - the validator runs at construction and nothing writes to it afterwards. A `if min_zone_id < 0` branch is deleted as unreachable: the same method rejects any non-unsigned dtype a dozen lines earlier, so it read as the guard against negative zone ids while being incapable of firing. The class had no tests at all, so what it actually promises - the unsigned-dtype rejection that makes a negative id unrepresentable, the ordering and maximum-id rules, and the shape `zone_positions` returns - is now pinned by `tests/timezone_data_test.py`. - The seven out-of-range coordinates - one representable step outside the valid WGS84 range, per axis and at every corner - are declared once in `tests/locations.py` instead of verbatim in both `tests/main_test.py` and `tests/utils_test.py`, where only one copy carried the comment explaining what makes them interesting and adding a corner to it left the other testing a smaller set. - The shortcut compilation chain in `scripts/shortcuts.py` is annotated for what it is actually passed. Both annotations were the wrong way round: `check_shortcut_sorting` declared `np.ndarray` and only ever receives the `list[int]` that `optimise_shortcut_ordering` returns, and it hands the `np.ndarray` it derives to `has_coherent_sequences(lst: list[int])`. Widened rather than swapped, since `tests/shortcut_test.py` calls the latter with real lists. - The supported Python versions are declared in five places that cannot read each other - `requires-python` and one classifier per minor version in `pyproject.toml`, the `py{...}` factors of `tox.ini`'s envlist, the test matrix and `CIBW_BUILD_VERSIONS` in `build.yml`, and `py_limited_api` in `setup.py` - and two "must match" comments said so while nothing enforced them. `tests/test_python_version_support.py` fails when they drift, in either of the two directions that fail silently: a classifier added without a matrix entry ships a version the package claims to support and CI never runs, and a `requires-python` raised without moving the abi3 base builds wheels tagged for an interpreter that is no longer supported. Each assertion was checked against the specific one-sided edit it targets, and both comments now name the test. - The data report generator states figures it derives rather than ones it restates, and its annotations describe what it returns. `calculate_shortcut_index_stats` took the number of H3 cells existing at the shortcut resolution from a ladder of literals covering resolutions 0 to 4 and fell through, for anything else, to the number of cells actually stored - which reports coverage of exactly 100 % instead of failing - behind an `except ImportError` that cannot fire, since h3 is a runtime dependency rather than an optional one. It asks `h3.get_num_cells`, which returns precisely the numbers that were tabulated. Running mypy over `scripts/reporting.py`, which the pre-commit hook excludes, found seventeen further disagreements between the module and its own signatures: the statistics bag was typed as holding scalars while returning two distributions, `load_binary_data`'s nine-key result was a bare `dict` indexed by string literal, the table renderer declared string rows while stringifying whatever it is handed, `main` was annotated `None` while returning exit codes to `exit()`, and `print_polygon_distribution_table` documented a return value it never produced while its one caller discarded it. The two dict results are now `TypedDict`\ s in `scripts/configs.py`, carrying tests that assert their keys against what is really returned, since CI cannot type-check `scripts/`. The polygon count that labels a distribution row is no longer formatted into that label and parsed back out of it to key the example lookup. `docs/data_report.rst` and the benchmark reports regenerate byte-identically throughout. - Removed five definitions nothing referenced - three JSON/pickle helpers in `scripts/utils.py` and the `import pickle` they kept alive, the `i8` dtype shim in `timezonefinder/_numba_replacements.py` that the no-numba fallback never imports, and a test helper self-documented as kept for future reference - and a guard in `scripts/hex_utils.py` that could not fire. `Hex.poly_candidates` re-read its cache after initialising it and returned an empty set if it were still unset, which no path through `_init_candidates` leaves it: an empty set there means "no candidate polygons", so a converter bug would have surfaced as silently missing shortcuts rather than as a failure. The property had no direct test, being reached only through shortcut generation, and now has one. `_memory_mode_label` looks its two labels up in `PARAM_LABELS` instead of spelling them out, so renaming the display vocabulary can no longer leave the comparison bullets and the tables above them disagreeing. - `make parse` and `make testparse` run again. Both invoked `scripts/file_converter.py` by path, which puts `scripts/` on `sys.path[0]` instead of the repository root, so the converter's own `from scripts.timezone_data import ...` raised `ModuleNotFoundError` before any work started - a total failure that CI never sees, since it runs neither target. `make testparse` is the only cheap end-to-end exercise of the converter (`update_data.sh` needs a \~55 MB download), and nothing under `tests/` covers `parse_data()`, so while it was broken the converter had no smoke test at all. The invocation documented in the usage docs had the same defect and is now the `python -m scripts.file_converter` form that `update_data.sh` already used; `tests/test_script_invocations.py` fails if a by-path invocation returns. Note that `parse_data()` writes its report to the checkout's committed `docs/data_report.rst` whatever `-out` it is given, so `make testparse` leaves that file describing the three-zone fixture - the target now says so. - `scripts/` is type-checked by the mypy pre-commit hook instead of being excluded from it. The directory holds the data converter and the benchmark tooling - most of the repository's non-library Python - and with nothing running mypy over it the annotations had drifted to fifteen errors: two `# type: ignore` codes mypy no longer emits, so the ignore silenced nothing; two implicit `Optional` defaults that `no_implicit_optional = true` was already configured to reject; a dict annotated with a narrower value type than it is assigned; a bucket key and four bounding-box lists annotated `int` while `Boundaries` declares `float`; and two missing variable annotations. All fixed as annotations, with no runtime change. Two of the four errors mypy reported in `tests/auxiliaries.py`, which it reaches by following imports out of `scripts/`, are fixed alongside. `test_scripts_are_type_checked_by_the_hook` guards the exclude, which is a quieter way to stop type-checking a directory than the `ignore_errors` list the neighbouring tests already cover: it takes no override entry and reports nothing. - The eight `__del__` cleanup tests that differed only in which exception `cleanup()` raised, and whether zero or one `ResourceWarning` was expected, are two parametrized tests over the suppressed and warned exception tuples. Each previously repeated the same subclass, the same `catch_warnings` block and the same filter, so adding a ninth exception to `__del__`'s suppression list meant copying the block a ninth time and a copy asserting the wrong count would be invisible. Coverage rises rather than falls: the hand-rolled loop asserting that `__del__` never raises to user code now runs over all six exception types instead of four. - Three leftovers in the converter that read as bugs are gone: `has_coherent_sequences` built an iterator solely to take its first element and then looped from the start anyway (correct, but it reads as an off-by-one), `compile_bboxes` unpacked a pair and immediately reassigned half of it, and `process_single_hex` returned the `hex_id` it was handed so its only caller reassigned the loop variable to itself. Two shadowed builtins (`dir` as a loop variable, `id` as a parameter) are renamed and three bare generator signatures annotated. The benchmark renderer classifies its "other" group by name suffix, as the two lines above it do, rather than by deep-equality scan over lists of dicts; and the `check-manifest` ignore list drops two entries naming files that do not exist (`CONTRIBUTING.rst`, `publish.py`). Every converter change was verified by parsing `tests/test_input.json` before and after and comparing the outputs byte for byte. </details> <details> <summary>twilio/twilio-python (twilio)</summary> ### [`v9.13.0`](https://github.com/twilio/twilio-python/blob/HEAD/CHANGES.md#2026-11-05-Version-9130) [Compare Source](https://github.com/twilio/twilio-python/compare/9.12.0...9.13.0) **Library - Chore** - [PR #&#8203;987](https://github.com/twilio/twilio-python/pull/987): support HMAC-SHA256 webhook signatures in RequestValidator. Thanks to [@&#8203;sbansla](https://github.com/sbansla)! **Twiml** - Add ElevenLabs voices to `<Say>` verb. - Add `partialPromptOnHangup`, `eagerEotThreshold`, `asrSmartFormat`, `ttsTextNormalization`, `ttsLanguageTextNormalization`, `elevenlabsLanguageTextNormalization`, `includeInPrompt`, `customerName`, `applicationReconnect`, `echoPromptFiltering`, `turnDetection` attributes to `<ConversationRelay>`, and `hints`, `asrSmartFormat`, `ttsTextNormalization`, `ttsLanguageTextNormalization` attributes to `<Language>` **Api** - # API Changes - ## 2026-09-22 - Simplified the `criteria` field description. - ## 2026-09-18 - Moved `readOnly` on the snapshot count fields (`profileCount`, `partitionCount`) from the shared schema to the response usage sites, so the counts stay read-only in responses (no change for API consumers). - ## 2026-09-17 - Renamed 3 `Get*` operations to `Fetch*` to match the operationId standard: `FetchCohort`, `FetchSnapshot`, `FetchOperation`. - Removed the unused `ExpressionId` schema and made the operation error example cohort-native, so no `aud_` identifiers remain in the spec. - Kept `libraryVisibility: hidden` across the whole surface (info, path items, and operations). - ## 2026-09-08 - Removed the deprecated header-based-versioning unified specs, consolidating audiences onto the path-based `api.twilio.com/v1` surface. - ## 2026-08-31 - Published the unified audiences spec at `api.twilio.com/v1`. - ## 2026-08-26 - Fixed the Cohort operation response mapping in the unified audiences API. - ## 2026-08-19 - Migrated the unified audiences spec to the Cohort surface (Audiences renamed to Cohorts). - Switched `downstreamServiceName` to `audiences-domain`. - ## 2026-08-05 - Added the `api.unified.version.preview` beta feature. - Made the unified APIs available in prod us1. - ## 2026-07-30 - Fixed example values. - ## 2026-07-29 - Added the initial version of the audiences API to the unified APIs. - ## 2026-07-20 - Deployed the audiences-domain OAS to the dev edge. - ## 2026-07-06 - Added the prod-us1 realm to the audiences public API. - ## 2026-06-23 - Changed the `storeType` enum from `MEMORA` to `TWILIO`. - ## 2026-05-04 - Added the stage-us1 realm and `x-rate-limit` to the audiences API. - ## 2026-04-08 - Added the initial audiences endpoints. - # API Changes - ## 2026-10-28 - Enabled the Redaction Configurations and Redaction Catalog resources in prod-us1. - ## 2026-10-27 - Enabled the Redaction Configurations and Redaction Catalog resources in stage-us1. - ## 2026-09-28 - Added the Redaction Configurations resource (`/v1/RedactionConfigurations`) as a private beta in dev-us1, gated by the `api.redaction.enabled` beta feature. - Added the Redaction Catalog resource (`/v1/RedactionCatalog`), under the same beta feature. It is restricted to One Console. - Add `ApplicationSid` parameter to TwimlSession and TwimlProcess Create endpoints **Audiences** - ## 2026-10-23 - **Content updates**: - Updated description for `AdminFetchRecord` - Updated description for `AdminListCohorts` - Updated description for `AdminListCohortSnapshots` - Updated description for `AdminFetchCohortOperation` - Updated description for `AdminListSnapshotOperations` - Updated schema description for `OperationStatus` - Added properties to `Cohort`: tags - Removed properties from `Cohort`: labels - Added properties to `CohortSnapshot`: tags - Removed properties from `CohortSnapshot`: labels - ## 2026-10-23 - **Content updates**: - Updated description for `ListCohorts` - Updated description for `CreateCohort` - Updated description for `UpdateCohort` - Updated description for `ListCohortSnapshots` - Updated description for `CreateCohortSnapshot` - Updated description for `FetchCohortOperation` - Updated schema description for `OperationStatus` - Added properties to `Cohort`: tags - Removed properties from `Cohort`: labels - Added properties to `CohortSnapshot`: tags - ...and 8 more changes - ## 2026-10-14 - Minor updates (formatting, metadata) - ## 2026-10-07 - Minor updates (formatting, metadata) **Conversations** - Enable the Imports endpoints (list, create, fetch, cancel) and the Import Outcomes list endpoint in prod-us1 - Add GET /v2/Imports/{ImportId}/Outcomes to list an import's per-resource outcomes (dev-us1 and stage-us1) - Add `EMAIL` to the Conversations v2 Communication channel enum. **Deletions** - ## 2026-10-28 - Enable the User Data Deletions API in the `stage-us1` realm. **Destinations** - ## 2026-11-03 - Enable Replay admin APIs for prod-us1 and prod-ie1 realms **Iam** - Raised the most permissions in a POST /v1/Account/AuthorizedApps section, and in a part of the PUT /v1/Organization/AgentsRegistration/Permissions request, to 2000 for MCP agents; the limit of other consents is unchanged - Lowered the most permissions in a POST /v1/Account/AuthorizedApps section to 150, which is what an XMS policy holds - Made the GET and PUT /v1/Organization/AgentsRegistration/Permissions routes available in stage-us1 and prod-us1 - Added the MCP agent consent fields to GET /v1/Account/AuthorizedApps: agent, account, organization, sections (the offered permissions per context) and redirect, and a 401 body with redirect when the account's organization has not registered or enabled the agent (code 25110, with organization\_sid) or the account has no organization (code 25111). oauth\_app\_sid, client\_sid, consent\_state and app\_permissions are now nullable, since an MCP agent response does not use them - Added sections (at least 1) with permissionSelectionMode (ALL\_READ, ALL\_READ\_WRITE, SPECIFIC) and permissions (at most 200) to the POST /v1/Account/AuthorizedApps request, and response\_mode and form\_params to its 201 response - Made the /v1/Organization/AgentsRegistration routes available in stage-us1 and prod-us1 - Added created\_by (the name of the user who registered the agent) and created\_by\_sid to the /v1/Organization/AgentsRegistration responses; both are null for a registration made before the user was recorded - Moved the POST /v1/actions/post\_login (PostLoginActionRequest) webhook payload to camelCase (accountSid, nodeId, actionId, userContext, authenticationContext, requestContext, ipAddress, userAgent, requestId, clientId, identifierType); replaced timestamp with the RFC 3339 sentAt, made authorizationDetails a JSON array, made completedAt an RFC 3339 string, and added userContext (isFirstLogin, user) with the CIAM id at userContext.user.userId - Added the optional type, agent, account, organization, sections, last\_used and expires\_at to the iam.v1.consent responses of the GET /v1/Account/AuthorizedApps and GET /v1/Organization/AuthorizedApps lists, for MCP connections. The list shows an MCP connection beside the OAuth applications, and deleting it revokes the whole connection - Added a 404 to PUT /v1/Account/AuthorizedApps/{consentSid} for an MCP connection, which cannot be updated - Added the GET and PUT /v1/Organization/AgentsRegistration/Permissions routes for what any agent may do in the caller's organization (dev-us1) - Renamed the properties of the /v1/Organization/AgentsRegistration responses to snake\_case (registration\_sid, friendly\_name, client\_url, date\_created, date\_updated), as the other IAM responses are; the request bodies keep clientUrl and enabled - Fixed the pagination meta of the GET /v1/Organization/AgentsRegistration response: it is mapped from the service's snake\_case fields, as in the other IAM list routes, so key, pageSize and the tokens are no longer null - Added the /v1/Organization/AgentsRegistration routes (list, register, fetch, enable or disable, remove) for the MCP agents an organization lets its users connect (dev-us1) **Instrumentation** - # API Changes - ## 2026-10-12 - Initial read-only admin-api spec for the Behavioral Events (events-domain) One Admin console: event producers (list, fetch), write keys (list), event schemas (list, fetch). dev-us1 and stage-us1 only. - ## 2026-10-27 - **Control Plane create, update and attach are synchronous** (`dev-us1`), matching the deployed service: - CreateEventProducer returns `201` with the event producer (`ETag`, `Idempotent-Replayed`), not `202` with an operation - PatchEventProducer returns `200` with the event producer (`ETag`), not `202`; `If-Match` is its only header parameter - AttachEventProducerSchemaVersion returns `201` with the attachment (`Idempotent-Replayed`), not `202` - ## 2026-10-21 - **Replaced the Control Plane with the private-beta API** (`/v1/ControlPlane/…`), enabled in `dev-us1` only: - Removed the EventSources, Datasets, EventSources EventSchemas and AutoInstrumentationRules operations - Added `/v1/ControlPlane/EventProducers` (CreateEventProducer, ListEventProducers) - Added `/v1/ControlPlane/EventProducers/{producerId}` (FetchEventProducer, PatchEventProducer, DeleteEventProducer) - Added `/v1/ControlPlane/EventProducers/{producerId}/WriteKeys` (CreateWriteKey, ListWriteKeys) - Added `/v1/ControlPlane/EventProducers/{producerId}/WriteKeys/{writeKey}` (DeleteWriteKey) - Added `/v1/ControlPlane/EventProducers/{producerId}/EventSchemas` (AttachEventProducerSchemaVersion, ListEventProducerSchemaAttachments) - Added `/v1/ControlPlane/EventProducers/{producerId}/EventSchemas/{schemaId}/Versions/{version}` (DetachEventProducerSchemaVersion) - Added `/v1/ControlPlane/EventSchemas` (CreateEventSchema, ListEventSchemas) - Added `/v1/ControlPlane/EventSchemas/{schemaId}` (FetchEventSchema, PatchEventSchema, DeleteEventSchema) - Added `/v1/ControlPlane/EventSchemas/{schemaId}/Versions` (ListEventSchemaVersions) - Added `/v1/ControlPlane/EventSchemas/{schemaId}/Versions/{version}` (FetchEventSchemaVersion, DeleteEventSchemaVersion) - Updated `/v1/ControlPlane/Operations/{operationId}` (FetchControlPlaneOperationStatus) to the new operation shape; now `dev-us1` only **Knowledge** - ## 2026-10-27 - **Added 1 new path(s)**: - `/v2/ControlPlane/KnowledgeMigrations/{accountSid}/Limits` (AdminFetchKnowledgeMigrationLimits) - ## 2026-10-21 - **Content updates**: - `AdminListKnowledgeMigrations`: the `state` query parameter is optional; without it the list returns every account with knowledge bases - Added properties to `MigrationSummary`: knowledgeBaseCount - ## 2026-10-19 - **Added 7 new path(s)**: - `/v2/ControlPlane/KnowledgeMigrations` (AdminListKnowledgeMigrations) - `/v2/ControlPlane/KnowledgeMigrations/{accountSid}` (AdminFetchKnowledgeMigration) - `/v2/ControlPlane/KnowledgeMigrations/{accountSid}/History` (AdminListKnowledgeMigrationHistory) - `/v2/ControlPlane/KnowledgeMigrations/{accountSid}/Readiness` (AdminFetchKnowledgeMigrationReadiness) - `/v2/ControlPlane/KnowledgeMigrations/{accountSid}/Runs` (AdminListKnowledgeMigrationRuns) - `/v2/ControlPlane/KnowledgeMigrations/{accountSid}/Transitions` (AdminListKnowledgeMigrationTransitions, AdminCreateKnowledgeMigrationTransition) - `/v2/ControlPlane/KnowledgeMigrations/{accountSid}/Transitions/{transitionId}` (AdminFetchKnowledgeMigrationTransition) **Lookups** - Add test api support for Lookup Bulk Jobs endpoints **Memory** - ## 2026-10-14 - No path changes (schema only) - Added optional `dataAsOf` to the `Store` schema returned by `AdminFetchStore`. - ## 2026-10-14 - Added optional `dataAsOf` to the `Store` schema returned by `FetchStore`. - ## 2026-10-08 - Added `FetchProfileOperation` (`GET /v1/ProfileOperations/{operationId}`) to check the status and - progress of an asynchronous profile operation. The response includes a `Retry-After` header with - the minimum number of seconds to wait before polling again. The endpoint is hidden from the - helper libraries and gated behind the `api.memory.2026Q3` beta feature. - The `202` responses of `UpdateProfilesBulk` and `CreateProfilesImportV2` now return `operationId`, - `createdAt` and `statusUrl` (behind the `api.memory.2026Q3` beta feature), plus the `Operation-Id`, - `Location` and `Retry-After` response headers. Use `statusUrl` with `FetchProfileOperation` to - track the operation. - Additive and backwards compatible: existing request and response fields are unchanged. **Messaging** - Add data access policy admin endpoints (`GET/PUT /v1/Accounts/{AccountSid}/DataAccessPolicy`) to the messaging admin-api, backed by `postflight-messaging-api` (dev-us1 and stage-us1 only) - Enable data access policy admin endpoints (`GET/PUT /v1/Accounts/{AccountSid}/DataAccessPolicy`) in prod-us1 and prod-ie1 **Segment** - # API Changes - ## 2026-11-04 - Add read-only Cob routes: `GET /v1/Segment/Cob/Whoami`, `/Records`, `/Audits`, `/Audits/{Family}/{Name}` - ## 2026-10-30 - Add `GET /v1/Whoami` (One Admin identity check for the Segment oneadmin-gateway) **Trusthub** - Make id, sessionId and sessionToken required and non-nullable in the A2P embedded session response. **(breaking change)** **Voice** - Add internal console ProvisioningStatus endpoint. **Webhooks** - ## 2026-10-28 - **Changed**: Rule `prefix` and `value` are limited to 1000 characters. A `prefix` must end with `/` and a `value` must not. - ## 2026-10-13 - API maturity level changed from `beta` to `ga`. Library visibility changed from `private` to `public`. ### [`v9.12.0`](https://github.com/twilio/twilio-python/blob/HEAD/CHANGES.md#2026-10-12-Version-9120) [Compare Source](https://github.com/twilio/twilio-python/compare/9.11.2...9.12.0) **Audiences** - ## 2026-10-06 - Minor updates (formatting, metadata) - ## 2026-10-05 - Minor updates (formatting, metadata) - ## 2026-10-02 - **Added 1 new path(s)**: - `/preview/Cohorts/{cohortId}/Operations` (AdminListCohortOperations) - ## 2026-10-01 - **Content updates**: - Updated description for `AdminListSnapshotOperations` - ## 2026-09-28 - **Content updates**: - Updated description for `AdminListCohortSnapshots` - Updated description for `AdminFetchCohortSnapshot` - Updated schema description for `Criteria` - Added properties to `OperationPayload`: cohortId - Removed properties from `OperationPayload`: audienceId - Updated schema description for `OperationResult` - Added properties to `OperationResult`: cohortId - Removed properties from `OperationResult`: audienceId - Updated schema description for `Record` - Updated schema description for `Cohort` - ...and 3 more changes - ## 2026-10-01 - Minor updates (formatting, metadata) - ## 2026-09-28 - **Content updates**: - Updated schema description for `CohortOperationResult` - Updated schema description for `PartitionCount` **Conversations** - Add PATCH /v2/Imports/{id} to cancel an import, and the `CANCELED` import status (dev-us1 and stage-us1) - Add Imports endpoints for 1console (private visibility, dev-us1 and stage-us1) - Add `traitExtractionStrategyIds` and `observationExtractionStrategyIds` to the Conversations v2 Admin Configuration schema. - Align the Conversations v2 Capabilities list and create contracts with the backend `domainId` field. **Data-ingress** - ## 2026-10-01 - Minor updates (formatting, metadata) - ## 2026-09-17 - Add support for Hubspot connector - ## 2026-10-01 - Minor updates (formatting, metadata) - ## 2026-09-17 - Add support for Hubspot connector **Events** - Remove the Replays API (`/v1/Replays`, beta feature `api.eventstreams.replay`); the feature was never GA and is being sunset **(breaking change)** **Knowledge** - ## 2026-09-24 - **Routing updates**: - Changed `downstreamServiceName` from `memora-domain` to `enterprise-knowledge-domain` for all operations **Memory** - ## 2026-09-30 - The `source` field on observations and conversation summaries, and the `source` filter - on `ListProfileObservations`, now also accept forward slashes (`/`). The pattern is - `^[a-zA-Z0-9 _./-]+$`. This is additive and backwards compatible: every previously - valid value is still accepted. - `UpdateStore`, `UpdateTraitGroup`, and `UpdateDataMapping` now require a body with at least one property. An empty `{}` gets a 400. **Messaging** - Add opt-out configuration admin endpoints (`GET/PUT/DELETE /v1/Accounts/{AccountSid}/OptOuts/{OptOutSid}/...`) to the messaging admin-api (dev-us1 and stage-us1 only) - Add create opt-out configuration endpoint (`POST /v1/Accounts/{AccountSid}/OptOuts`) to the messaging admin-api (dev-us1 and stage-us1 only) - Add update messaging service endpoint (`PUT /v1/Accounts/{AccountSid}/Services/{MessagingServiceSid}`) to the messaging admin-api (dev-us1 and stage-us1 only) - Enable messaging service add-ons, update messaging service, and opt-out configuration admin endpoints in prod-us1 and prod-ie1 - Add WhatsApp display name change support to Sender API: `pending_display_name`, `pending_display_name_status` and `pending_display_name_status_date` on fetch, and `display_name_status` on update and partial update **Routes** - Set SDK and docs visibility of `GET`/`POST` `/v3/ShortCodes/{isoCountryCode}/{shortCode}` to `public`, maturity to `ga` ### [`v9.11.2`](https://github.com/twilio/twilio-python/blob/HEAD/CHANGES.md#2026-09-28-Version-9112) [Compare Source](https://github.com/twilio/twilio-python/compare/9.11.1...9.11.2) **Twiml** - Add `audio_format` and `sample_rate` to Stream for HDCodec **Api** - # API Changes - ## 2026-09-22 - Simplified the `criteria` field description. - ## 2026-09-18 - Moved `readOnly` on the snapshot count fields (`profileCount`, `partitionCount`) from the shared schema to the response usage sites, so the counts stay read-only in responses (no change for API consumers). - ## 2026-09-17 - Renamed 3 `Get*` operations to `Fetch*` to match the operationId standard: `FetchCohort`, `FetchSnapshot`, `FetchOperation`. - Removed the unused `ExpressionId` schema and made the operation error example cohort-native, so no `aud_` identifiers remain in the spec. - Kept `libraryVisibility: hidden` across the whole surface (info, path items, and operations). - ## 2026-09-08 - Removed the deprecated header-based-versioning unified specs, consolidating audiences onto the path-based `api.twilio.com/v1` surface. - ## 2026-08-31 - Published the unified audiences spec at `api.twilio.com/v1`. - ## 2026-08-26 - Fixed the Cohort operation response mapping in the unified audiences API. - ## 2026-08-19 - Migrated the unified audiences spec to the Cohort surface (Audiences renamed to Cohorts). - Switched `downstreamServiceName` to `audiences-domain`. - ## 2026-08-05 - Added the `api.unified.version.preview` beta feature. - Made the unified APIs available in prod us1. - ## 2026-07-30 - Fixed example values. - ## 2026-07-29 - Added the initial version of the audiences API to the unified APIs. - ## 2026-07-20 - Deployed the audiences-domain OAS to the dev edge. - ## 2026-07-06 - Added the prod-us1 realm to the audiences public API. - ## 2026-06-23 - Changed the `storeType` enum from `MEMORA` to `TWILIO`. - ## 2026-05-04 - Added the stage-us1 realm and `x-rate-limit` to the audiences API. - ## 2026-04-08 - Added the initial audiences endpoints. - Add `TwimlProcessStatusCallbackEvents` parameter to CreateTwimlProcess endpoint - Add `twiml_process` resource alongside `twiml_session` (`twiml_session` is deprecated and will be removed in a future release) **Audiences** - ## 2026-09-14 - Minor updates (formatting, metadata) - ## 2026-09-11 - **Content updates**: - Updated summary for `AdminFetchRecord` - Updated summary for `AdminFetchCohort` - Updated summary for `AdminFetchCohortSnapshot` - Updated summary for `AdminFetchCohortOperation` - Updated schema description for `ResourceLabels` - ## 2026-09-22 - **Content updates**: - Updated schema description for `Criteria` - ## 2026-09-18 - Minor updates (formatting, metadata) - ## 2026-09-17 - Minor updates (formatting, metadata) - ## 2026-09-17 - **Content updates**: - Updated description for `CreateCohort` - Updated description for `ListCohortSnapshots` - Updated description for `CreateCohortSnapshot` - Updated description for `FetchCohortSnapshot` - Updated description for `ListCohortSnapshotProfiles` - Updated schema description for `Criteria` - Updated schema description for `Cohort` - Updated schema description for `CohortSnapshot` - Updated schema description for `CohortOperationResult` - Updated schema description for `CohortOperation` - ## 2026-09-15 - Minor updates (formatting, metadata) - ## 2026-09-14 - **Content updates**: - Updated summary for `FetchCohort` - Updated summary for `FetchCohortSnapshot` - Updated summary for `FetchCohortOperation` - Updated schema description for `ResourceLabels` **Capabilities** - Add a feature-gated preview endpoint to create Capabilities. **Conversations** - Add the feature-gated Capabilities list and create endpoints to Conversations v2. **Data-ingress** - ## 2026-09-07 - Minor updates (formatting, metadata) - ## 2026-09-09 - **Added 16 new path(s)**: - `/v1/DataSyncs/{syncId}` (FetchDataSync) - `/v1/CloudAppSources/{sourceId}/Objects` (ListCloudAppObjects) - `/v1/WarehouseSources/{sourceId}/Preview` (CreateWarehousePreview) - `/v1/WarehouseSources/{sourceId}/Preview/{operationId}` (FetchWarehousePreview) - `/v1/DataSample/{operationId}` (FetchDataSample) - `/v1/ControlPlane/CloudAppSources/{sourceId}` (FetchCloudAppSource, PatchCloudAppSource, DeleteCloudAppSource) - `/v1/ControlPlane/CloudAppSources/{sourceId}/Datasets` (ListCloudAppDatasets, CreateCloudAppDataset) - `/v1/ControlPlane/CloudAppSources/{sourceId}/Datasets/{datasetId}` (FetchCloudAppDataset, PatchCloudAppDataset, DeleteCloudAppDataset) - `/v1/ControlPlane/WarehouseSources/{sourceId}` (FetchWarehouseSource, PatchWarehouseSource, DeleteWarehouseSource) - `/v1/ControlPlane/WarehouseSources/{sourceId}/Datasets` (ListWarehouseDatasets, CreateWarehouseDataset) - ...and 6 more paths - **Removed 31 path(s)**: - `/v1/DataSyncs/{SyncId}` (FetchDataSync) - `/v1/CloudAppSources/{SourceId}/Objects` (ListCloudAppObjects) - `/v1/WarehouseSources/{SourceId}/Preview` (CreateWarehousePreview) - `/v1/WarehouseSources/{SourceId}/Preview/{OperationId}` (FetchWarehousePreview) - `/v1/DataSample/{OperationId}` (FetchDataSample) - `/v1/ControlPlane/CloudAppSources/{SourceId}` (FetchCloudAppSource, PatchCloudAppSource, DeleteCloudAppSource) - `/v1/ControlPlane/CloudAppSources/{SourceId}/Datasets` (ListCloudAppDatasets, CreateCloudAppDataset) - `/v1/ControlPlane/CloudAppSources/{SourceId}/Datasets/{DatasetId}` (FetchCloudAppDataset, PatchCloudAppDataset, DeleteCloudAppDataset) - `/v1/ControlPlane/WarehouseSources/{SourceId}` (FetchWarehouseSource, PatchWarehouseSource, DeleteWarehouseSource) - `/v1/ControlPlane/WarehouseSources/{SourceId}/Datasets` (ListWarehouseDatasets, CreateWarehouseDataset) - ...and 21 more paths **Destinations** - ## 2026-09-24 - **Content updates**: - Removed `GET` from the `method` enum on the `webhook` destination type's config options - ## 2026-09-22 - **Content updates**: - Added `CDP` to the `categories` enum on `DestinationType` - ## 2026-09-14 - Enable admin APIs for stage-us1 and prod-ie1 realms - ## 2026-09-11 - **Content updates**: - Updated description for `CreateDestination` - Updated description for `UpdateDestination` - Updated description for `DeleteDestination` - Updated schema description for `CredentialInput` - Updated schema description for `DestinationCredentialOptions` - ## 2026-09-11 - **Content updates**: - Updated description for `ListDestinationTypes` - Updated description for `GetDestinationType` - Updated description for `CreateDestination` - Updated description for `UpdateDestination` - ## 2026-09-10 - Made `ListDestinationTypes` and `GetDestinationType` unauthenticated (`security: []`). - Removed `iamOperation`, `addAuthorizationHeader`, and `betaFeature` from these operations. **Iam** - Removed user\_context from the POST /v1/actions/post\_login (PostLoginActionRequest) webhook payload; the login email is read from authentication\_context.methods - Replaced acr and completed\_factors with authentication\_context (acr, amr, methods) on the POST /v1/actions/post\_login (PostLoginActionRequest) webhook payload - Made request\_context and request\_context.ip\_address required on the POST /v1/actions/post\_login (PostLoginActionRequest) webhook payload **Intelligence** - Added optional `rule.operators[]` parameter override field to \`POST /v3/RuleExecutions - Change Summary in `POST /v3/RuleExecutions` **Knowledge** - ## 2026-09-23 - **Content updates**: - Added properties to `WebSourceDetails`: errors - **Routing updates**: - Changed `downstreamServiceName` from `memora-domain` to `enterprise-knowledge-domain` for all operations **Memory** - ## 2026-09-18 - **Added 2 new path(s)**: - `/v1/ControlPlane/TraitExtractionStrategies` (AdminListTraitExtractionStrategies) - `/v1/ControlPlane/TraitExtractionStrategies/{traitStrategyId}` (AdminFetchTraitExtractionStrategy) - ## 2026-09-03 - No path changes (schema description only) - Clarified the `DataMappingCore` description: the PATCH body requires at least one field. - ## 2026-09-10 - **Added 2 new path(s)** for Observation Extraction Strategies: - `/v1/ControlPlane/ObservationExtractionStrategies` (ListObservationExtractionStrategies, CreateObservationExtractionStrategy) - `/v1/ControlPlane/ObservationExtractionStrategies/{observationExtractionStrategyId}` (FetchObservationExtractionStrategy, UpdateObservationExtractionStrategy, DeleteObservationExtractionStrategy) - **Content updates**: - Updated `CreateObservationExtractionStrategyInput` description to document that at least one of `allowedCategories`/`prohibitedCategories` must be provided with a non-empty list - ## 2026-09-07 - **Added 1 new path(s)** for Profile: - `/v1/Stores/{storeId}/Profiles/BulkDeletions` (CreateProfilesBulkDeletion) - ## 2026-09-03 - `UpdateStore`, `UpdateTraitGroup`, `UpdateDataMapping`, and `UpdateTraitExtractionStrategy` now require a body with at least one property. An empty `{}` gets a 400. **Routes** - Add `GET`/`POST` `/v3/ShortCodes/{isoCountryCode}/{shortCode}` to assign and fetch the Inbound Processing Region for short codes **Verify** - Add `aaguid` and `date_last_approved` to passkeys factors `metadata`. **Voice** - Add typed Recording AccountDefaultConfiguration public API endpoints. **Webhooks** - ## 2026-09-24 - **Changed**: `GET /v1/Webhooks/Settings` now documents each item as the full `Setting` rather than `SettingSummary`, adding `auth`, `signature`, `connection` and `edgeZones` to the list response. The service already returned these fields; only the schema understated them. Additive for consumers — no field is removed or renamed. The now-unreferenced `SettingSummary` schema is removed. ### [`v9.11.1`](https://github.com/twilio/twilio-python/blob/HEAD/CHANGES.md#2026-09-09-Version-9111) [Compare Source](https://github.com/twilio/twilio-python/compare/9.11.0...9.11.1) **Library - Fix** - [PR #&#8203;954](https://github.com/twilio/twilio-python/pull/954): Fix tag validation regex in deploy.yml. Thanks to [@&#8203;kridai](https://github.com/kridai)! **Audiences** - ## 2026-09-01 - Backticked brace- and angle-bracket-bearing tokens in descriptions for MDX safety. - Updated a prose reference to the renamed `FetchCohortSnapshot` operation. - ## 2026-08-26 - **Removed 5 path(s)**: - `/preview/Audiences` (AdminListAudiences) - `/preview/Audiences/{audienceId}` (AdminGetAudience) - `/preview/Snapshots` (AdminListSnapshots) - `/preview/Snapshots/{snapshotId}` (AdminGetSnapshot) - `/preview/Operations/{operationId}` (AdminGetOperation) - ## 2026-08-25 - Minor updates (formatting, metadata) - ## 2026-08-24 - **Added 1 new path(s)**: - `/preview/Snapshots/{cohortSnapshotId}/Operations` (AdminListSnapshotOperations) - **Removed 1 path(s)**: - `/preview/Snapshots/{snapshotId}/Operations` (ListAdminSnapshotOperations) - ## 2026-08-20 - Renamed all 13 operations so the operationId keyword leads (`AdminGetCohort` -> `FetchAdminCohort`) to meet standard. - Set `info` `libraryVisibility` to `hidden` to exclude this admin spec from generation. - Added the standard `pageSize`/`pageToken` query parameters to `ListAdminSnapshotOperations`, the only list operation missing them. - ## 2026-08-19 - **Added 5 new path(s)**: - `/preview/Cohorts` (AdminListCohorts) - `/preview/Cohorts/{cohortId}` (AdminGetCohort) - `/preview/CohortSnapshots` (AdminListCohortSnapshots) - `/preview/CohortSnapshots/{cohortSnapshotId}` (AdminGetCohortSnapshot) - `/preview/CohortOperations/{cohortOperationId}` (AdminGetCohortOperation) - ## 2026-09-01 - Renamed 3 `Get*` operations to `Fetch*` to match the operationId standard: `FetchCohort`, `FetchCohortSnapshot`, `FetchCohortOperation`. The transpiler skips operations whose operationId does not start with a standard keyword, which had been dropping all three from generated output. - Set `libraryVisibility` to `private` (was `hidden`) so the spec is eligible for the private docs pipeline. - Backticked brace- and angle-bracket-bearing tokens in descriptions for MDX safety. - ## 2026-08-28 - **Removed 6 path(s)**: - `/preview/Audiences` (ListAudiences, CreateAudience) - `/preview/Audiences/{audienceId}` (FetchAudience, UpdateAudience, DeleteAudience) - `/preview/Snapshots` (ListSnapshots, CreateSnapshot) - `/preview/Snapshots/{snapshotId}` (FetchSnapshot, DeleteSnapshot) - `/preview/Snapshots/{snapshotId}/Profiles` (ListSnapshotProfiles) - `/preview/Operations/{operationId}` (FetchOperation) - ## 2026-08-20 - Renamed 6 `Get*` operations to `Fetch*` to match the operationId standard. - Hid the deprecated Audiences/Snapshots paths and `/preview/Operations/{operationId}`. - Backticked 11 brace-bearing tokens in descriptions for MDX safety. **Conversations** - Add PATCH support for partial updates to Configuration - Add `VIDEO` to the Conversations v2 Communication channel enum. **Data-ingress** - # API Changes - ## 2026-09-01 - Minor updates (formatting, metadata) - ## 2026-08-12 - Minor updates (formatting, metadata) - ## 2026-08-12 - Initial release with 13 paths and 13 operations **Destinations** - ## 2026-09-08 - Added `prod-ie1` to `supportedRealms` and `iamOperationEnabledRealms` for all endpoints - ## 2026-09-01 - Removed the unused `admin-api` placeholder from `supportedRealms` on the public endpoints; - One Admin routes now live in `admin_openapi.yaml`. - **Added 6 new path(s)** (admin\_openapi.yaml): - `/v1/ControlPlane/Destinations` (AdminListDestinations) - `/v1/ControlPlane/Destinations/{destinationId}` (AdminGetDestination) - `/v1/ControlPlane/Subscriptions` (AdminListSubscriptions) - `/v1/ControlPlane/Subscriptions/{subscriptionId}` (AdminGetSubscription) - `/v1/ControlPlane/Subscriptions/{subscriptionId}/EventTypes` (AdminListSubscribedEvents) - `/v1/ControlPlane/Subscriptions/{subscriptionId}/EventTypes/{eventType}` (AdminGetSubscribedEvent) - ## 2026-08-26 - Minor updates (formatting, metadata) - ## 2026-08-26 - Minor updates (formatting, metadata) - ## 2026-08-25 - **Content updates**: - Updated description for `CreateDestination` - ## 2026-08-12 - Minor updates (formatting, metadata) - ## 2026-08-12 - **Content updates**: - Added properties to `DestinationType`: releaseStatus - Removed properties from `DestinationType`: maturity **Email** - # API Changes - ## 2026-09-02 - **Added 1 new path(s)**: - `/v1/Sends/Cohorts` (sendCohort) - ## 2026-08-28 - **Content updates**: - Updated summary for `sendTransactional` - Added parameter(s) to `sendTransactional`: X-Twilio-Version - Updated schema description for `SuppressionsGroup` - Added properties to `SuppressionsGroup`: type - Removed properties from `SuppressionsGroup`: mode - Updated schema description for `SuppressionsGlobal` - Added properties to `SuppressionsGlobal`: type - Removed properties from `SuppressionsGlobal`: mode - Updated schema description for `Suppressions` - Updated schema description for `LongRunningOperationResponse` - ## 2026-08-27 - **Content updates**: - Updated description for `SendEmail` - Added parameter(s) to `SendEmail`: Content-Encoding, Idempotency-Key - Updated schema description for `Envelope` - Updated schema description for `SuppressionsGroup` - Updated schema description for `SuppressionsGlobal` **Iam** - Removed redirect\_urls from the GET /v1/Account/AuthorizedApps/{consentSid} response - Added company\_name, homepage\_url, tos\_url, and redirect\_urls to the GET /v1/Account/AuthorizedApps/{consentSid} response - Added GET /v1/Account/AuthorizedApps/{consentSid} - fetch authorized app details, including allowed permissions, by consent identifier SID - added container-scoped entitlements endpoint (GET /v2/Container/{containerId}/Entitlements) **Instrumentation** - # API Changes - ## 2026-09-04 - **Content updates**: - Added `IdempotencyKeyHeader` to Create/Patch/Delete `AutoInstrumentationRule`; corrected the shared header's description - Added `operationId`/`createdAt` to `LongRunningOperationResponse`; corrected example `status` from `RUNNING` to `PENDING` - Renamed `Signal.timestamp` → `occurredAt`, `HourlyStats.hourTimestamp` → `hourAt`; uppercased `Signal.type` and `ListSignals`' `signalType` enums to SCREAMING\_SNAKE\_CASE - Renamed `UserBehaviors` request/response fields to camelCase; added the `summaryDelivery` webhook callback - Reshaped `PaginationMeta` (added required `key`, corrected `pageSize` bounds) and all 6 list operations (`ListEventSources`, `ListEventSourceDatasets`, `ListEventSchemas`, `ListAutoInstrumentationRules`, `ListSignals`, `ListSignalStats`) to the `meta` envelope; added `ListSignalStats`' `500` response - Narrowed the domain's default `supportedRealms` to `dev-us1` only; `POST /v1/UserBehaviors` (`AnalyzeUserBehaviors`) keeps its own `dev-us1`/`stage-us1` override (prod withheld pending stage validation) — every other operation is now dev-only - ## 2026-08-31 - **Content updates**: - Fixed stale `tdi_` TTID prefix throughout (path params, examples, transaction URLs) to `events_`; unified dataset/schema ID formats (`tdi_dat_`/`tdi_dataset_` → `events_dataset_`, `tdi_schema_` → `events_evsch_`); fixed rule-version examples to match the real `version: integer` field - Fixed `operationId` to use the domain-agnostic `proc_job_` TTID prefix; corrected the `OperationId` parameter's length constraint (`max=34` → `max=35`) and added a `pattern` - Fixed two length constraints hardcoded for the old `tdi_` prefix length: `IngestEventBatch`'s `sourceId` path parameter (`maxLength` 37 → 40); removed the stale, redundant `Twilio-Write-Key` header parameter - Added the missing `AutoInstrumentationRuleId` regex `pattern` - Fixed `info.title` ("Twilio Data Ingress - Instrumentation API" → "Events Domain - Instrumentation API") - **Added 1 new API path**: - `/v1/UserBehaviors` (AnalyzeUserBehaviors) - ## 2026-07-28 - **Initial release** — 21 paths, 37 operations across three API surfaces: - **Control Plane** (`/v1/ControlPlane/…`): - `/v1/ControlPlane/EventSources` (CreateEventSource, ListEventSources) - `/v1/ControlPlane/EventSources/{sourceId}` (FetchEventSource, PatchEventSource, DeleteEventSource) - `/v1/ControlPlane/EventSources/{sourceId}/WriteKeys` (CreateWriteKey, ListWriteKeys) - `/v1/ControlPlane/EventSources/{sourceId}/WriteKeys/{writeKey}` (DeleteWriteKey) - `/v1/ControlPlane/EventSources/{sourceId}/Datasets` (CreateEventSourceDataset, ListEventSourceDatasets) - `/v1/ControlPlane/EventSources/{sourceId}/Datasets/{datasetId}` (FetchEventSourceDataset, PatchEventSourceDataset, DeleteEventSourceDataset) - `/v1/ControlPlane/EventSources/{sourceId}/EventSchemas` (CreateEventSchema, ListEventSchemas) - `/v1/ControlPlane/EventSources/{sourceId}/EventSchemas/{schemaId}` (FetchEventSchema, PatchEventSchema, DeleteEventSchema) - `/v1/ControlPlane/EventSources/{sourceId}/AutoInstrumentationRules` (CreateAutoInstrumentationRule, ListAutoInstrumentationRules) - `/v1/ControlPlane/EventSources/{sourceId}/AutoInstrumentationRules/{autoInstrumentationRuleId}` (FetchAutoInstrumentationRule, PatchAutoInstrumentationRule, DeleteAutoInstrumentationRule) - `/v1/ControlPlane/EventSources/{sourceId}/AutoInstrumentationRules/{autoInstrumentationRuleId}/Versions` (ListAutoInstrumentationRuleVersions) - `/v1/ControlPlane/EventSources/{sourceId}/AutoInstrumentationRules/{autoInstrumentationRuleId}/Versions/{version}` (FetchAutoInstrumentationRuleVersion) - `/v1/ControlPlane/Datasets` (ListDatasets) - `/v1/ControlPlane/Datasets/{datasetId}` (FetchDataset) - `/v1/ControlPlane/Operations/{operationId}` (FetchControlPlaneOperationStatus) - `/v1/ControlPlane/Datasets` (ListDatasets) - `/v1/ControlPlane/Datasets/{datasetId}` (FetchDataset) - **Event Ingestion** (`/v1/EventSources/…`): - `/v1/EventSources/{sourceId}/Batch` (IngestEventBatch) - `/v1/EventSources/{sourceId}/AutoInstrumentationRules/{autoInstrumentationRuleId}/Preview` (TriggerAutoInstrumentationPreview) - `/v1/EventSources/{sourceId}/AutoInstrumentationRules/{autoInstrumentationRuleId}/Preview/{operationId}` (GetAutoInstrumentationPreviewResult) - **Signal API** (`/v1/EventSources/…`): - `/v1/EventSources/{sourceId}/Signals` (IngestSignals, ListSignals) - `/v1/EventSources/{sourceId}/Signals/{signalKey}` (GetSignalBySignalKey) - `/v1/EventSources/{sourceId}/SignalStats` (ListSignalStats) **Knowledge** - ## 2026-07-20 - **Content updates**: - Added new schemas: `KnowledgeErrorInstance`, `KnowledgeErrorGroup` - Added `errors` field to `WebSourceDetails` for reporting web crawl errors **Memory** - ## 2026-08-18 - **Breaking change**: - Removed the deprecated `CSV` and `DATASET` values from the `DataMappingType` enum. - `INGRESS`, `DATASET_CLOUDAPP`, and `DATASET_WAREHOUSE` are the only valid values now. - Removed the `DataMappingFromCSV` and `DataMappingFromDataSet` schemas and their - `oneOf`/discriminator entries on `DataMappingFromTypes`, along with the corresponding - `CSV`/`DATASET` discriminator mapping keys. - Any caller still sending `type: CSV` or `type: DATASET` on `AdminListDataMappings` - (filtering by those values) will get a 400. - ## 2026-08-10 - No path changes (updated metadata only) - `DataMappingType` gains `INGRESS`, `DATASET_CLOUDAPP`, and `DATASET_WAREHOUSE`. - `CSV` and `DATASET` remain valid and unchanged; they are deprecated aliases and - will be removed in a follow-up change. - `DataMappingFromTypes` gains three `oneOf` members and three discriminator keys: - `DataMappingFromIngress` (renames `DataMappingFromCSV`), - `DataMappingFromCloudAppDataSet` and `DataMappingFromWarehouseDataSet` - (both split from `DataMappingFromDataSet`, distinguishing a cloud-app-backed - TDI dataset from a warehouse-backed one). - Additive and backwards compatible: existing `CSV` and `DATASET` payloads are - unaffected. - ## 2026-08-27 - **Added 2 new path(s)** for Trait Extraction Strategies: - `/v1/ControlPlane/TraitExtractionStrategies` (ListTraitExtractionStrategies, CreateTraitExtractionStrategy) - `/v1/ControlPlane/TraitExtractionStrategies/{traitStrategyId}` (FetchTraitExtractionStrategy, UpdateTraitExtractionStrategy, DeleteTraitExtractionStrategy) - ## 2026-08-18 - **Breaking change**: - Removed the deprecated `CSV` and `DATASET` values from the `DataMappingType` enum. - `INGRESS`, `DATASET_CLOUDAPP`, and `DATASET_WAREHOUSE` are the only valid values now. - Removed the `DataMappingFromCSV` and `DataMappingFromDataSet` schemas and their - `oneOf`/discriminator entries on `DataMappingFromTypes`, along with the corresponding - `CSV`/`DATASET` discriminator mapping keys. - Any caller still sending `type: CSV` or `type: DATASET` on `CreateDataMapping` or - `UpdateDataMapping` (or filtering `ListDataMappings`/`ListDataMappingSuggestions` by - those values) will get a 400. - ## 2026-08-10 - No path changes (updated metadata only) - `DataMappingType` gains `INGRESS`, `DATASET_CLOUDAPP`, and `DATASET_WAREHOUSE`. - `CSV` and `DATASET` remain valid and unchanged; they are deprecated aliases and - will be removed in a follow-up change. - `DataMappingFromTypes` gains three `oneOf` members and three discriminator keys: - `DataMappingFromIngress` (renames `DataMappingFromCSV`), - `DataMappingFromCloudAppDataSet` and `DataMappingFromWarehouseDataSet` - (both split from `DataMappingFromDataSet`, distinguishing a cloud-app-backed - TDI dataset from a warehouse-backed one). - Additive and backwards compatible: existing `CSV` and `DATASET` payloads are - unaffected. **Messaging** - Add SenderIdentity, SenderType, and SenderRegion filter query parameters to list numbers and senders endpoint (beta) - Add capabilities field to the numbers and senders response (beta) - Remove the WhatsApp Senders v1 endpoints (`/v1/Channels/WhatsApp/Senders`) from RestProxy; the sender was routed to the sunsetting `messaging-whatsapp-k8s-orch` downstream. Use the Senders v2 API (`/v2/Channels/Senders`) instead. **Verify** - Add `Templates` optional parameter on Verification creation (a stringified JSON array of `sid`/`substitutions` entries). When provided, `Templates` takes precedence over `TemplateSid`. **Voice** - ## 2026-09-03 - Added `links.conversation` to Transcription resources as the absolute Conversations API URL for the - transcript's `conversationId`. It is present once the transcript has been stored; the `links` object - is omitted otherwise. - ## 2026-09-01 - Removed `mediaUrl` from `CreateRequestWithMediaUrl`'s required fields so a request with neither `sourceId` nor `mediaUrl` reaches the downstream service, which rejects it with the specific error code 17500 instead of a generic gateway 400 - Set `additionalProperties: false` on both `CreateRequestWithSourceId` and `CreateRequestWithMediaUrl` so the two `oneOf` variants stay mutually exclusive: `sourceId` is undeclared on the media-URL variant and `mediaUrl` is undeclared on the source-ID variant, keeping every request shape resolvable to exactly one variant - ## 2026-08-05 - Added GET /v3/Transcriptions to list and filter transcriptions (status, sourceId, languageCode, createdAfter/createdBefore) with pageSize/pageToken pagination. createdAfter is inclusive and createdBefore exclusive. Returns 422 (error code 17535) when a sourceId's historical item count exceeds the service scan cap **Webhooks** - # API Changes - ## 2026-08-24 - **Changed**: Created Webhooks Config API ( <https://docs.google.com/document/d/1zkAJD8a8MgoxWifdYDl_d465Az3W6CcD9fuCC2xlSXE/edit?tab=t.0#heading=h.u9e0ry6oe89j> ), that includes 7 new resource(s)\*\*: SharedKeys, AuthProfiles, Settings, Rules, Operations, Tests, EdgeZones in /v1/Webhooks referencing webhooks-config downstream. ### [`v9.11.0`](https://github.com/twilio/twilio-python/blob/HEAD/CHANGES.md#2026-08-11-Version-9110) [Compare Source](https://github.com/twilio/twilio-python/compare/9.10.9...9.11.0) **Library - Fix** - [PR #&#8203;929](https://github.com/twilio/twilio-python/pull/929): mock HTTP session in TestUserAgentClients to avoid live network calls. Thanks to [@&#8203;shrutiburman](https://github.com/shrutiburman)! **Twiml** - Remove `<Assistant>` noun from `<Connect>` verb as part of the AI Assistants deprecation **(breaking change)** - Add `passports` attribute to `<Dial>` verb for SHAKEN/STIR passport passthrough **Accounts** - Add `SuppressEmailNotification` parameter to the Secondary Auth Token and Auth Token promotion endpoints. Set it to `true` to suppress the email notification sent to account owners and administrators. Defaults to `false`, preserving existing behavior. - Add SMS Pumping Protection GET and POST API **Ai** - Removing ai workbench apis **Api** - Add missing `uri` property to the `twiml_session` resource **Data-ingress** - ## 2026-08-07 - **Removed 1 API path**: - `/v1/DataQuery` (Realtime DataQuery) - ## 2026-07-07 - **Added 1 new API path (data plane)**: - `/v1/DataQuery` (Realtime DataQuery) - ## 2026-06-17 - **Content updates**: - Added properties to `OAuthJWTBearerCredentials`: privateKey, privateKeyPassphrase - ## 2026-06-12 - **Added 16 new path(s)**: - `/v1/DataSyncs/{syncId}` (FetchDataSync) - `/v1/CloudAppSources/{sourceId}/Objects` (ListCloudAppObjects) - `/v1/WarehouseSources/{sourceId}/Preview` (CreateWarehousePreview) - `/v1/WarehouseSources/{sourceId}/Preview/{operationId}` (FetchWarehousePreview) - `/v1/DataSample/{operationId}` (FetchDataSample) - `/v1/ControlPlane/CloudAppSources/{sourceId}` (FetchCloudAppSource, PatchCloudAppSource, DeleteCloudAppSource) - `/v1/ControlPlane/CloudAppSources/{sourceId}/Datasets` (ListCloudAppDatasets, CreateCloudAppDataset) - `/v1/ControlPlane/CloudAppSources/{sourceId}/Datasets/{datasetId}` (FetchCloudAppDataset, PatchCloudAppDataset, DeleteCloudAppDataset) - `/v1/ControlPlane/WarehouseSources/{sourceId}` (FetchWarehouseSource, PatchWarehouseSource, DeleteWarehouseSource) - `/v1/ControlPlane/WarehouseSources/{sourceId}/Datasets` (ListWarehouseDatasets, CreateWarehouseDataset) - ...and 6 more paths - **Removed 16 path(s)**: - `/v1/DataSyncs/{SyncId}` (FetchDataSync) - `/v1/CloudAppSources/{SourceId}/Objects` (ListCloudAppObjects) - `/v1/WarehouseSources/{SourceId}/Preview` (CreateWarehousePreview) - `/v1/WarehouseSources/{SourceId}/Preview/{OperationId}` (FetchWarehousePreview) - `/v1/DataSample/{OperationId}` (FetchDataSample) - `/v1/ControlPlane/CloudAppSources/{SourceId}` (FetchCloudAppSource, PatchCloudAppSource, DeleteCloudAppSource) - `/v1/ControlPlane/CloudAppSources/{SourceId}/Datasets` (ListCloudAppDatasets, CreateCloudAppDataset) - `/v1/ControlPlane/CloudAppSources/{SourceId}/Datasets/{DatasetId}` (FetchCloudAppDataset, PatchCloudAppDataset, DeleteCloudAppDataset) - `/v1/ControlPlane/WarehouseSources/{SourceId}` (FetchWarehouseSource, PatchWarehouseSource, DeleteWarehouseSource) - `/v1/ControlPlane/WarehouseSources/{SourceId}/Datasets` (ListWarehouseDatasets, CreateWarehouseDataset) - ...and 6 more paths - ## 2026-06-11 - **Added 3 new Signal API path(s) for public exposure (data plane)**: - `/v1/EventSources/{sourceId}/Signals` (ListSignals) - `/v1/EventSources/{sourceId}/Signals/{signalKey}` (GetSignalBySignalKey) - `/v1/EventSources/{sourceId}/SignalStats` (ListSignalStats) - **Added new Signal API schemas**: - Signal, SignalListResponse, HourlyStats, SignalStatsResponse - ## 2026-05-26 - **Added 12 new path(s) for public exposure**: - `/v1/ControlPlane/EventSources` (CreateEventSource, ListEventSources) - `/v1/ControlPlane/EventSources/{SourceId}` (FetchEventSource, PatchEventSource, DeleteEventSource) - `/v1/ControlPlane/EventSources/{SourceId}/WriteKeys` (CreateWriteKey, ListWriteKeys) - `/v1/ControlPlane/EventSources/{SourceId}/WriteKeys/{WriteKey}` (DeleteWriteKey) - `/v1/ControlPlane/EventSources/{SourceId}/Datasets` (CreateEventSourceDataset, ListEventSourceDatasets) - `/v1/ControlPlane/EventSources/{SourceId}/Datasets/{DatasetId}` (FetchEventSourceDataset, PatchEventSourceDataset, DeleteEventSourceDataset) - `/v1/ControlPlane/EventSources/{SourceId}/EventSchemas` (CreateEventSchema, ListEventSchemas) - `/v1/ControlPlane/EventSources/{SourceId}/EventSchemas/{SchemaId}` (FetchEventSchema, PatchEventSchema, DeleteEventSchema) - `/v1/ControlPlane/AutoInstrumentationRule` (CreateAutoInstrumentationRule, ListAutoInstrumentationRules) - `/v1/ControlPlane/AutoInstrumentationRule/{AutoInstrumentationRuleId}` (FetchAutoInstrumentationRule, PatchAutoInstrumentationRule, DeleteAutoInstrumentationRule) - `/v1/ControlPlane/AutoInstrumentationRule/{AutoInstrumentationRuleId}/Versions` (ListAutoInstrumentationRuleVersions) - `/v1/ControlPlane/AutoInstrumentationRule/{AutoInstrumentationRuleId}/Versions/{Version}` (FetchAutoInstrumentationRuleVersion) - **Added new schemas**: - EventSource, EventSourceCreate, EventSourceUpdate - WriteKey, WriteKeyCreate - EventSourceDataset, EventSourceDatasetCreate, EventSourceDatasetUpdate - EventSchema, EventSchemaCreate, EventSchemaUpdate, EventSchemaField, EventSchemaProperty - AutoInstrumentationRule, AutoInstrumentationRuleCreate, AutoInstrumentationRuleUpdate - AutoInstrumentationRuleVersion, AutoInstrumentationRuleVersionsResponse - ## 2026-06-12 - **Added 16 new path(s)**: - `/v1/DataSyncs/{syncId}` (FetchDataSync) - `/v1/CloudAppSources/{sourceId}/Objects` (ListCloudAppObjects) - `/v1/WarehouseSources/{sourceId}/Preview` (CreateWarehousePreview) - `/v1/WarehouseSources/{sourceId}/Preview/{operationId}` (FetchWarehousePreview) - `/v1/DataSample/{operationId}` (FetchDataSample) - `/v1/ControlPlane/CloudAppSources/{sourceId}` (FetchCloudAppSource, PatchCloudAppSource, DeleteCloudAppSource) - `/v1/ControlPlane/CloudAppSources/{sourceId}/Datasets` (ListCloudAppDatasets, CreateCloudAppDataset) - `/v1/ControlPlane/CloudAppSources/{sourceId}/Datasets/{datasetId}` (FetchCloudAppDataset, PatchCloudAppDataset, DeleteCloudAppDataset) - `/v1/ControlPlane/WarehouseSources/{sourceId}` (FetchWarehouseSource, PatchWarehouseSource, DeleteWarehouseSource) - `/v1/ControlPlane/WarehouseSources/{sourceId}/Datasets` (ListWarehouseDatasets, CreateWarehouseDataset) - ...and 6 more paths - **Removed 16 path(s)**: - `/v1/DataSyncs/{SyncId}` (FetchDataSync) - `/v1/CloudAppSources/{SourceId}/Objects` (ListCloudAppObjects) - `/v1/WarehouseSources/{SourceId}/Preview` (CreateWarehousePreview) - `/v1/WarehouseSources/{SourceId}/Preview/{OperationId}` (FetchWarehousePreview) - `/v1/DataSample/{OperationId}` (FetchDataSample) - `/v1/ControlPlane/CloudAppSources/{SourceId}` (FetchCloudAppSource, PatchCloudAppSource, DeleteCloudAppSource) - `/v1/ControlPlane/CloudAppSources/{SourceId}/Datasets` (ListCloudAppDatasets, CreateCloudAppDataset) - `/v1/ControlPlane/CloudAppSources/{SourceId}/Datasets/{DatasetId}` (FetchCloudAppDataset, PatchCloudAppDataset, DeleteCloudAppDataset) - `/v1/ControlPlane/WarehouseSources/{SourceId}` (FetchWarehouseSource, PatchWarehouseSource, DeleteWarehouseSource) - `/v1/ControlPlane/WarehouseSources/{SourceId}/Datasets` (ListWarehouseDatasets, CreateWarehouseDataset) - ...and 6 more paths **Deletions** - # API Changes - ## 2026-06-23 - Initial public Rest Proxy registration for the User Data Deletions API - (`POST` / `GET /v1/UserDataDeletions`, `GET /v1/UserDataDeletions/{deletionId}`, - `GET /v1/Operations/{operationId}`). - A single request may mix identifier formats: E.164 phone numbers, email - addresses, and profile IDs. **Destinations** - # API Changes - ## 2026-08-07 - **Content updates**: - Updated summary for `ListDestinationSupportedEventTypes` - ## 2026-08-07 - **Content updates**: - Updated summary for `ListDestinationSupportedEventTypes` - ## 2026-08-07 - **Added 3 new path(s)**: - `/v1/Catalog/DestinationSupportedEventTypes` (ListDestinationSupportedEventTypes) - `/v1/ControlPlane/Subscriptions/{subscriptionId}/EventTypes` (ListSubscribedEvents, CreateSubscribedEvent) - `/v1/ControlPlane/Subscriptions/{subscriptionId}/EventTypes/{eventType}` (GetSubscribedEvent, UpdateSubscribedEvent, DeleteSubscribedEvent) - **Removed 3 path(s)**: - `/v1/ControlPlane/Subscriptions/{subscriptionId}/SubscribedEvents` (ListSubscribedEvents, CreateSubscribedEvent) - `/v1/ControlPlane/Subscriptions/{subscriptionId}/SubscribedEvents/{eventType}` (GetSubscribedEvent, UpdateSubscribedEvent, DeleteSubscribedEvent) - `/v1/Catalog/DestinationEventTypes` (ListDestinationEventTypes) - ## 2026-08-04 - Minor updates (formatting, metadata) - ## 2026-08-04 - Minor updates (formatting, metadata) - ## 2026-08-04 - Minor updates (formatting, metadata) - ## 2026-08-04 - Minor updates (formatting, metadata) - ## 2026-08-04 - **Content updates**: - Added properties to `SubscriptionResponse`: eventTypes - ## 2026-08-03 - **Content updates**: - Added properties to `DestinationType`: documentationUrl, maturity, tier, categories - ## 2026-07-27 - Minor updates (formatting, metadata) - ## 2026-07-23 - **Content updates**: - `meta` is now a required property in the response of `ListDestinations`, `ListSubscriptions`, and `ListSubscribedEvents` - `CreateSubscribedEvent` request body schema consolidated onto `SubscribedEventInput` (previously `SubscribedEventCreate`, a duplicate schema) - Added response examples for `ListDestinations`, `ListSubscriptions`, and `ListSubscribedEvents` - ## 2026-07-23 - **Added 1 new path(s)**: - `/v1/Catalog/DestinationEventTypes` (ListDestinationEventTypes) - ## 2026-07-22 - **Content updates**: - Added parameter(s) to `ListDestinations`: namePrefix - Updated description for `UpdateSubscription` - Added properties to `SubscriptionUpdate`: eventTypes - ## 2026-07-16 - Initial release with 9 paths and 18 operations **Events** - Add `stage-ie1` realm support for EventTypes and Schemas endpoints (datataps-catalog) **Memory** - ## 2026-08-10 - Removed `Events` endpoints from the spec, as they were hidden, never implemented, and are not part of the public API - ## 2026-08-07 - **New functionality**: - Added `pageSize`, `pageToken`, and `orderBy` query parameters to `ListProfileImportsV2`, plus a `meta` object in its response, to support pagination. - **Content updates**: - Updated the `ListProfileImportsV2` description to document the new pagination behavior. - Corrected the example presigned upload URL on `CreateProfilesImportV2` to match the real S3 bucket naming convention. - Corrected the `meta.key` example on `ListProfileTraits`'s response (was `profiles`, now `traits`) to accurately describe which response field it points to. - ## 2026-08-07 - **Content updates**: - Updated `matchingRules` description in `IdentityResolutionSettingsCore` to remove compound `AND` rule documentation - ## 2026-07-30 - **Content updates**: - Increased the maximum value for the Twilio error `code` from `99999` to `999999` - ## 2026-07-28 - **Content updates**: - Updated the `pageSize` description on the pagination `Meta` schema to clarify it reflects the number of items actually returned, not the requested or default page size. - ## 2026-07-13 - **Content updates**: - Renamed `ListProfiles` response schema references from `ProfileID`/`ProfilesMeta` to `IdentityProfileID`/`IdentityProfilesMeta` (new `IdentityProfilesMeta` schema added; `ProfileID`/`ProfilesMeta` retained for other operations). - ## 2026-07-08 - **Content updates**: - Updated description for `CreateDataMappingSuggestion` - Updated description for `FetchDataMappingSuggestion` - ## 2026-07-06 - **Added 2 new path(s)**: - `/v1/ControlPlane/Stores/{storeId}/DataMappings/Suggestions` (ListDataMappingSuggestions, CreateDataMappingSuggestion) - `/v1/ControlPlane/Stores/{storeId}/DataMappings/Suggestions/{suggestionId}` (FetchDataMappingSuggestion) - ## 2026-06-26 - **Content updates**: - Minor updates (formatting, metadata) - Updated x-twilio location parameter from `instance` to `list` for all endpoints that don't end with a /{param} - Updated description for `UpdateProfileTraits` - Updated summary for `UpdateProfileTraits` - Removed properties from `MappingTraitItem`: fieldName - Removed `additionalProperties` from `allof` schemas since it isn't supported and causes invalid lint errors on example blocks. - matruity ga and libraryVisibility public - ## 2026-06-24 - **Content updates**: - Add ConversationID as an optional query parameter for ListObservations and ListConversationSummaries - ## 2026-05-01 - **Content updates**: - Updated description & summary for `UpdateProfileTraits` - Updated description for `FetchIdentityResolutionSettings` - Removed properties from `MappingTraitItem`: fieldName - Updated patch Observations to not require `occurredAt`, `content`, or `source` - ## 2026-04-28 - **Content updates**: - Updated description for `UpdateProfileTraits` - Updated summary for `UpdateProfileTraits` - Added properties to `TraitDefinition`: validationRule - Removed properties from `MappingTraitItem`: fieldName **Messaging\_admin** - Add Intelligent Alerts endpoints at `/v1/Messaging/IntelligentAlertsEvents/*`, routing to intelligent-alerts-api via messaging-monkey-backend. Account SID is a required query parameter (`accountSid`) on all three endpoints. </details> <details> <summary>Kludex/uvicorn (uvicorn)</summary> ### [`v0.54.0`](https://github.com/Kludex/uvicorn/releases/tag/0.54.0): Version 0.54.0 [Compare Source](https://github.com/Kludex/uvicorn/compare/0.53.0...0.54.0) #### 📨 Send metadata after the response body `uvicorn` 0.54.0 adds response trailers and `103 Early Hints` to its experimental HTTP/2 implementation through `zttp`. ```console uv add uvicorn==0.54.0 "zttp>=0.0.34" ``` - **Send HTTP/2 response trailers** ([#&#8203;3146](https://github.com/Kludex/uvicorn/pull/3146)). The ASGI `http.response.trailers` extension lets applications send metadata, such as checksums, after the response body. Clients must send `TE: trailers` to receive them. Multiple trailer messages are combined before completing the response. - **HTTP/2 remains experimental and opt-in.** Enable it with `--http zttp --http2`. Upgrade-based h2c and WebSockets over HTTP/2 remain unsupported. #### 💡 Hint at resources before the final response - **Send `103 Early Hints` over HTTP/2** ([#&#8203;3137](https://github.com/Kludex/uvicorn/pull/3137)). Applications can use the ASGI `http.response.early_hint` extension to send resource hints before the final response. Each supplied link becomes a separate `Link` header. **Full changelog:** [0.53.0...0.54.0](https://github.com/Kludex/uvicorn/compare/0.53.0...0.54.0) ### [`v0.53.0`](https://github.com/Kludex/uvicorn/releases/tag/0.53.0): Version 0.53.0 [Compare Source](https://github.com/Kludex/uvicorn/compare/0.52.4...0.53.0) #### 🌐 Opt-in HTTP/2 support `uvicorn` 0.53.0 adds experimental HTTP/2 through `zttp`, alongside a new `zuvloop` integration and connection-handling improvements. ```console uv add uvicorn==0.53.0 ``` - **Serve HTTP/1.1 and HTTP/2 with `zttp`** ([#&#8203;2982](https://github.com/Kludex/uvicorn/pull/2982), [#&#8203;3101](https://github.com/Kludex/uvicorn/pull/3101)). Install `zttp`, then enable HTTP/2 with `--http zttp --http2`. Uvicorn negotiates HTTP/2 over TLS with ALPN and supports cleartext prior knowledge. - **HTTP/2 remains experimental.** Upgrade-based h2c and WebSockets over HTTP/2 are not supported. #### ⚙️ More event loop choice - **Run Uvicorn with `zuvloop`** ([#&#8203;3104](https://github.com/Kludex/uvicorn/pull/3104)). Install `zuvloop` separately and select it explicitly with `--loop zuvloop` on CPython 3.14 or newer. #### 🛡️ More reliable connections and proxies - **Honor `Connection: close` token lists** ([#&#8203;3103](https://github.com/Kludex/uvicorn/pull/3103)). Uvicorn now parses comma-separated tokens case-insensitively across HTTP implementations. - **Trust IPv6 loopback proxies by default** ([#&#8203;3119](https://github.com/Kludex/uvicorn/pull/3119)). The default `FORWARDED_ALLOW_IPS` value now includes `::1`. - **Keep upgraded WebSockets alive** ([#&#8203;3107](https://github.com/Kludex/uvicorn/pull/3107)). Uvicorn cancels the HTTP keep-alive timer when the connection becomes a WebSocket. **Full changelog:** [0.52.4...0.53.0](https://github.com/Kludex/uvicorn/compare/0.52.4...0.53.0) ### [`v0.52.4`](https://github.com/Kludex/uvicorn/releases/tag/0.52.4): Version 0.52.4 [Compare Source](https://github.com/Kludex/uvicorn/compare/0.52.3...0.52.4) ##### Fixed - Remove duplicate `Date` headers from accepted WebSocket handshakes with `websockets-sansio` ([#&#8203;3078](https://github.com/Kludex/uvicorn/pull/3078)) **Full Changelog**: <https://github.com/Kludex/uvicorn/compare/0.52.3...0.52.4> ### [`v0.52.3`](https://github.com/Kludex/uvicorn/releases/tag/0.52.3): Version 0.52.3 [Compare Source](https://github.com/Kludex/uvicorn/compare/0.52.2...0.52.3) ##### Changed - Update `zttp` to 0.0.24 and use its combined receive path, improving HTTP/1.1 request parsing performance ([#&#8203;3067](https://github.com/Kludex/uvicorn/issues/3067)) **Full Changelog**: <https://github.com/Kludex/uvicorn/compare/0.52.2...0.52.3> ### [`v0.52.2`](https://github.com/Kludex/uvicorn/releases/tag/0.52.2): Version 0.52.2 [Compare Source](https://github.com/Kludex/uvicorn/compare/0.52.1...0.52.2) ##### Fixed - Update `zttp` to 0.0.22, fixing bodyless request receives and improving HTTP/1 request parsing performance ([#&#8203;3063](https://github.com/Kludex/uvicorn/issues/3063)) **Full Changelog**: <https://github.com/Kludex/uvicorn/compare/0.52.1...0.52.2> ### [`v0.52.1`](https://github.com/Kludex/uvicorn/releases/tag/0.52.1): Version 0.52.1 [Compare Source](https://github.com/Kludex/uvicorn/compare/0.52.0...0.52.1) ##### Fixed - Complete the closing handshake on server-initiated WebSocket closes in the `websockets-sansio` and `wsproto` implementations, waiting for the client's close reply with a 10 second timeout instead of resetting the connection ([#&#8203;3053](https://github.com/Kludex/uvicorn/issues/3053)) - Add missing write flow control to the `websockets-sansio` implementation, preventing data truncation on server-initiated closes with large in-flight payloads ([#&#8203;3048](https://github.com/Kludex/uvicorn/issues/3048)) - Handle connection loss while a WebSocket write is waiting on backpressure ([#&#8203;3050](https://github.com/Kludex/uvicorn/issues/3050)) - Remove duplicate `Content-Type` and `Content-Length` headers from WebSocket denial responses on the `websockets-sansio` implementation, and deliver non-UTF-8 denial bodies intact ([#&#8203;3041](https://github.com/Kludex/uvicorn/issues/3041)) **Full Changelog**: <https://github.com/Kludex/uvicorn/compare/0.52.0...0.52.1> ### [`v0.52.0`](https://github.com/Kludex/uvicorn/releases/tag/0.52.0): Version 0.52.0 [Compare Source](https://github.com/Kludex/uvicorn/compare/0.51.0...0.52.0) This release adds an experimental HTTP/1.1 implementation backed by [zttp](https://zttp.marcelotryle.com/), a sans-IO HTTP parser I've been developing on the side: a core written in Zig, with bindings to Python. It has been running under a fuzzer for some weeks now, and has been through multiple rounds of security auditing. It is still **experimental**, so don't put it in front of production traffic yet. Try it with `--http zttp`, and please send any feedback to the [issue tracker](https://github.com/Kludex/uvicorn/issues). ##### Added - Add an experimental `zttp` HTTP/1.1 implementation, selectable with `--http zttp` ([#&#8203;2979](https://github.com/Kludex/uvicorn/issues/2979)) ##### Fixed - Keep non-ASCII WebSocket request headers intact with websockets 17.0, which encodes them with ISO-8859-1 ([#&#8203;3036](https://github.com/Kludex/uvicorn/issues/3036)) **Full Changelog**: <https://github.com/Kludex/uvicorn/compare/0.51.0...0.52.0> </details> --- ### Configuration 📅 **Schedule**: (in timezone America/New_York) - Branch creation - "before 6am on monday" - Automerge - At any time (no schedule defined) 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 👻 **Immortal**: This PR will be recreated if closed unmerged. Get [config help](https://github.com/renovatebot/renovate/discussions) if that's undesired. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box --- This PR has been generated by [Mend Renovate](https://github.com/renovatebot/renovate). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4yODAuMyIsInVwZGF0ZWRJblZlciI6IjQzLjI4OC4wIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->
chore(deps): update python minor/patch
All checks were successful
CI / test (pull_request) Successful in 6m8s
b0ec11f777
renovate-bot force-pushed renovate/python-minorpatch from b0ec11f777
All checks were successful
CI / test (pull_request) Successful in 6m8s
to 07435a2682
All checks were successful
CI / test (pull_request) Successful in 6m20s
2026-08-05 00:13:26 +00:00
Compare
renovate-bot force-pushed renovate/python-minorpatch from 07435a2682
All checks were successful
CI / test (pull_request) Successful in 6m20s
to 339b1c3c5d
All checks were successful
CI / test (pull_request) Successful in 4m6s
2026-08-07 12:10:01 +00:00
Compare
renovate-bot force-pushed renovate/python-minorpatch from 339b1c3c5d
All checks were successful
CI / test (pull_request) Successful in 4m6s
to 108a38839c
All checks were successful
CI / test (pull_request) Successful in 8m34s
2026-08-08 18:12:09 +00:00
Compare
renovate-bot force-pushed renovate/python-minorpatch from 108a38839c
All checks were successful
CI / test (pull_request) Successful in 8m34s
to 7d6f9b1646
All checks were successful
CI / test (pull_request) Successful in 4m48s
2026-08-11 12:09:55 +00:00
Compare
renovate-bot force-pushed renovate/python-minorpatch from 7d6f9b1646
All checks were successful
CI / test (pull_request) Successful in 4m48s
to 9b52093c8e
All checks were successful
CI / test (pull_request) Successful in 6m0s
2026-08-12 00:10:55 +00:00
Compare
renovate-bot force-pushed renovate/python-minorpatch from 9b52093c8e
All checks were successful
CI / test (pull_request) Successful in 6m0s
to 7e374cd903
All checks were successful
CI / test (pull_request) Successful in 5m13s
2026-08-13 12:10:31 +00:00
Compare
renovate-bot force-pushed renovate/python-minorpatch from 7e374cd903
All checks were successful
CI / test (pull_request) Successful in 5m13s
to 171edff1e9
All checks were successful
CI / test (pull_request) Successful in 4m33s
2026-08-13 18:10:47 +00:00
Compare
renovate-bot force-pushed renovate/python-minorpatch from 171edff1e9
All checks were successful
CI / test (pull_request) Successful in 4m33s
to dad1a0e75c
All checks were successful
CI / test (pull_request) Successful in 5m51s
2026-08-16 18:11:24 +00:00
Compare
renovate-bot force-pushed renovate/python-minorpatch from dad1a0e75c
All checks were successful
CI / test (pull_request) Successful in 5m51s
to c1f8f671d2
All checks were successful
CI / test (pull_request) Successful in 3m48s
2026-08-19 12:11:13 +00:00
Compare
renovate-bot force-pushed renovate/python-minorpatch from c1f8f671d2
All checks were successful
CI / test (pull_request) Successful in 3m48s
to 72cd7c8552
All checks were successful
CI / test (pull_request) Successful in 6m15s
2026-08-30 18:16:06 +00:00
Compare
renovate-bot force-pushed renovate/python-minorpatch from 72cd7c8552
All checks were successful
CI / test (pull_request) Successful in 6m15s
to c91fdd4714
All checks were successful
CI / test (pull_request) Successful in 4m32s
2026-09-04 18:14:13 +00:00
Compare
renovate-bot force-pushed renovate/python-minorpatch from c91fdd4714
All checks were successful
CI / test (pull_request) Successful in 4m32s
to 3c5ed19d67
All checks were successful
CI / test (pull_request) Successful in 6m40s
2026-09-10 06:21:36 +00:00
Compare
renovate-bot force-pushed renovate/python-minorpatch from 3c5ed19d67
All checks were successful
CI / test (pull_request) Successful in 6m40s
to 49d42fc4dd
All checks were successful
CI / test (pull_request) Successful in 3m55s
2026-09-12 00:14:44 +00:00
Compare
renovate-bot force-pushed renovate/python-minorpatch from 49d42fc4dd
All checks were successful
CI / test (pull_request) Successful in 3m55s
to 1c0f8f6ecd
All checks were successful
CI / test (pull_request) Successful in 5m10s
2026-09-14 12:17:33 +00:00
Compare
renovate-bot force-pushed renovate/python-minorpatch from 1c0f8f6ecd
All checks were successful
CI / test (pull_request) Successful in 5m10s
to 5319c5e701
All checks were successful
CI / test (pull_request) Successful in 6m29s
2026-09-15 00:15:00 +00:00
Compare
renovate-bot force-pushed renovate/python-minorpatch from 5319c5e701
All checks were successful
CI / test (pull_request) Successful in 6m29s
to f77cf6b705
All checks were successful
CI / test (pull_request) Successful in 10m34s
2026-09-16 00:13:25 +00:00
Compare
renovate-bot force-pushed renovate/python-minorpatch from f77cf6b705
All checks were successful
CI / test (pull_request) Successful in 10m34s
to fd6e4c71e3
All checks were successful
CI / test (pull_request) Successful in 6m53s
2026-09-25 00:15:00 +00:00
Compare
renovate-bot force-pushed renovate/python-minorpatch from fd6e4c71e3
All checks were successful
CI / test (pull_request) Successful in 6m53s
to be4e7d0694
All checks were successful
CI / test (pull_request) Successful in 4m34s
2026-09-25 12:13:22 +00:00
Compare
renovate-bot force-pushed renovate/python-minorpatch from be4e7d0694
All checks were successful
CI / test (pull_request) Successful in 4m34s
to 81f54903fd
All checks were successful
CI / test (pull_request) Successful in 4m27s
2026-09-25 18:21:27 +00:00
Compare
renovate-bot force-pushed renovate/python-minorpatch from 81f54903fd
All checks were successful
CI / test (pull_request) Successful in 4m27s
to 622b158b45
All checks were successful
CI / test (pull_request) Successful in 4m10s
2026-09-28 12:15:23 +00:00
Compare
renovate-bot force-pushed renovate/python-minorpatch from 622b158b45
All checks were successful
CI / test (pull_request) Successful in 4m10s
to 5a6b90a0a5
All checks were successful
CI / test (pull_request) Successful in 4m33s
2026-09-29 18:20:44 +00:00
Compare
renovate-bot force-pushed renovate/python-minorpatch from 5a6b90a0a5
All checks were successful
CI / test (pull_request) Successful in 4m33s
to 652ed7bac7
All checks were successful
CI / test (pull_request) Successful in 4m1s
2026-09-30 00:18:16 +00:00
Compare
renovate-bot force-pushed renovate/python-minorpatch from 652ed7bac7
All checks were successful
CI / test (pull_request) Successful in 4m1s
to c5e6af8bf0
All checks were successful
CI / test (pull_request) Successful in 10m9s
2026-09-30 12:44:53 +00:00
Compare
renovate-bot force-pushed renovate/python-minorpatch from c5e6af8bf0
All checks were successful
CI / test (pull_request) Successful in 10m9s
to bd15688a7d
All checks were successful
CI / test (pull_request) Successful in 4m23s
2026-10-01 06:20:37 +00:00
Compare
renovate-bot force-pushed renovate/python-minorpatch from bd15688a7d
All checks were successful
CI / test (pull_request) Successful in 4m23s
to 76a5ad54ca
All checks were successful
CI / test (pull_request) Successful in 6m40s
2026-10-02 06:16:10 +00:00
Compare
renovate-bot force-pushed renovate/python-minorpatch from 76a5ad54ca
All checks were successful
CI / test (pull_request) Successful in 6m40s
to c21b60668e
All checks were successful
CI / test (pull_request) Successful in 5m6s
2026-10-03 00:16:29 +00:00
Compare
renovate-bot force-pushed renovate/python-minorpatch from c21b60668e
All checks were successful
CI / test (pull_request) Successful in 5m6s
to b842bd4c9d
All checks were successful
CI / test (pull_request) Successful in 3m48s
2026-10-07 00:18:24 +00:00
Compare
renovate-bot force-pushed renovate/python-minorpatch from b842bd4c9d
All checks were successful
CI / test (pull_request) Successful in 3m48s
to de40e82f13
All checks were successful
CI / test (pull_request) Successful in 4m32s
2026-10-07 18:16:09 +00:00
Compare
renovate-bot force-pushed renovate/python-minorpatch from de40e82f13
All checks were successful
CI / test (pull_request) Successful in 4m32s
to 1ee697eb4b
All checks were successful
CI / test (pull_request) Successful in 4m3s
2026-10-08 00:16:48 +00:00
Compare
renovate-bot force-pushed renovate/python-minorpatch from 1ee697eb4b
All checks were successful
CI / test (pull_request) Successful in 4m3s
to d5faadae3c
All checks were successful
CI / test (pull_request) Successful in 3m55s
2026-10-08 18:25:43 +00:00
Compare
renovate-bot force-pushed renovate/python-minorpatch from d5faadae3c
All checks were successful
CI / test (pull_request) Successful in 3m55s
to 05a4ef76c7
All checks were successful
CI / test (pull_request) Successful in 6m20s
2026-10-10 00:16:52 +00:00
Compare
renovate-bot force-pushed renovate/python-minorpatch from 05a4ef76c7
All checks were successful
CI / test (pull_request) Successful in 6m20s
to 1f1813137a
All checks were successful
CI / test (pull_request) Successful in 5m47s
2026-10-12 18:29:20 +00:00
Compare
renovate-bot force-pushed renovate/python-minorpatch from 1f1813137a
All checks were successful
CI / test (pull_request) Successful in 5m47s
to 63b16edc46
All checks were successful
CI / test (pull_request) Successful in 6m30s
2026-10-13 18:19:46 +00:00
Compare
renovate-bot force-pushed renovate/python-minorpatch from 63b16edc46
All checks were successful
CI / test (pull_request) Successful in 6m30s
to db4bd75841
All checks were successful
CI / test (pull_request) Successful in 12m47s
2026-10-14 12:22:32 +00:00
Compare
renovate-bot force-pushed renovate/python-minorpatch from db4bd75841
All checks were successful
CI / test (pull_request) Successful in 12m47s
to 0f2023470b
All checks were successful
CI / test (pull_request) Successful in 17m47s
2026-10-14 18:29:05 +00:00
Compare
renovate-bot force-pushed renovate/python-minorpatch from 0f2023470b
All checks were successful
CI / test (pull_request) Successful in 17m47s
to dc2bbd045d
Some checks failed
CI / test (pull_request) Failing after 4m53s
2026-10-15 18:27:06 +00:00
Compare
renovate-bot force-pushed renovate/python-minorpatch from dc2bbd045d
Some checks failed
CI / test (pull_request) Failing after 4m53s
to b1bfa5a423
Some checks failed
CI / test (pull_request) Failing after 5m49s
2026-10-16 18:20:18 +00:00
Compare
renovate-bot force-pushed renovate/python-minorpatch from b1bfa5a423
Some checks failed
CI / test (pull_request) Failing after 5m49s
to b9eee989a8
Some checks failed
CI / test (pull_request) Failing after 3m30s
2026-10-17 00:18:45 +00:00
Compare
renovate-bot force-pushed renovate/python-minorpatch from b9eee989a8
Some checks failed
CI / test (pull_request) Failing after 3m30s
to 64f8b76675
Some checks failed
CI / test (pull_request) Failing after 3m38s
2026-10-18 12:18:14 +00:00
Compare
renovate-bot force-pushed renovate/python-minorpatch from 64f8b76675
Some checks failed
CI / test (pull_request) Failing after 3m38s
to d4f5912964
Some checks failed
CI / test (pull_request) Failing after 3m32s
2026-10-18 18:19:02 +00:00
Compare
renovate-bot force-pushed renovate/python-minorpatch from d4f5912964
Some checks failed
CI / test (pull_request) Failing after 3m32s
to f790b4f656
Some checks failed
CI / test (pull_request) Failing after 4m54s
2026-10-19 12:27:58 +00:00
Compare
renovate-bot force-pushed renovate/python-minorpatch from f790b4f656
Some checks failed
CI / test (pull_request) Failing after 4m54s
to e19a294cd3
Some checks failed
CI / test (pull_request) Failing after 9m34s
2026-10-19 18:26:37 +00:00
Compare
renovate-bot force-pushed renovate/python-minorpatch from e19a294cd3
Some checks failed
CI / test (pull_request) Failing after 9m34s
to f234a1f176
Some checks failed
CI / test (pull_request) Failing after 4m57s
2026-10-20 00:23:18 +00:00
Compare
renovate-bot force-pushed renovate/python-minorpatch from f234a1f176
Some checks failed
CI / test (pull_request) Failing after 4m57s
to 20b6382350
Some checks failed
CI / test (pull_request) Failing after 4m43s
2026-10-20 12:18:06 +00:00
Compare
renovate-bot force-pushed renovate/python-minorpatch from 20b6382350
Some checks failed
CI / test (pull_request) Failing after 4m43s
to addc600200
Some checks failed
CI / test (pull_request) Failing after 4m57s
2026-10-20 18:17:53 +00:00
Compare
renovate-bot force-pushed renovate/python-minorpatch from addc600200
Some checks failed
CI / test (pull_request) Failing after 4m57s
to c0f1502efa
Some checks failed
CI / test (pull_request) Failing after 3m51s
2026-10-21 00:19:19 +00:00
Compare
renovate-bot force-pushed renovate/python-minorpatch from c0f1502efa
Some checks failed
CI / test (pull_request) Failing after 3m51s
to c4dd38523e
Some checks failed
CI / test (pull_request) Failing after 3m36s
2026-10-21 12:22:57 +00:00
Compare
renovate-bot force-pushed renovate/python-minorpatch from c4dd38523e
Some checks failed
CI / test (pull_request) Failing after 3m36s
to 24014af6ee
Some checks failed
CI / test (pull_request) Failing after 5m26s
2026-10-21 18:32:55 +00:00
Compare
renovate-bot force-pushed renovate/python-minorpatch from 24014af6ee
Some checks failed
CI / test (pull_request) Failing after 5m26s
to 1ba77dfdfd
Some checks failed
CI / test (pull_request) Failing after 6m8s
2026-10-22 00:28:38 +00:00
Compare
renovate-bot force-pushed renovate/python-minorpatch from 1ba77dfdfd
Some checks failed
CI / test (pull_request) Failing after 6m8s
to 8dede9bbcd
Some checks failed
CI / test (pull_request) Failing after 4m14s
2026-10-22 06:30:15 +00:00
Compare
renovate-bot force-pushed renovate/python-minorpatch from 8dede9bbcd
Some checks failed
CI / test (pull_request) Failing after 4m14s
to 8b880efea3
Some checks failed
CI / test (pull_request) Failing after 4m37s
2026-10-22 18:30:18 +00:00
Compare
renovate-bot force-pushed renovate/python-minorpatch from 8b880efea3
Some checks failed
CI / test (pull_request) Failing after 4m37s
to e78dd405bd
Some checks failed
CI / test (pull_request) Failing after 3m56s
2026-10-23 00:26:27 +00:00
Compare
renovate-bot force-pushed renovate/python-minorpatch from e78dd405bd
Some checks failed
CI / test (pull_request) Failing after 3m56s
to 9a0187e0b6
Some checks failed
CI / test (pull_request) Failing after 4m2s
2026-10-24 00:23:46 +00:00
Compare
renovate-bot force-pushed renovate/python-minorpatch from 9a0187e0b6
Some checks failed
CI / test (pull_request) Failing after 4m2s
to 53e4f56ff6
Some checks failed
CI / test (pull_request) Failing after 5m20s
2026-10-24 18:17:05 +00:00
Compare
renovate-bot force-pushed renovate/python-minorpatch from 53e4f56ff6
Some checks failed
CI / test (pull_request) Failing after 5m20s
to a50909b0f5
Some checks failed
CI / test (pull_request) Failing after 10m23s
2026-10-27 06:28:13 +00:00
Compare
renovate-bot force-pushed renovate/python-minorpatch from a50909b0f5
Some checks failed
CI / test (pull_request) Failing after 10m23s
to c965bc202d
Some checks failed
CI / test (pull_request) Failing after 3m42s
2026-10-28 00:44:38 +00:00
Compare
renovate-bot force-pushed renovate/python-minorpatch from c965bc202d
Some checks failed
CI / test (pull_request) Failing after 3m42s
to 585b12d92c
Some checks failed
CI / test (pull_request) Failing after 7m35s
2026-10-28 12:25:27 +00:00
Compare
renovate-bot force-pushed renovate/python-minorpatch from 585b12d92c
Some checks failed
CI / test (pull_request) Failing after 7m35s
to 40a5139f11
Some checks failed
CI / test (pull_request) Failing after 3m52s
2026-10-31 18:33:31 +00:00
Compare
renovate-bot force-pushed renovate/python-minorpatch from 40a5139f11
Some checks failed
CI / test (pull_request) Failing after 3m52s
to 35495753a2
Some checks failed
CI / test (pull_request) Failing after 4m25s
2026-11-02 00:31:17 +00:00
Compare
renovate-bot force-pushed renovate/python-minorpatch from 35495753a2
Some checks failed
CI / test (pull_request) Failing after 4m25s
to 227ede06a7
Some checks failed
CI / test (pull_request) Failing after 4m36s
2026-11-03 12:22:31 +00:00
Compare
renovate-bot force-pushed renovate/python-minorpatch from 227ede06a7
Some checks failed
CI / test (pull_request) Failing after 4m36s
to 7ea7c421c3
Some checks failed
CI / test (pull_request) Failing after 4m41s
2026-11-04 00:30:07 +00:00
Compare
renovate-bot force-pushed renovate/python-minorpatch from 7ea7c421c3
Some checks failed
CI / test (pull_request) Failing after 4m41s
to d0baf70709
Some checks failed
CI / test (pull_request) Failing after 4m52s
2026-11-04 06:19:56 +00:00
Compare
renovate-bot force-pushed renovate/python-minorpatch from d0baf70709
Some checks failed
CI / test (pull_request) Failing after 4m52s
to 9d336a497a
Some checks failed
CI / test (pull_request) Failing after 3m41s
2026-11-04 12:19:58 +00:00
Compare
renovate-bot force-pushed renovate/python-minorpatch from 9d336a497a
Some checks failed
CI / test (pull_request) Failing after 3m41s
to d4250db51d
Some checks failed
CI / test (pull_request) Failing after 3m57s
2026-11-05 18:23:42 +00:00
Compare
renovate-bot force-pushed renovate/python-minorpatch from d4250db51d
Some checks failed
CI / test (pull_request) Failing after 3m57s
to fdbd09f321
Some checks failed
CI / test (pull_request) Failing after 4m15s
2026-11-06 00:41:34 +00:00
Compare
renovate-bot force-pushed renovate/python-minorpatch from fdbd09f321
Some checks failed
CI / test (pull_request) Failing after 4m15s
to a197379f91
Some checks failed
CI / test (pull_request) Failing after 3m51s
2026-11-06 12:22:58 +00:00
Compare
renovate-bot force-pushed renovate/python-minorpatch from a197379f91
Some checks failed
CI / test (pull_request) Failing after 3m51s
to 03a2a3f5a6
Some checks failed
CI / test (pull_request) Failing after 3m35s
2026-11-07 12:27:16 +00:00
Compare
renovate-bot force-pushed renovate/python-minorpatch from 03a2a3f5a6
Some checks failed
CI / test (pull_request) Failing after 3m35s
to 59fb28597d
Some checks failed
CI / test (pull_request) Failing after 4m32s
2026-11-07 18:19:33 +00:00
Compare
Some checks failed
CI / test (pull_request) Failing after 4m32s
Required
Details
Some required checks were not successful.
You are not authorized to merge this pull request.
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin renovate/python-minorpatch:renovate/python-minorpatch
git switch renovate/python-minorpatch
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
rbrooks/WeatherBot!178
No description provided.