GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — feat: replace python-dateutil with stdlib datetime.fromisoformat by splch · Pull Request #1429 · openapi-generators/openapi-python-client

Conversation

@splch

@splch splch commented Apr 24, 2026

Copy link
Copy Markdown
Contributor

Summary

Drop the python-dateutil dependency from both the generator and all generated client packages. Date/datetime parsing now uses Python's built-in datetime.fromisoformat() instead of dateutil.parser.isoparse().

This removes one runtime dependency from every generated client, reducing install size and eliminating a dependency that is unmaintained upstream and being deprecated by Fedora 45 (no releases since March 2024).

Changes

Generator source (openapi_python_client/parser/properties/):

  • datetime.py: Validate defaults with datetime.datetime.fromisoformat() instead of isoparse(). Normalize Z to +00:00 at generation time so the emitted Python code is clean.
  • date.py: Validate defaults with datetime.date.fromisoformat() instead of isoparse().date().
  • Both: Remove "from dateutil.parser import isoparse" from the import set returned by get_imports().

Jinja templates (openapi_python_client/templates/property_templates/):

  • datetime_property.py.jinja: isoparse(x) -> datetime.datetime.fromisoformat(x.replace("Z", "+00:00"))
  • date_property.py.jinja: isoparse(x).date() -> datetime.date.fromisoformat(x)

Dependency removal (all 4 metadata formats):

  • pyproject_uv.toml.jinja, pyproject_poetry.toml.jinja, pyproject_pdm.toml.jinja, setup.py.jinja: Remove python-dateutil from generated dependencies.
  • pyproject.toml (generator): Remove python-dateutil from runtime deps and types-python-dateutil from dev deps.
  • integration-tests/pyproject.toml: Remove both as well.

Tests & golden records: All regenerated. Unit tests pass (283 passed, 4 skipped).

Python 3.10 compatibility

datetime.fromisoformat() gained full ISO 8601 support (including the Z suffix) in Python 3.11. On Python 3.10, the Z suffix raises a ValueError:

# Python 3.10
>>> datetime.datetime.fromisoformat("2024-01-15T10:30:00Z")
ValueError: Invalid isoformat string: '2024-01-15T10:30:00Z'

>>> datetime.datetime.fromisoformat("2024-01-15T10:30:00+00:00")
datetime.datetime(2024, 1, 15, 10, 30, tzinfo=datetime.timezone.utc)  # works
# Python 3.11+
>>> datetime.datetime.fromisoformat("2024-01-15T10:30:00Z")
datetime.datetime(2024, 1, 15, 10, 30, tzinfo=datetime.timezone.utc)  # works natively

The generated datetime parsing code uses .replace("Z", "+00:00") to normalize Z to an explicit UTC offset before calling fromisoformat(), which works on both 3.10 and 3.11+. This is a no-op on strings without Z. Date parsing does not need this since date strings have no timezone component.

Default values in OpenAPI specs are normalized at generation time (Z -> +00:00), so the emitted default expressions are clean datetime.datetime.fromisoformat("...") calls.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@splch
feat: replace python-dateutil with stdlib datetime.fromisoformat
6c43b97
Drop the python-dateutil dependency from both the generator and all
generated client code. Date/datetime parsing now uses the stdlib:

- datetime fields: datetime.datetime.fromisoformat(v.replace("Z", "+00:00"))
- date fields: datetime.date.fromisoformat(v)

The .replace("Z", "+00:00") call is needed because Python 3.10's
fromisoformat() does not accept the Z timezone suffix (added in 3.11).
It is a no-op on strings that do not contain Z.

Default values in OpenAPI specs are normalized at generation time
(Z replaced with +00:00), so the generated default expressions are
clean datetime.datetime.fromisoformat("...") calls without the
replace.

This removes one runtime dependency from every generated client
package, reducing install size and eliminating a dependency that is
in maintenance-only mode upstream.
dbanty
dbanty reviewed May 25, 2026
View reviewed changes
Comment thread openapi_python_client/parser/properties/datetime.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread openapi_python_client/templates/property_templates/datetime_property.py.jinja Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread pdm.minimal.lock Resolved

Uh oh!

There was an error while loading. Please reload this page.

splch added 3 commits May 27, 2026 14:17
@splch
docs: add TODO(py3.10) markers for fromisoformat workaround
01da6d2
Make the .replace("Z", "+00:00") workaround discoverable by both
`rg TODO` and `rg "3.10|py3.10"` so it can be cleanly removed
when the project drops Python 3.10 support.
@splch
Merge upstream/main into drop-python-dateutil
5875773
Brings in 8 commits since the PR opened, notably:
  - typer constraint bump to <0.27
  - uv_build 0.11 template update
  - mypy v2 cast cleanup in generated output

Conflict resolution:
  - pdm.lock, integration-tests/pdm.lock: regenerated via 'pdm lock'
    against the merged pyproject.toml.
  - Golden records: regenerated via 'pdm run regen' to absorb the
    mypy-cast cleanup; the dateutil -> fromisoformat change from this
    branch is preserved.

Verified locally with ruff check, ruff format --check, mypy, and the
unit-test suite (283 passed, 4 skipped).
@splch
chore(deps): regenerate minimal lockfiles with direct_minimal_versions
f3ea270
The minimal lockfiles were previously regenerated without
'-S direct_minimal_versions', so direct dependencies were locked
to highest-compatible versions instead of lowest. That defeats the
point of the test_min_deps CI job, which exists to verify the
declared lower bounds in pyproject.toml still work.

Re-locked both pdm.minimal.lock files using:
    pdm lock -S direct_minimal_versions -L pdm.minimal.lock

Strategy marker confirmed as
["direct_minimal_versions", "inherit_metadata"] in the metadata
of both files. python-dateutil is absent (this branch's main change).
dbanty
dbanty approved these changes May 30, 2026
View reviewed changes

@dbanty dbanty left a comment

Copy link
Copy Markdown
Collaborator

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@dbanty
dbanty added this pull request to the merge queue May 30, 2026
Merged via the queue into openapi-generators:main with commit 6df45e9 May 30, 2026
22 checks passed

Uh oh!

There was an error while loading. Please reload this page.

@knope-bot knope-bot Bot mentioned this pull request May 30, 2026
Release 0.29.0 #1439
Merged
@dbanty

dbanty commented May 30, 2026

Copy link
Copy Markdown
Collaborator

Turns out fractional seconds also aren't really supported in Python 3.10, caught by intermittent failures in the integration tests 😒. I think I'll just drop 3.10 support for this release, there's only a few months left of security support for it anyway.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

iloveitaly pushed a commit to iloveitaly/openapi-python-client that referenced this pull request May 31, 2026
@knope-bot
Release 0.29.0 (openapi-generators#1439)
7939364
> [!IMPORTANT]
> Merging this pull request will create this release

## Breaking Changes

- Drop support for Python 3.10
- Raise minimum httpx version to 0.23.1

## Features

- replace python-dateutil with stdlib datetime.fromisoformat (openapi-generators#1429)

## Fixes

- Remove some generated casts that aren't necessary with mypy v2 (openapi-generators#1436)
- Explicitly set boundary for multipart/form-data (openapi-generators#1005)

Co-authored-by: knope-bot[bot] <152252888+knope-bot[bot]@users.noreply.github.com>
@splch
splch deleted the drop-python-dateutil branch June 1, 2026 18:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

@dbanty dbanty dbanty approved these changes

Uh oh!

There was an error while loading. Please reload this page.

Assignees

No one assigned

Labels

None yet

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

Uh oh!

There was an error while loading. Please reload this page.

2 participants

@splch @dbanty
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.