Skip to content

chore(deps): bump the minor-and-patch-updates group across 1 directory with 19 updates - #575

Open
dependabot[bot] wants to merge 1 commit into
mainfrom
dependabot/uv/apps/backend/minor-and-patch-updates-cf22c37504
Open

chore(deps): bump the minor-and-patch-updates group across 1 directory with 19 updates#575
dependabot[bot] wants to merge 1 commit into
mainfrom
dependabot/uv/apps/backend/minor-and-patch-updates-cf22c37504

Conversation

@dependabot

@dependabot dependabot Bot commented on behalf of github Sep 1, 2026

Copy link
Copy Markdown
Contributor

Bumps the minor-and-patch-updates group with 19 updates in the /apps/backend directory:

Package From To
alembic 1.18.5 1.19.1
uvicorn 0.51.0 0.52.4
gunicorn 26.0.0 26.2.0
sqlalchemy 2.0.51 2.0.52
greenlet 3.5.3 3.5.5
pydantic-settings 2.14.2 2.15.0
protobuf 7.35.1 7.36.0
upstash-redis 1.7.0 1.8.0
timezonefinder 8.2.5 8.3.0
numpy 2.5.1 2.5.2
google-genai 2.12.1 2.20.0
pre-commit 4.6.0 4.6.2
ruff 0.15.22 0.16.5
mypy 2.3.0 2.3.1
python-json-logger 4.1.0 4.2.0
tiktoken 0.13.0 0.14.0
pandas 3.0.3 3.0.5
tqdm 4.69.0 4.70.0
kaggle 2.2.3 2.2.4

Updates alembic from 1.18.5 to 1.19.1

Release notes

Sourced from alembic's releases.

1.19.1

Released: August 8, 2026

bug

  • [bug] [autogenerate] Fixed bug in the check constraint detection implemented in #508 that failed to take into account column bound check constraints, leading to wrong autogenerate detections.

    References: #1842

1.19.0

Released: August 4, 2026

changed

  • [changed] [installation] Environmental updates:

    -   Trove classifiers now include Python 3.15 which is now part of CI
        integration
    
    • Python 3.14 is also added to trove classifiers which had been previously omitted

    • Implemented PEP 604 style unions in type annotations

feature

  • [feature] [autogenerate] Autogenerate now detects the addition and removal of named CHECK constraints, as part of the default autogenerate behavior. Detection is name-based only; a constraint whose name is unchanged is presumed equivalent regardless of its expression text, as reliably normalizing SQL expressions across backends for comparison purposes is not generally feasible. This behavior is implemented as a plugin named alembic.autogenerate.checkconstraint_byname, and may be disabled if not desired by excluding it from the EnvironmentContext.configure.autogenerate_plugins list. Pull request courtesy Francois van Kempen.

    References: #508

bug

... (truncated)

Commits

Updates uvicorn from 0.51.0 to 0.52.4

Release notes

Sourced from uvicorn's releases.

Version 0.52.4

Fixed

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

Full Changelog: Kludex/uvicorn@0.52.3...0.52.4

Version 0.52.3

Changed

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

Full Changelog: Kludex/uvicorn@0.52.2...0.52.3

Version 0.52.2

Fixed

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

Full Changelog: Kludex/uvicorn@0.52.1...0.52.2

Version 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 (#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: Kludex/uvicorn@0.52.0...0.52.1

Version 0.52.0

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: Kludex/uvicorn@0.51.0...0.52.0

Changelog

Sourced from uvicorn's changelog.

0.52.4 (August 18, 2026)

Fixed

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

0.52.3 (August 13, 2026)

Changed

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

0.52.2 (August 13, 2026)

Fixed

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

0.52.1 (August 1, 2026)

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)

0.52.0 (July 29, 2026)

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)
Commits

Updates gunicorn from 26.0.0 to 26.2.0

Release notes

Sourced from gunicorn's releases.

gunicorn 26.2.0

Cleartext HTTP/2 lands, and an HTTP/2 security fix.

Cleartext HTTP/2 (h2c)

http2_cleartext accepts prior-knowledge, upgrade, both or off (the default). Prior knowledge serves a connection that opens with the HTTP/2 preface; upgrade honours an HTTP/1.1 Upgrade: h2c request. Both work on the gthread, gevent and asgi workers.

This is for deployments where TLS is terminated by a proxy that speaks HTTP/2 upstream, so the hop into gunicorn no longer drops to HTTP/1.1. Only peers in forwarded_allow_ips are considered; everyone else is served HTTP/1.x exactly as if the setting were off. Each mechanism is enabled separately, so turning one on does not turn the other on.

Do not expose a cleartext HTTP/2 port to the internet.

Security

HTTP2Request built its headers straight from the stream, so nothing the HTTP/1 path enforces applied over HTTP/2: the underscore and header_map policy, duplicate Host and Content-Type, control characters in values, and the forwarded_allow_ips trust gate. An untrusted client could set SCRIPT_NAME and forge HTTP_* entries in the WSGI environ, and decide wsgi.url_scheme through :scheme. Both request classes now share one policy mixin, and the scheme comes from the transport.

If you serve HTTP/2, this is the reason to upgrade.

Other HTTP/2 fixes

WSGI responses were buffered whole before anything was sent; they stream now. HEAD, 204 and 304 no longer carry a body. Events read while blocked on a flow-control window were discarded, losing requests and body data outright. sendfile() is refused on HTTP/2 responses rather than bypassing framing.

Request bodies dropped on Upgrade requests

On the ASGI worker with the fast parser, any request carrying an Upgrade header reached the application with an empty body, whatever the header's value and with HTTP/2 switched off entirely. Fixed in gunicorn_h1c 0.6.9, which the fast extra now requires.

Full changelog: https://gunicorn.org/news/

gunicorn 26.1.0

New Features

  • Glob patterns in reload_extra_files: entries containing *, ? or [

... (truncated)

Commits
  • 36f2a3c gunicorn 26.2.0
  • cbba350 test: cover the h2c edge paths that had none
  • 9885411 Merge pull request #3703 from cormier/fix-inconsistency-in-control-socket-docs
  • 86f0919 Merge pull request #3704 from methane/doc-wsgi-h1c
  • 5853551 Merge pull request #3712 from Rotzbua/patch-1
  • 7bce87e Merge pull request #3700 from benoitc/fix/sponsor-logo-path
  • 972dfb0 Merge pull request #3690 from melbinjp/docs/contributing-settings-path
  • 7b3f16b Merge pull request #3711 from benoitc/docs/http2-changelog
  • 5bf237c http2: require gunicorn_h1c 0.6.9 and drop the upgrade body workaround
  • 7cf0338 test: skip the fast-parser cases when gunicorn_h1c is absent
  • Additional commits viewable in compare view

Updates sqlalchemy from 2.0.51 to 2.0.52

Release notes

Sourced from sqlalchemy's releases.

2.0.52

Released: August 11, 2026

platform

  • [platform] [bug] Python 3.15 support has been added and tested, including minimal changes for full compatibility.

    References: #13477

orm

  • [orm] [bug] Fixed a result-column misalignment bug in ORM-enabled UPDATE statements where synchronize_session="fetch" is in use, either explicitly or because the statement uses constructs such as CTEs that implicitly select for it. Columns in rows returned by .returning() could be returned under incorrect keys (e.g. row[SomeClass.a] returning the value of a different column), a problem most likely to manifest under concurrent workloads. ORM DELETE statements were not affected.

    References: #13439

  • [orm] [bug] Fixed bug where a failed _orm.Session.bulk_insert_mappings(), _orm.Session.bulk_update_mappings() or _orm.Session.bulk_save_objects() call could leave the _orm.Session permanently in a "flushing" state, such as when the transaction could not be begun because a previous flush had left it needing a rollback. Unlike _orm.Session.flush(), the bulk methods set the internal flushing flag and began the transaction outside of the try/finally block that resets it, so that neither _orm.Session.rollback() nor _orm.Session.close() would clear it, and every subsequent flush would raise InvalidRequestError: Session is already flushing. Pull request courtesy Hamody We.

    References: #13485

  • [orm] [bug] Fixed issue where unpickling an ORM object that were loaded using loader options making use of wildcard tokens, such as _orm.load_only() or _orm.raiseload() with "*", would fail with KeyError or IndexError if the process doing the unpickling had not yet constructed a loader path making use of that same token. This would typically be observed when the object were unpickled in a separate process, such as with the spawn or forkserver multiprocessing start methods, the latter of which became the default on POSIX platforms as of Python 3.14. The internal collection of these tokens is now established up front, so that it is identical in every process.

... (truncated)

Commits

Updates greenlet from 3.5.3 to 3.5.5

Changelog

Sourced from greenlet's changelog.

3.5.5 (2026-08-10)

  • Link the C++ runtime statically into the Windows wheels again, as the Appveyor builds did through 3.3.0. Since 3.3.1 _greenlet.pyd imported MSVCP140.dll, which no Windows CPython distribution ships, so importing greenlet failed on machines without the Visual C++ redistributable. See issue 525 <https://github.com/python-greenlet/greenlet/issues/525>_. Issue and pull request by Daniel Sticker.

.. note:: Binary 3.15 wheels are now built with 3.15.0rc1. This should be compatible with future 3.15 releases and is believed compatible with 3.15b4 as well (but not earlier versions).

3.5.4 (2026-07-22)

  • Fix a crash (segfault) on free-threaded builds of Python 3.14 and later when the garbage collector runs while a greenlet that was started from a non-empty C-stack-reference state is active. See issue 515 <https://github.com/python-greenlet/greenlet/issues/515>_. Thanks to ddorian and Kumar Aditya.

  • Fix a potential use-after-free on free-threaded builds of Python 3.14 and later when the garbage collector runs while a greenlet is suspended holding a _PyCStackRef (for example, mid attribute resolution). See issue 515 <https://github.com/python-greenlet/greenlet/issues/515>_. Thanks to ddorian and Kumar Aditya.

  • Fix a deadlock on free-threaded builds when a greenlet switch happened while a PyCriticalSection was held -- for example inside asyncio's Task.__step, which holds one on the running task for the duration of the step. See PR 519 <https://github.com/python-greenlet/greenlet/pull/519/>. Thanks to ddorian and Kumar Aditya.

.. note:: Binary 3.15 wheels are now built with Python 3.15b4. These may not be compatible with earlier or later versions of 3.15. Binary 3.15 wheels of greenlet from previous releases (e.g., 3.5.3) may not be compatible with Python 3.15b4.

Commits
  • ddb1453 Preparing release 3.5.5
  • 7de515c Update CHANGES: Credit for issue 525 and note about 3.15 binary wheels [skip ci]
  • f3746aa Merge pull request #526 from stickerdaniel/windows-static-runtime
  • f1ce3ca Restore static linking of the C++ runtime for Windows wheels
  • b6690a5 Merge pull request #523 from python-greenlet/dependabot/github_actions/github...
  • 726cc38 Bump the github-actions group with 3 updates
  • e5c5f4c Merge pull request #522 from ddorian/c-stack-refs-test-detection
  • be55a59 Check that the suspended greenlet is what keeps the class alive
  • e9c01dd Back to development: 3.5.5
  • 384be88 Preparing release 3.5.4
  • Additional commits viewable in compare view

Updates pydantic-settings from 2.14.2 to 2.15.0

Release notes

Sourced from pydantic-settings's releases.

v2.15.0

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).

What's Changed

... (truncated)

Commits
  • f725ca1 Prepare release 2.15.0 (#930)
  • 28f35c2 Bump the python-packages group with 4 updates (#929)
  • 9056db0 test: move function-local imports to the top of test modules (#927)
  • f077e3a fix: raise ValidationError for non-JSON env values on strict fields (#926)
  • ae25d70 fix: treat Secret subclasses as non-complex fields (#716) (#920)
  • 798dcea Bump the python-packages group with 4 updates (#924)
  • a190041 Bump the github-actions group with 4 updates (#925)
  • 5d93332 Bump the python-packages group with 4 updates (#921)
  • d2fdeda fix: read secret files as UTF-8 instead of the locale encoding (#917)
  • 2256a4e Bump the python-packages group with 3 updates (#915)
  • Additional commits viewable in compare view

Updates protobuf from 7.35.1 to 7.36.0

Commits

Updates upstash-redis from 1.7.0 to 1.8.0

Release notes

Sourced from upstash-redis's releases.

1.8.0

What's Changed

Full Changelog: upstash/redis-py@v1.6.0...1.8.0

Commits

Updates timezonefinder from 8.2.5 to 8.3.0

Changelog

Sourced from timezonefinder's changelog.

8.3.0 (2026-08-19)

  • 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

  • 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()

  • 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 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 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

  • 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

  • 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 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

  • 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

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

…y with 19 updates

Bumps the minor-and-patch-updates group with 19 updates in the /apps/backend directory:

| Package | From | To |
| --- | --- | --- |
| [alembic](https://github.com/sqlalchemy/alembic) | `1.18.5` | `1.19.1` |
| [uvicorn](https://github.com/Kludex/uvicorn) | `0.51.0` | `0.52.4` |
| [gunicorn](https://github.com/benoitc/gunicorn) | `26.0.0` | `26.2.0` |
| [sqlalchemy](https://github.com/sqlalchemy/sqlalchemy) | `2.0.51` | `2.0.52` |
| [greenlet](https://github.com/python-greenlet/greenlet) | `3.5.3` | `3.5.5` |
| [pydantic-settings](https://github.com/pydantic/pydantic-settings) | `2.14.2` | `2.15.0` |
| [protobuf](https://github.com/protocolbuffers/protobuf) | `7.35.1` | `7.36.0` |
| [upstash-redis](https://github.com/upstash/redis-python) | `1.7.0` | `1.8.0` |
| [timezonefinder](https://github.com/jannikmi/timezonefinder) | `8.2.5` | `8.3.0` |
| [numpy](https://github.com/numpy/numpy) | `2.5.1` | `2.5.2` |
| [google-genai](https://github.com/googleapis/python-genai) | `2.12.1` | `2.20.0` |
| [pre-commit](https://github.com/pre-commit/pre-commit) | `4.6.0` | `4.6.2` |
| [ruff](https://github.com/astral-sh/ruff) | `0.15.22` | `0.16.5` |
| [mypy](https://github.com/python/mypy) | `2.3.0` | `2.3.1` |
| [python-json-logger](https://github.com/nhairs/python-json-logger) | `4.1.0` | `4.2.0` |
| [tiktoken](https://github.com/openai/tiktoken) | `0.13.0` | `0.14.0` |
| [pandas](https://github.com/pandas-dev/pandas) | `3.0.3` | `3.0.5` |
| [tqdm](https://github.com/tqdm/tqdm) | `4.69.0` | `4.70.0` |
| [kaggle](https://github.com/Kaggle/kaggle-cli) | `2.2.3` | `2.2.4` |



Updates `alembic` from 1.18.5 to 1.19.1
- [Release notes](https://github.com/sqlalchemy/alembic/releases)
- [Changelog](https://github.com/sqlalchemy/alembic/blob/main/CHANGES)
- [Commits](https://github.com/sqlalchemy/alembic/commits)

Updates `uvicorn` from 0.51.0 to 0.52.4
- [Release notes](https://github.com/Kludex/uvicorn/releases)
- [Changelog](https://github.com/Kludex/uvicorn/blob/main/docs/release-notes.md)
- [Commits](Kludex/uvicorn@0.51.0...0.52.4)

Updates `gunicorn` from 26.0.0 to 26.2.0
- [Release notes](https://github.com/benoitc/gunicorn/releases)
- [Commits](benoitc/gunicorn@26.0.0...26.2.0)

Updates `sqlalchemy` from 2.0.51 to 2.0.52
- [Release notes](https://github.com/sqlalchemy/sqlalchemy/releases)
- [Changelog](https://github.com/sqlalchemy/sqlalchemy/blob/main/CHANGES.rst)
- [Commits](https://github.com/sqlalchemy/sqlalchemy/commits)

Updates `greenlet` from 3.5.3 to 3.5.5
- [Changelog](https://github.com/python-greenlet/greenlet/blob/master/CHANGES.rst)
- [Commits](python-greenlet/greenlet@3.5.3...3.5.5)

Updates `pydantic-settings` from 2.14.2 to 2.15.0
- [Release notes](https://github.com/pydantic/pydantic-settings/releases)
- [Commits](pydantic/pydantic-settings@v2.14.2...v2.15.0)

Updates `protobuf` from 7.35.1 to 7.36.0
- [Release notes](https://github.com/protocolbuffers/protobuf/releases)
- [Commits](https://github.com/protocolbuffers/protobuf/commits)

Updates `upstash-redis` from 1.7.0 to 1.8.0
- [Release notes](https://github.com/upstash/redis-python/releases)
- [Commits](https://github.com/upstash/redis-python/commits/1.8.0)

Updates `timezonefinder` from 8.2.5 to 8.3.0
- [Release notes](https://github.com/jannikmi/timezonefinder/releases)
- [Changelog](https://github.com/jannikmi/timezonefinder/blob/master/CHANGELOG.rst)
- [Commits](jannikmi/timezonefinder@8.2.5...8.3.0)

Updates `numpy` from 2.5.1 to 2.5.2
- [Release notes](https://github.com/numpy/numpy/releases)
- [Changelog](https://github.com/numpy/numpy/blob/main/doc/RELEASE_WALKTHROUGH.rst)
- [Commits](numpy/numpy@v2.5.1...v2.5.2)

Updates `google-genai` from 2.12.1 to 2.20.0
- [Release notes](https://github.com/googleapis/python-genai/releases)
- [Changelog](https://github.com/googleapis/python-genai/blob/main/CHANGELOG.md)
- [Commits](googleapis/python-genai@v2.12.1...v2.20.0)

Updates `pre-commit` from 4.6.0 to 4.6.2
- [Release notes](https://github.com/pre-commit/pre-commit/releases)
- [Changelog](https://github.com/pre-commit/pre-commit/blob/main/CHANGELOG.md)
- [Commits](pre-commit/pre-commit@v4.6.0...v4.6.2)

Updates `ruff` from 0.15.22 to 0.16.5
- [Release notes](https://github.com/astral-sh/ruff/releases)
- [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md)
- [Commits](astral-sh/ruff@0.15.22...0.16.5)

Updates `mypy` from 2.3.0 to 2.3.1
- [Changelog](https://github.com/python/mypy/blob/master/CHANGELOG.md)
- [Commits](python/mypy@v2.3.0...v2.3.1)

Updates `python-json-logger` from 4.1.0 to 4.2.0
- [Release notes](https://github.com/nhairs/python-json-logger/releases)
- [Changelog](https://github.com/nhairs/python-json-logger/blob/main/docs/changelog.md)
- [Commits](nhairs/python-json-logger@v4.1.0...v4.2.0)

Updates `tiktoken` from 0.13.0 to 0.14.0
- [Release notes](https://github.com/openai/tiktoken/releases)
- [Changelog](https://github.com/openai/tiktoken/blob/main/CHANGELOG.md)
- [Commits](openai/tiktoken@0.13.0...0.14.0)

Updates `pandas` from 3.0.3 to 3.0.5
- [Release notes](https://github.com/pandas-dev/pandas/releases)
- [Commits](pandas-dev/pandas@v3.0.3...v3.0.5)

Updates `tqdm` from 4.69.0 to 4.70.0
- [Release notes](https://github.com/tqdm/tqdm/releases)
- [Commits](tqdm/tqdm@v4.69.0...v4.70.0)

Updates `kaggle` from 2.2.3 to 2.2.4
- [Release notes](https://github.com/Kaggle/kaggle-cli/releases)
- [Changelog](https://github.com/Kaggle/kaggle-cli/blob/main/CHANGELOG.md)
- [Commits](Kaggle/kaggle-cli@v2.2.3...v2.2.4)

---
updated-dependencies:
- dependency-name: alembic
  dependency-version: 1.19.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: minor-and-patch-updates
- dependency-name: uvicorn
  dependency-version: 0.52.4
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: minor-and-patch-updates
- dependency-name: gunicorn
  dependency-version: 26.2.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: minor-and-patch-updates
- dependency-name: sqlalchemy
  dependency-version: 2.0.52
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: minor-and-patch-updates
- dependency-name: greenlet
  dependency-version: 3.5.5
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: minor-and-patch-updates
- dependency-name: pydantic-settings
  dependency-version: 2.15.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: minor-and-patch-updates
- dependency-name: protobuf
  dependency-version: 7.36.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: minor-and-patch-updates
- dependency-name: upstash-redis
  dependency-version: 1.8.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: minor-and-patch-updates
- dependency-name: timezonefinder
  dependency-version: 8.3.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: minor-and-patch-updates
- dependency-name: numpy
  dependency-version: 2.5.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: minor-and-patch-updates
- dependency-name: google-genai
  dependency-version: 2.20.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: minor-and-patch-updates
- dependency-name: pre-commit
  dependency-version: 4.6.2
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: minor-and-patch-updates
- dependency-name: ruff
  dependency-version: 0.16.5
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: minor-and-patch-updates
- dependency-name: mypy
  dependency-version: 2.3.1
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: minor-and-patch-updates
- dependency-name: python-json-logger
  dependency-version: 4.2.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: minor-and-patch-updates
- dependency-name: tiktoken
  dependency-version: 0.14.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: minor-and-patch-updates
- dependency-name: pandas
  dependency-version: 3.0.5
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: minor-and-patch-updates
- dependency-name: tqdm
  dependency-version: 4.70.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: minor-and-patch-updates
- dependency-name: kaggle
  dependency-version: 2.2.4
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: minor-and-patch-updates
...

Signed-off-by: dependabot[bot] <support@github.com>
@dependabot dependabot Bot added dependencies Pull requests that update a dependency file python:uv Pull requests that update python:uv code labels Sep 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Pull requests that update a dependency file python:uv Pull requests that update python:uv code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants