diff --git a/python/src/typechat/_internal/ts_conversion/python_type_to_ts_nodes.py b/python/src/typechat/_internal/ts_conversion/python_type_to_ts_nodes.py index e663be58..bf12b4b4 100644 --- a/python/src/typechat/_internal/ts_conversion/python_type_to_ts_nodes.py +++ b/python/src/typechat/_internal/ts_conversion/python_type_to_ts_nodes.py @@ -1,5 +1,6 @@ from __future__ import annotations +import collections.abc from collections import OrderedDict import inspect import sys @@ -21,6 +22,7 @@ NotRequired, Protocol, Required, + Self, TypeAlias, TypeAliasType, TypeGuard, @@ -131,25 +133,24 @@ class TypeScriptNodeTranslationResult: errors: list[str] -# TODO: https://github.com/microsoft/pyright/issues/6587 -_SELF_TYPE = getattr(typing_extensions, "Self") - _LIST_TYPES: set[object] = { list, set, frozenset, - # TODO: https://github.com/microsoft/pyright/issues/6582 - # collections.abc.MutableSequence, - # collections.abc.Sequence, - # collections.abc.Set + collections.abc.Sequence, + collections.abc.MutableSequence, + collections.abc.Set, + collections.abc.MutableSet, + collections.abc.Iterable, + collections.abc.Collection, } -# TODO: https://github.com/microsoft/pyright/issues/6582 -# _DICT_TYPES: set[type] = { -# dict, -# collections.abc.MutableMapping, -# collections.abc.Mapping -# } + +_DICT_TYPES: set[type] = { + dict, + collections.abc.MutableMapping, + collections.abc.Mapping, +} def python_type_to_typescript_nodes(root_py_type: object) -> TypeScriptNodeTranslationResult: @@ -222,7 +223,7 @@ def convert_to_type_node(py_type: object) -> TypeNode: return NullTypeReferenceNode if py_type is Never or py_type is NoReturn: return NeverTypeReferenceNode - if py_type is _SELF_TYPE: + if py_type is Self: return ThisTypeReferenceNode # TODO: consider handling bare 'tuple' (and list, etc.) @@ -237,7 +238,7 @@ def convert_to_type_node(py_type: object) -> TypeNode: return TypeReferenceNode(IdentifierNode("Array"), [type_arg]) return ArrayTypeNode(type_arg) - if origin is dict: + if origin in _DICT_TYPES: # TODO # Currently, we naively assume all dicts are string-keyed # unless they're annotated with `int` or `float` (note: not `int | float`). diff --git a/python/tests/__snapshots__/test_abstract_collections/test_abstract_collections.schema.d.ts b/python/tests/__snapshots__/test_abstract_collections/test_abstract_collections.schema.d.ts new file mode 100644 index 00000000..c4717175 --- /dev/null +++ b/python/tests/__snapshots__/test_abstract_collections/test_abstract_collections.schema.d.ts @@ -0,0 +1,15 @@ +// Entry point is: 'MyType' + +interface MyType { + built_in_dict: Record; + built_in_set: string[]; + built_in_frozen_set: string[]; + mapping: Record; + mutable_mapping: Record; + set: string[]; + mutable_set: string[]; + sequence: string[]; + mutable_sequence: string[]; + iterable: string[]; + collection: string[]; +} diff --git a/python/tests/test_abstract_collections.py b/python/tests/test_abstract_collections.py new file mode 100644 index 00000000..21322813 --- /dev/null +++ b/python/tests/test_abstract_collections.py @@ -0,0 +1,27 @@ +import collections.abc +from typing import Any, TypedDict + +from typechat import python_type_to_typescript_schema +from .utilities import TypeScriptSchemaSnapshotExtension + + +class MyType(TypedDict): + built_in_dict: dict[str, str] + built_in_set: set[str] + built_in_frozen_set: frozenset[str] + + mapping: collections.abc.Mapping[str, str] + mutable_mapping: collections.abc.MutableMapping[str, str] + + set: collections.abc.Set[str] + mutable_set: collections.abc.MutableSet[str] + + sequence: collections.abc.Sequence[str] + mutable_sequence: collections.abc.MutableSequence[str] + + iterable: collections.abc.Iterable[str] + collection: collections.abc.Collection[str] + + +def test_abstract_collections(snapshot: Any): + assert python_type_to_typescript_schema(MyType) == snapshot(extension_class=TypeScriptSchemaSnapshotExtension)