Skip to content

Commit

Permalink
fix(typing): Revise annotation sorting
Browse files Browse the repository at this point in the history
The doc stated that `None` would appear after builtins, but any builtin with a length greater than 4 appeared after.

The issue is not new, but became more apparent to me while writing #3653 (comment)
  • Loading branch information
dangotbanned committed Oct 23, 2024
1 parent 2ba89d5 commit 93b5dab
Showing 1 changed file with 44 additions and 5 deletions.
49 changes: 44 additions & 5 deletions tools/schemapi/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,23 @@
"array": "list",
"null": "None",
}
_STDLIB_TYPE_NAMES = frozenset(
(
"int",
"float",
"str",
"None",
"bool",
"date",
"datetime",
"time",
"tuple",
"list",
"deque",
"dict",
"set",
)
)

_VALID_IDENT: Pattern[str] = re.compile(r"^[^\d\W]\w*\Z", re.ASCII)

Expand Down Expand Up @@ -859,9 +876,10 @@ def sort_type_reprs(tps: Iterable[str], /) -> list[str]:
We use `set`_ for unique elements, but the lack of ordering requires additional sorts:
- If types have same length names, order would still be non-deterministic
- Hence, we sort as well by type name as a tie-breaker, see `sort-stability`_.
- Using ``str.lower`` gives priority to `builtins`_ over ``None``.
- Lowest priority is given to generated aliases from ``TypeAliasTracer``.
- Using ``str.lower`` gives priority to `builtins`_.
- Lower priority is given to generated aliases from ``TypeAliasTracer``.
- These are purely to improve autocompletion
- ``None`` will always appear last.
Related
-------
Expand All @@ -875,9 +893,30 @@ def sort_type_reprs(tps: Iterable[str], /) -> list[str]:
https://docs.python.org/3/library/functions.html
"""
dedup = tps if isinstance(tps, set) else set(tps)
it = sorted(dedup, key=str.lower) # Tertiary sort
it = sorted(it, key=len) # Secondary sort
return sorted(it, key=TypeAliasTracer.is_cached) # Primary sort
it = sorted(dedup, key=str.lower) # Quinary sort
it = sorted(it, key=len) # Quaternary sort
it = sorted(it, key=TypeAliasTracer.is_cached) # Tertiary sort
it = sorted(it, key=is_not_stdlib) # Secondary sort
it = sorted(it, key=is_none) # Primary sort
return it


def is_not_stdlib(s: str, /) -> bool:
"""
Sort key.
Places a subset of stdlib types at the **start** of list.
"""
return s not in _STDLIB_TYPE_NAMES


def is_none(s: str, /) -> bool:
"""
Sort key.
Always places ``None`` at the **end** of list.
"""
return s == "None"


def spell_nested_sequence(
Expand Down

0 comments on commit 93b5dab

Please sign in to comment.