Skip to content

Support for Python3.9 type hint syntax#2795

Merged
schani merged 9 commits into
glideapps:masterfrom
matthew-c-lee:python3.9
Jul 20, 2026
Merged

Support for Python3.9 type hint syntax#2795
schani merged 9 commits into
glideapps:masterfrom
matthew-c-lee:python3.9

Conversation

@matthew-c-lee

Copy link
Copy Markdown
Contributor

Description

In python 3.9 and onwards, some generics are type hinted differently (Dict, List should be lowercase dict, list instead) as well as some syntax changes (Optional[Type] syntax replaced with Type | None syntax, along with Union[Type1, Type2] replaced with Type1 | Type2)

I added a new option to pythonOptions.features, a boolean "builtinGenerics". In python 3.9 it's enabled, and disabled for the previous versions. I use pretty simple logic to do it, just a couple of if statements and ternary operators to account for the new syntax.

Some ways quotes are handled around types was changed to support wrapping around unions. (see _suppressQuotes in PythonRenderer's namedType method)

Motivation and Context

To keep up with newer Python syntax.

How Has This Been Tested?

Tested with python 3.7 and python 3.9 using the scripted tests that use mypy (confirms that the syntax is valid, and that with python 3.7, it's not trying to use any of the new syntax) along with looking at the outputs manually and confirming that 3.9 uses the newer syntax.

@matthew-c-lee matthew-c-lee changed the title Python3.9 Support for Python3.9 type hint syntax Jun 26, 2025
schani and others added 4 commits July 9, 2026 15:56
- Rename the new python-version level to 3.10: PEP 604 unions (X | None)
  require Python 3.10, not 3.9.  Split the feature flag into
  builtinGenerics (PEP 585, 3.9+) and unionOperators (PEP 604, 3.10+),
  which also yields a 3.9 level with builtin generics but typing
  Optional/Union.  Make 3.10 the default python-version.
- Emit " = None" defaults outside the quoted annotation: the annotation
  'Foo | None = None' is invalid syntax.
- Only quote PEP 604 unions when a member actually needs a forward
  reference, and never quote inside an already-quoted annotation.
- Restore withTyping("Dict") registration in the dict converter so the
  typing import is emitted for pre-3.9 versions, and revert typeObject's
  map branch to the runtime type "dict".
- Cover the legacy typing.* code paths in QUICKTEST via
  quickTestRendererOptions for 3.5/3.6/3.7/3.9.
- Run python fixtures under Python 3.12 in CI and the fixture driver.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
With dataclasses (3.7+), optional properties become nullable unions and
get a " = None" default — except when the property type is Any (null is
absorbed into it) or plain null (the union collapses), which got no
default yet could sort after defaulted fields, making the generated
dataclass raise "TypeError: non-default argument follows default
argument" at import.  This was latent on master because CI only ever
exercised 3.5/3.6, which don't use dataclasses; with 3.10 as the new
default it breaks e.g. vega-lite.schema and the combinations samples.

Emit " = None" for root-level Any/None fields too, and make the
property sort order compute exactly "will this field render with a
default" via followTargetType — the old kind-based predicate saw
pre-transformation types (transformed unions have kind "any" at sort
time) and could order a non-defaulted field after defaulted ones.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@schani
schani merged commit a80b105 into glideapps:master Jul 20, 2026
25 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants