From 8c09d666488e6c0eb961e2aa20b096763411ba2b Mon Sep 17 00:00:00 2001 From: Andrew Hilger Date: Fri, 13 Dec 2024 21:14:33 -0800 Subject: [PATCH] implement flat-name container support Summary: Implement support for flat-name containers in py3 auto-migrate. Previously, `import List__i32 from foo.types` would hard crash. Now it returns a class based loosely on `python.types.ListTypeFactory(typeinfo_i32)`. The class extends `python.types.List` and supplies the necessary `typeinfo` to properly construct `List`. It forwards the values, whether passed as `args` or `kwargs`. The class uses a `metaclass` that implements `__instancecheck__` so that customer `isinstance(x, List__i32)` will work properly even in auto-migrate. Reviewed By: prakashgayasen, Filip-F Differential Revision: D66985311 fbshipit-source-id: f4aa70084676f0617daa17768069f2df85080718 --- .../generate/t_mstch_py3_generator.cc | 9 + .../generate/templates/py3/types.py.mustache | 47 ++ .../py3/types/container_base.mustache | 24 + .../templates/py3/types/typeinfo.mustache | 42 ++ .../py3_auto_migrate/gen-py3/module/types.py | 633 ++++++++++++++++++ thrift/lib/py3/test/auto_migrate/lists.py | 32 +- thrift/lib/py3/test/auto_migrate/maps.py | 33 +- .../lib/py3/test/auto_migrate/reflection.py | 12 +- thrift/lib/py3/test/auto_migrate/sets.py | 43 +- thrift/lib/python/types.pyx | 11 + 10 files changed, 865 insertions(+), 21 deletions(-) create mode 100644 thrift/compiler/generate/templates/py3/types/container_base.mustache create mode 100644 thrift/compiler/generate/templates/py3/types/typeinfo.mustache diff --git a/thrift/compiler/generate/t_mstch_py3_generator.cc b/thrift/compiler/generate/t_mstch_py3_generator.cc index fa3b8e7847e..7f4b6b14d48 100644 --- a/thrift/compiler/generate/t_mstch_py3_generator.cc +++ b/thrift/compiler/generate/t_mstch_py3_generator.cc @@ -601,6 +601,8 @@ class py3_mstch_type : public mstch_type { this, { {"type:modulePath", &py3_mstch_type::modulePath}, + {"type:module_auto_migrate_path", + &py3_mstch_type::moduleAutoMigratePath}, {"type:cbinding_path", &py3_mstch_type::cbinding_path}, {"type:flat_name", &py3_mstch_type::flatName}, {"type:cppNamespaces", &py3_mstch_type::cppNamespaces}, @@ -651,6 +653,13 @@ class py3_mstch_type : public mstch_type { get_type_py3_namespace(get_type_program(), "cbindings"), "_")); } + mstch::node moduleAutoMigratePath() { + return fmt::format( + "_{}", + fmt::join( + get_type_py3_namespace(get_type_program(), "thrift_types"), "_")); + } + mstch::node flatName() { return cached_props_.flat_name(); } mstch::node cppNamespaces() { diff --git a/thrift/compiler/generate/templates/py3/types.py.mustache b/thrift/compiler/generate/templates/py3/types.py.mustache index ae7dffcfe59..4247c6c1be0 100644 --- a/thrift/compiler/generate/templates/py3/types.py.mustache +++ b/thrift/compiler/generate/templates/py3/types.py.mustache @@ -35,4 +35,51 @@ want to include. {{#program:auto_migrate?}} {{> common/auto_generated_py}} from {{#program:py3Namespaces}}{{value}}.{{/program:py3Namespaces}}{{program:name}}.thrift_types import * +{{#program:hasContainerTypes}} +import thrift.python.types as _fbthrift_python_types +import {{#program:py3Namespaces}}{{value}}.{{/program:py3Namespaces}}{{program:name}}.thrift_types as {{! +}}_{{#program:py3Namespaces}}{{value}}_{{/program:py3Namespaces}}{{program:name}}_thrift_types +{{#program:includeNamespaces}} +{{#hasTypes?}} +import {{#includeNamespace}}{{value}}.{{/includeNamespace}}thrift_types as _{{#includeNamespace}}{{value}}_{{/includeNamespace}}thrift_types +{{/hasTypes?}} +{{/program:includeNamespaces}} +{{/program:hasContainerTypes}}{{! + +py3-container "flat name" name aliases for backwards-compatibility + +}} +{{#program:containerTypes}} +{{#type:container?}} +class {{type:flat_name}}__Meta(type): + def _fbthrift_type_info(cls): + return ( + {{#type:list?}} + {{#type:list_elem_type}}{{> types/typeinfo }}{{/type:list_elem_type}}, + {{/type:list?}} + {{#type:set?}} + {{#type:set_elem_type}}{{> types/typeinfo }}{{/type:set_elem_type}}, + {{/type:set?}} + {{#type:map?}} + {{#type:key_type}}{{> types/typeinfo }}{{/type:key_type}}, + {{#type:value_type}}{{> types/typeinfo }}{{/type:value_type}}, + {{/type:map?}} + ) + + def __instancecheck__(cls, instance): + return ( + isinstance(instance, _fbthrift_python_types.{{> types/container_base}}) and + instance._fbthrift_same_type(*cls._fbthrift_type_info()) + ) + +class {{type:flat_name}}(_fbthrift_python_types.{{> types/container_base}}, metaclass={{type:flat_name}}__Meta): + def __init__(self, *args, **kwargs): + super().__init__( + *{{type:flat_name}}._fbthrift_type_info(), + *args, + **kwargs, + ) + +{{/type:container?}} +{{/program:containerTypes}} {{/program:auto_migrate?}} diff --git a/thrift/compiler/generate/templates/py3/types/container_base.mustache b/thrift/compiler/generate/templates/py3/types/container_base.mustache new file mode 100644 index 00000000000..e749aaef27d --- /dev/null +++ b/thrift/compiler/generate/templates/py3/types/container_base.mustache @@ -0,0 +1,24 @@ +{{! + + Copyright (c) Meta Platforms, Inc. and affiliates. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +}}{{! + +This is used only in py3 auto-migrate for the base class +of flat-name containers (List__i32) + +}}{{#type:list?}}List{{/type:list?}}{{! +}}{{#type:set?}}Set{{/type:set?}}{{! +}}{{#type:map?}}Map{{/type:map?}} diff --git a/thrift/compiler/generate/templates/py3/types/typeinfo.mustache b/thrift/compiler/generate/templates/py3/types/typeinfo.mustache new file mode 100644 index 00000000000..1587b2dab4b --- /dev/null +++ b/thrift/compiler/generate/templates/py3/types/typeinfo.mustache @@ -0,0 +1,42 @@ +{{! + + Copyright (c) Meta Platforms, Inc. and affiliates. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +}}{{! + +This is used only in py3 auto-migrate to generate +aliases for container flat names, i.e., List__i32 + +}}{{#type:bool?}}_fbthrift_python_types.typeinfo_bool{{/type:bool?}}{{! +}}{{#type:byte?}}_fbthrift_python_types.typeinfo_byte{{/type:byte?}}{{! +}}{{#type:i16?}}_fbthrift_python_types.typeinfo_i16{{/type:i16?}}{{! +}}{{#type:i32?}}_fbthrift_python_types.typeinfo_i32{{/type:i32?}}{{! +}}{{#type:i64?}}_fbthrift_python_types.typeinfo_i64{{/type:i64?}}{{! +}}{{#type:double?}}_fbthrift_python_types.typeinfo_double{{/type:double?}}{{! +}}{{#type:float?}}_fbthrift_python_types.typeinfo_float{{/type:float?}}{{! +}}{{#type:string?}}_fbthrift_python_types.typeinfo_string{{/type:string?}}{{! +}}{{#type:binary?}}{{#type:iobuf?}}_fbthrift_python_types.typeinfo_iobuf{{/type:iobuf?}}{{^type:iobuf?}}_fbthrift_python_types.typeinfo_binary{{/type:iobuf?}}{{/type:binary?}}{{! +}}{{#type:struct}}_fbthrift_python_types.StructTypeInfo({{! + }}{{type:module_auto_migrate_path}}.{{struct:name}}){{! +}}{{/type:struct}}{{! +}}{{#type:list?}}_fbthrift_python_types.ListTypeInfo({{#type:list_elem_type}}{{> types/typeinfo }}{{/type:list_elem_type}}){{/type:list?}}{{! +}}{{#type:set?}}_fbthrift_python_types.SetTypeInfo({{#type:set_elem_type}}{{> types/typeinfo }}{{/type:set_elem_type}}){{/type:set?}}{{! +}}{{#type:map?}}_fbthrift_python_types.MapTypeInfo({{! + }}{{#type:key_type}}{{> types/typeinfo }}{{/type:key_type}}, {{! + }}{{#type:value_type}}{{> types/typeinfo }}{{/type:value_type}}{{! +}}){{/type:map?}}{{! +}}{{#type:enum}}_fbthrift_python_types.EnumTypeInfo({{! + }}{{type:module_auto_migrate_path}}.{{enum:name}}){{! +}}{{/type:enum}} diff --git a/thrift/compiler/test/fixtures/py3/out/py3_auto_migrate/gen-py3/module/types.py b/thrift/compiler/test/fixtures/py3/out/py3_auto_migrate/gen-py3/module/types.py index ee5d3592393..a51e0c52710 100644 --- a/thrift/compiler/test/fixtures/py3/out/py3_auto_migrate/gen-py3/module/types.py +++ b/thrift/compiler/test/fixtures/py3/out/py3_auto_migrate/gen-py3/module/types.py @@ -5,3 +5,636 @@ # @generated # from module.thrift_types import * +import thrift.python.types as _fbthrift_python_types +import module.thrift_types as _module_thrift_types +class List__i16__Meta(type): + def _fbthrift_type_info(cls): + return ( + _fbthrift_python_types.typeinfo_i16, + ) + + def __instancecheck__(cls, instance): + return ( + isinstance(instance, _fbthrift_python_types.List) and + instance._fbthrift_same_type(*cls._fbthrift_type_info()) + ) + +class List__i16(_fbthrift_python_types.List, metaclass=List__i16__Meta): + def __init__(self, *args, **kwargs): + super().__init__( + *List__i16._fbthrift_type_info(), + *args, + **kwargs, + ) + +class List__i32__Meta(type): + def _fbthrift_type_info(cls): + return ( + _fbthrift_python_types.typeinfo_i32, + ) + + def __instancecheck__(cls, instance): + return ( + isinstance(instance, _fbthrift_python_types.List) and + instance._fbthrift_same_type(*cls._fbthrift_type_info()) + ) + +class List__i32(_fbthrift_python_types.List, metaclass=List__i32__Meta): + def __init__(self, *args, **kwargs): + super().__init__( + *List__i32._fbthrift_type_info(), + *args, + **kwargs, + ) + +class List__i64__Meta(type): + def _fbthrift_type_info(cls): + return ( + _fbthrift_python_types.typeinfo_i64, + ) + + def __instancecheck__(cls, instance): + return ( + isinstance(instance, _fbthrift_python_types.List) and + instance._fbthrift_same_type(*cls._fbthrift_type_info()) + ) + +class List__i64(_fbthrift_python_types.List, metaclass=List__i64__Meta): + def __init__(self, *args, **kwargs): + super().__init__( + *List__i64._fbthrift_type_info(), + *args, + **kwargs, + ) + +class List__string__Meta(type): + def _fbthrift_type_info(cls): + return ( + _fbthrift_python_types.typeinfo_string, + ) + + def __instancecheck__(cls, instance): + return ( + isinstance(instance, _fbthrift_python_types.List) and + instance._fbthrift_same_type(*cls._fbthrift_type_info()) + ) + +class List__string(_fbthrift_python_types.List, metaclass=List__string__Meta): + def __init__(self, *args, **kwargs): + super().__init__( + *List__string._fbthrift_type_info(), + *args, + **kwargs, + ) + +class List__SimpleStruct__Meta(type): + def _fbthrift_type_info(cls): + return ( + _fbthrift_python_types.StructTypeInfo(_module_thrift_types.SimpleStruct), + ) + + def __instancecheck__(cls, instance): + return ( + isinstance(instance, _fbthrift_python_types.List) and + instance._fbthrift_same_type(*cls._fbthrift_type_info()) + ) + +class List__SimpleStruct(_fbthrift_python_types.List, metaclass=List__SimpleStruct__Meta): + def __init__(self, *args, **kwargs): + super().__init__( + *List__SimpleStruct._fbthrift_type_info(), + *args, + **kwargs, + ) + +class Set__i32__Meta(type): + def _fbthrift_type_info(cls): + return ( + _fbthrift_python_types.typeinfo_i32, + ) + + def __instancecheck__(cls, instance): + return ( + isinstance(instance, _fbthrift_python_types.Set) and + instance._fbthrift_same_type(*cls._fbthrift_type_info()) + ) + +class Set__i32(_fbthrift_python_types.Set, metaclass=Set__i32__Meta): + def __init__(self, *args, **kwargs): + super().__init__( + *Set__i32._fbthrift_type_info(), + *args, + **kwargs, + ) + +class Set__string__Meta(type): + def _fbthrift_type_info(cls): + return ( + _fbthrift_python_types.typeinfo_string, + ) + + def __instancecheck__(cls, instance): + return ( + isinstance(instance, _fbthrift_python_types.Set) and + instance._fbthrift_same_type(*cls._fbthrift_type_info()) + ) + +class Set__string(_fbthrift_python_types.Set, metaclass=Set__string__Meta): + def __init__(self, *args, **kwargs): + super().__init__( + *Set__string._fbthrift_type_info(), + *args, + **kwargs, + ) + +class Map__string_string__Meta(type): + def _fbthrift_type_info(cls): + return ( + _fbthrift_python_types.typeinfo_string, + _fbthrift_python_types.typeinfo_string, + ) + + def __instancecheck__(cls, instance): + return ( + isinstance(instance, _fbthrift_python_types.Map) and + instance._fbthrift_same_type(*cls._fbthrift_type_info()) + ) + +class Map__string_string(_fbthrift_python_types.Map, metaclass=Map__string_string__Meta): + def __init__(self, *args, **kwargs): + super().__init__( + *Map__string_string._fbthrift_type_info(), + *args, + **kwargs, + ) + +class Map__string_SimpleStruct__Meta(type): + def _fbthrift_type_info(cls): + return ( + _fbthrift_python_types.typeinfo_string, + _fbthrift_python_types.StructTypeInfo(_module_thrift_types.SimpleStruct), + ) + + def __instancecheck__(cls, instance): + return ( + isinstance(instance, _fbthrift_python_types.Map) and + instance._fbthrift_same_type(*cls._fbthrift_type_info()) + ) + +class Map__string_SimpleStruct(_fbthrift_python_types.Map, metaclass=Map__string_SimpleStruct__Meta): + def __init__(self, *args, **kwargs): + super().__init__( + *Map__string_SimpleStruct._fbthrift_type_info(), + *args, + **kwargs, + ) + +class Map__string_i16__Meta(type): + def _fbthrift_type_info(cls): + return ( + _fbthrift_python_types.typeinfo_string, + _fbthrift_python_types.typeinfo_i16, + ) + + def __instancecheck__(cls, instance): + return ( + isinstance(instance, _fbthrift_python_types.Map) and + instance._fbthrift_same_type(*cls._fbthrift_type_info()) + ) + +class Map__string_i16(_fbthrift_python_types.Map, metaclass=Map__string_i16__Meta): + def __init__(self, *args, **kwargs): + super().__init__( + *Map__string_i16._fbthrift_type_info(), + *args, + **kwargs, + ) + +class List__List__i32__Meta(type): + def _fbthrift_type_info(cls): + return ( + _fbthrift_python_types.ListTypeInfo(_fbthrift_python_types.typeinfo_i32), + ) + + def __instancecheck__(cls, instance): + return ( + isinstance(instance, _fbthrift_python_types.List) and + instance._fbthrift_same_type(*cls._fbthrift_type_info()) + ) + +class List__List__i32(_fbthrift_python_types.List, metaclass=List__List__i32__Meta): + def __init__(self, *args, **kwargs): + super().__init__( + *List__List__i32._fbthrift_type_info(), + *args, + **kwargs, + ) + +class Map__string_i32__Meta(type): + def _fbthrift_type_info(cls): + return ( + _fbthrift_python_types.typeinfo_string, + _fbthrift_python_types.typeinfo_i32, + ) + + def __instancecheck__(cls, instance): + return ( + isinstance(instance, _fbthrift_python_types.Map) and + instance._fbthrift_same_type(*cls._fbthrift_type_info()) + ) + +class Map__string_i32(_fbthrift_python_types.Map, metaclass=Map__string_i32__Meta): + def __init__(self, *args, **kwargs): + super().__init__( + *Map__string_i32._fbthrift_type_info(), + *args, + **kwargs, + ) + +class Map__string_Map__string_i32__Meta(type): + def _fbthrift_type_info(cls): + return ( + _fbthrift_python_types.typeinfo_string, + _fbthrift_python_types.MapTypeInfo(_fbthrift_python_types.typeinfo_string, _fbthrift_python_types.typeinfo_i32), + ) + + def __instancecheck__(cls, instance): + return ( + isinstance(instance, _fbthrift_python_types.Map) and + instance._fbthrift_same_type(*cls._fbthrift_type_info()) + ) + +class Map__string_Map__string_i32(_fbthrift_python_types.Map, metaclass=Map__string_Map__string_i32__Meta): + def __init__(self, *args, **kwargs): + super().__init__( + *Map__string_Map__string_i32._fbthrift_type_info(), + *args, + **kwargs, + ) + +class List__Set__string__Meta(type): + def _fbthrift_type_info(cls): + return ( + _fbthrift_python_types.SetTypeInfo(_fbthrift_python_types.typeinfo_string), + ) + + def __instancecheck__(cls, instance): + return ( + isinstance(instance, _fbthrift_python_types.List) and + instance._fbthrift_same_type(*cls._fbthrift_type_info()) + ) + +class List__Set__string(_fbthrift_python_types.List, metaclass=List__Set__string__Meta): + def __init__(self, *args, **kwargs): + super().__init__( + *List__Set__string._fbthrift_type_info(), + *args, + **kwargs, + ) + +class Map__string_List__SimpleStruct__Meta(type): + def _fbthrift_type_info(cls): + return ( + _fbthrift_python_types.typeinfo_string, + _fbthrift_python_types.ListTypeInfo(_fbthrift_python_types.StructTypeInfo(_module_thrift_types.SimpleStruct)), + ) + + def __instancecheck__(cls, instance): + return ( + isinstance(instance, _fbthrift_python_types.Map) and + instance._fbthrift_same_type(*cls._fbthrift_type_info()) + ) + +class Map__string_List__SimpleStruct(_fbthrift_python_types.Map, metaclass=Map__string_List__SimpleStruct__Meta): + def __init__(self, *args, **kwargs): + super().__init__( + *Map__string_List__SimpleStruct._fbthrift_type_info(), + *args, + **kwargs, + ) + +class List__List__string__Meta(type): + def _fbthrift_type_info(cls): + return ( + _fbthrift_python_types.ListTypeInfo(_fbthrift_python_types.typeinfo_string), + ) + + def __instancecheck__(cls, instance): + return ( + isinstance(instance, _fbthrift_python_types.List) and + instance._fbthrift_same_type(*cls._fbthrift_type_info()) + ) + +class List__List__string(_fbthrift_python_types.List, metaclass=List__List__string__Meta): + def __init__(self, *args, **kwargs): + super().__init__( + *List__List__string._fbthrift_type_info(), + *args, + **kwargs, + ) + +class List__Set__i32__Meta(type): + def _fbthrift_type_info(cls): + return ( + _fbthrift_python_types.SetTypeInfo(_fbthrift_python_types.typeinfo_i32), + ) + + def __instancecheck__(cls, instance): + return ( + isinstance(instance, _fbthrift_python_types.List) and + instance._fbthrift_same_type(*cls._fbthrift_type_info()) + ) + +class List__Set__i32(_fbthrift_python_types.List, metaclass=List__Set__i32__Meta): + def __init__(self, *args, **kwargs): + super().__init__( + *List__Set__i32._fbthrift_type_info(), + *args, + **kwargs, + ) + +class List__Map__string_string__Meta(type): + def _fbthrift_type_info(cls): + return ( + _fbthrift_python_types.MapTypeInfo(_fbthrift_python_types.typeinfo_string, _fbthrift_python_types.typeinfo_string), + ) + + def __instancecheck__(cls, instance): + return ( + isinstance(instance, _fbthrift_python_types.List) and + instance._fbthrift_same_type(*cls._fbthrift_type_info()) + ) + +class List__Map__string_string(_fbthrift_python_types.List, metaclass=List__Map__string_string__Meta): + def __init__(self, *args, **kwargs): + super().__init__( + *List__Map__string_string._fbthrift_type_info(), + *args, + **kwargs, + ) + +class List__binary__Meta(type): + def _fbthrift_type_info(cls): + return ( + _fbthrift_python_types.typeinfo_binary, + ) + + def __instancecheck__(cls, instance): + return ( + isinstance(instance, _fbthrift_python_types.List) and + instance._fbthrift_same_type(*cls._fbthrift_type_info()) + ) + +class List__binary(_fbthrift_python_types.List, metaclass=List__binary__Meta): + def __init__(self, *args, **kwargs): + super().__init__( + *List__binary._fbthrift_type_info(), + *args, + **kwargs, + ) + +class Set__binary__Meta(type): + def _fbthrift_type_info(cls): + return ( + _fbthrift_python_types.typeinfo_binary, + ) + + def __instancecheck__(cls, instance): + return ( + isinstance(instance, _fbthrift_python_types.Set) and + instance._fbthrift_same_type(*cls._fbthrift_type_info()) + ) + +class Set__binary(_fbthrift_python_types.Set, metaclass=Set__binary__Meta): + def __init__(self, *args, **kwargs): + super().__init__( + *Set__binary._fbthrift_type_info(), + *args, + **kwargs, + ) + +class List__AnEnum__Meta(type): + def _fbthrift_type_info(cls): + return ( + _fbthrift_python_types.EnumTypeInfo(_module_thrift_types.AnEnum), + ) + + def __instancecheck__(cls, instance): + return ( + isinstance(instance, _fbthrift_python_types.List) and + instance._fbthrift_same_type(*cls._fbthrift_type_info()) + ) + +class List__AnEnum(_fbthrift_python_types.List, metaclass=List__AnEnum__Meta): + def __init__(self, *args, **kwargs): + super().__init__( + *List__AnEnum._fbthrift_type_info(), + *args, + **kwargs, + ) + +class _std_unordered_map__Map__i32_i32__Meta(type): + def _fbthrift_type_info(cls): + return ( + _fbthrift_python_types.typeinfo_i32, + _fbthrift_python_types.typeinfo_i32, + ) + + def __instancecheck__(cls, instance): + return ( + isinstance(instance, _fbthrift_python_types.Map) and + instance._fbthrift_same_type(*cls._fbthrift_type_info()) + ) + +class _std_unordered_map__Map__i32_i32(_fbthrift_python_types.Map, metaclass=_std_unordered_map__Map__i32_i32__Meta): + def __init__(self, *args, **kwargs): + super().__init__( + *_std_unordered_map__Map__i32_i32._fbthrift_type_info(), + *args, + **kwargs, + ) + +class _MyType__List__i32__Meta(type): + def _fbthrift_type_info(cls): + return ( + _fbthrift_python_types.typeinfo_i32, + ) + + def __instancecheck__(cls, instance): + return ( + isinstance(instance, _fbthrift_python_types.List) and + instance._fbthrift_same_type(*cls._fbthrift_type_info()) + ) + +class _MyType__List__i32(_fbthrift_python_types.List, metaclass=_MyType__List__i32__Meta): + def __init__(self, *args, **kwargs): + super().__init__( + *_MyType__List__i32._fbthrift_type_info(), + *args, + **kwargs, + ) + +class _MyType__Set__i32__Meta(type): + def _fbthrift_type_info(cls): + return ( + _fbthrift_python_types.typeinfo_i32, + ) + + def __instancecheck__(cls, instance): + return ( + isinstance(instance, _fbthrift_python_types.Set) and + instance._fbthrift_same_type(*cls._fbthrift_type_info()) + ) + +class _MyType__Set__i32(_fbthrift_python_types.Set, metaclass=_MyType__Set__i32__Meta): + def __init__(self, *args, **kwargs): + super().__init__( + *_MyType__Set__i32._fbthrift_type_info(), + *args, + **kwargs, + ) + +class _MyType__Map__i32_i32__Meta(type): + def _fbthrift_type_info(cls): + return ( + _fbthrift_python_types.typeinfo_i32, + _fbthrift_python_types.typeinfo_i32, + ) + + def __instancecheck__(cls, instance): + return ( + isinstance(instance, _fbthrift_python_types.Map) and + instance._fbthrift_same_type(*cls._fbthrift_type_info()) + ) + +class _MyType__Map__i32_i32(_fbthrift_python_types.Map, metaclass=_MyType__Map__i32_i32__Meta): + def __init__(self, *args, **kwargs): + super().__init__( + *_MyType__Map__i32_i32._fbthrift_type_info(), + *args, + **kwargs, + ) + +class _py3_simple_AdaptedList__List__i32__Meta(type): + def _fbthrift_type_info(cls): + return ( + _fbthrift_python_types.typeinfo_i32, + ) + + def __instancecheck__(cls, instance): + return ( + isinstance(instance, _fbthrift_python_types.List) and + instance._fbthrift_same_type(*cls._fbthrift_type_info()) + ) + +class _py3_simple_AdaptedList__List__i32(_fbthrift_python_types.List, metaclass=_py3_simple_AdaptedList__List__i32__Meta): + def __init__(self, *args, **kwargs): + super().__init__( + *_py3_simple_AdaptedList__List__i32._fbthrift_type_info(), + *args, + **kwargs, + ) + +class _py3_simple_AdaptedSet__Set__i32__Meta(type): + def _fbthrift_type_info(cls): + return ( + _fbthrift_python_types.typeinfo_i32, + ) + + def __instancecheck__(cls, instance): + return ( + isinstance(instance, _fbthrift_python_types.Set) and + instance._fbthrift_same_type(*cls._fbthrift_type_info()) + ) + +class _py3_simple_AdaptedSet__Set__i32(_fbthrift_python_types.Set, metaclass=_py3_simple_AdaptedSet__Set__i32__Meta): + def __init__(self, *args, **kwargs): + super().__init__( + *_py3_simple_AdaptedSet__Set__i32._fbthrift_type_info(), + *args, + **kwargs, + ) + +class _py3_simple_AdaptedMap__Map__i32_i32__Meta(type): + def _fbthrift_type_info(cls): + return ( + _fbthrift_python_types.typeinfo_i32, + _fbthrift_python_types.typeinfo_i32, + ) + + def __instancecheck__(cls, instance): + return ( + isinstance(instance, _fbthrift_python_types.Map) and + instance._fbthrift_same_type(*cls._fbthrift_type_info()) + ) + +class _py3_simple_AdaptedMap__Map__i32_i32(_fbthrift_python_types.Map, metaclass=_py3_simple_AdaptedMap__Map__i32_i32__Meta): + def __init__(self, *args, **kwargs): + super().__init__( + *_py3_simple_AdaptedMap__Map__i32_i32._fbthrift_type_info(), + *args, + **kwargs, + ) + +class Map__i32_double__Meta(type): + def _fbthrift_type_info(cls): + return ( + _fbthrift_python_types.typeinfo_i32, + _fbthrift_python_types.typeinfo_double, + ) + + def __instancecheck__(cls, instance): + return ( + isinstance(instance, _fbthrift_python_types.Map) and + instance._fbthrift_same_type(*cls._fbthrift_type_info()) + ) + +class Map__i32_double(_fbthrift_python_types.Map, metaclass=Map__i32_double__Meta): + def __init__(self, *args, **kwargs): + super().__init__( + *Map__i32_double._fbthrift_type_info(), + *args, + **kwargs, + ) + +class List__Map__i32_double__Meta(type): + def _fbthrift_type_info(cls): + return ( + _fbthrift_python_types.MapTypeInfo(_fbthrift_python_types.typeinfo_i32, _fbthrift_python_types.typeinfo_double), + ) + + def __instancecheck__(cls, instance): + return ( + isinstance(instance, _fbthrift_python_types.List) and + instance._fbthrift_same_type(*cls._fbthrift_type_info()) + ) + +class List__Map__i32_double(_fbthrift_python_types.List, metaclass=List__Map__i32_double__Meta): + def __init__(self, *args, **kwargs): + super().__init__( + *List__Map__i32_double._fbthrift_type_info(), + *args, + **kwargs, + ) + +class Map__AnEnumRenamed_i32__Meta(type): + def _fbthrift_type_info(cls): + return ( + _fbthrift_python_types.EnumTypeInfo(_module_thrift_types.AnEnumRenamed), + _fbthrift_python_types.typeinfo_i32, + ) + + def __instancecheck__(cls, instance): + return ( + isinstance(instance, _fbthrift_python_types.Map) and + instance._fbthrift_same_type(*cls._fbthrift_type_info()) + ) + +class Map__AnEnumRenamed_i32(_fbthrift_python_types.Map, metaclass=Map__AnEnumRenamed_i32__Meta): + def __init__(self, *args, **kwargs): + super().__init__( + *Map__AnEnumRenamed_i32._fbthrift_type_info(), + *args, + **kwargs, + ) + diff --git a/thrift/lib/py3/test/auto_migrate/lists.py b/thrift/lib/py3/test/auto_migrate/lists.py index b45b484c363..e02ad591109 100644 --- a/thrift/lib/py3/test/auto_migrate/lists.py +++ b/thrift/lib/py3/test/auto_migrate/lists.py @@ -24,14 +24,21 @@ easy, I32List, int_list, + List__i16, + List__i32, + List__string, ListTypes, StringList, StrList2D, Uint32List, ) -from thrift.lib.py3.test.auto_migrate.auto_migrate_util import brokenInAutoMigrate +from thrift.lib.py3.test.auto_migrate.auto_migrate_util import ( + brokenInAutoMigrate, + is_auto_migrated, +) from thrift.lib.python.test.testing_utils import Untruthy -from thrift.py3.types import Container +from thrift.py3.types import Container, List as Py3List +from thrift.python.types import List as PythonList class ListTests(unittest.TestCase): @@ -49,6 +56,25 @@ def test_list_of_None(self) -> None: # but got `List[None]`. I32List([None, None, None]) + with self.assertRaises(TypeError): + # pyre-fixme[6]: Expected `Optional[typing.Sequence[int]]` for 1st param + # but got `List[None]`. + List__i32([None, None, None]) + + def test_isinstance(self) -> None: + base_cls = PythonList if is_auto_migrated() else Py3List + self.assertIsInstance(List__i32(range(5)), base_cls) + self.assertIsInstance(List__i32(range(5)), List__i32) + self.assertIsInstance(easy(val_list=[1, 2, 3]).val_list, base_cls) + self.assertIsInstance(easy(val_list=[1, 2, 3]).val_list, List__i32) + self.assertIsInstance(I32List(range(5)), base_cls) + self.assertIsInstance(I32List(range(5)), List__i32) + + self.assertNotIsInstance(List__i16(range(5)), List__i32) + self.assertNotIsInstance( + List__string([f"str_{i}" for i in range(5)]), List__i32 + ) + def test_list_creation_with_list_items(self) -> None: a = ["one", "two", "three"] b = ["cyan", "magenta", "yellow"] @@ -128,7 +154,7 @@ def test_slicing(self) -> None: def test_comparisons(self) -> None: x = I32List([1, 2, 3, 4]) - y = I32List([1, 2, 3, 4, 5]) + y = List__i32([1, 2, 3, 4, 5]) z = I32List([1, 2, 3, 1, 10]) # pyre-fixme[6]: For 2nd param expected `SupportsDunderGT[Variable[_T]]` but diff --git a/thrift/lib/py3/test/auto_migrate/maps.py b/thrift/lib/py3/test/auto_migrate/maps.py index 2494afa0bcf..c4da262f8f8 100644 --- a/thrift/lib/py3/test/auto_migrate/maps.py +++ b/thrift/lib/py3/test/auto_migrate/maps.py @@ -19,15 +19,24 @@ from typing import Dict, List from testing.types import ( + Color, + ColorGroups, F14MapFollyString, LocationMap, + Map__Color_Color, + Map__string_i64, + Map__string_List__i32, StrI32ListMap, StrIntMap, StrStrIntListMapMap, StrStrMap, ) -from thrift.lib.py3.test.auto_migrate.auto_migrate_util import brokenInAutoMigrate -from thrift.py3.types import Container +from thrift.lib.py3.test.auto_migrate.auto_migrate_util import ( + brokenInAutoMigrate, + is_auto_migrated, +) +from thrift.py3.types import Container, Map as Py3Map +from thrift.python.types import Map as PythonMap class MapTests(unittest.TestCase): @@ -54,6 +63,22 @@ def test_None(self) -> None: # `Dict[str, Dict[str, None]]`. StrStrIntListMapMap({"bar": {"foo": None}}) + def test_isinstance(self) -> None: + base_cls = PythonMap if is_auto_migrated() else Py3Map + str_int_map = {"foo": 5, "bar": 4} + self.assertIsInstance(Map__string_i64(str_int_map), base_cls) + self.assertIsInstance(Map__string_i64(str_int_map), Map__string_i64) + color_map = {Color.red: Color.blue, Color.green: Color.red} + self.assertIsInstance(ColorGroups(color_map=color_map).color_map, base_cls) + self.assertIsInstance( + ColorGroups(color_map=color_map).color_map, Map__Color_Color + ) + self.assertIsInstance(StrIntMap(str_int_map), base_cls) + self.assertIsInstance(StrIntMap(str_int_map), Map__string_i64) + + self.assertNotIsInstance(StrIntMap(str_int_map), Map__Color_Color) + self.assertNotIsInstance(StrIntMap(str_int_map), Map__string_List__i32) + def test_getitem(self) -> None: x = StrStrMap({"test": "value"}) self.assertEqual(x["test"], "value") @@ -97,7 +122,7 @@ def test_empty(self) -> None: StrStrIntListMapMap({"foo": {"bar": []}}) def test_mixed_construction(self) -> None: - s = StrI32ListMap({"bar": [0, 1]}) + s = Map__string_List__i32({"bar": [0, 1]}) x = StrStrIntListMapMap({"foo": s}) px: Dict[str, Dict[str, List[int]]] = {} # pyre-fixme[6]: Expected `Dict[str, List[int]]` for 2nd param but got @@ -131,7 +156,7 @@ def test_hashability(self) -> None: def test_equality(self) -> None: x = StrIntMap({"foo": 5, "bar": 4}) - y = StrIntMap({"foo": 4, "bar": 5}) + y = Map__string_i64({"foo": 4, "bar": 5}) self.assertNotEqual(x, y) y = StrIntMap({"foo": 5, "bar": 4}) self.assertEqual(x, y) diff --git a/thrift/lib/py3/test/auto_migrate/reflection.py b/thrift/lib/py3/test/auto_migrate/reflection.py index a58d85e4442..b0cc62ac527 100644 --- a/thrift/lib/py3/test/auto_migrate/reflection.py +++ b/thrift/lib/py3/test/auto_migrate/reflection.py @@ -17,8 +17,6 @@ import unittest -import testing.types - from testing.clients import TestingService from testing.services import TestingServiceInterface from testing.types import ( @@ -27,8 +25,10 @@ HardError, I32List, Integers, + List__i32, Messy, Runtime, + Set__Color, SimpleError, StrI32ListMap, StrStrIntListMapMap, @@ -112,18 +112,18 @@ def test_exception(self) -> None: @brokenInAutoMigrate() def test_list_element(self) -> None: - x = testing.types.List__i32([1, 2, 3]) + x = List__i32([1, 2, 3]) self.assertTrue(inspectable(x)) - self.assertTrue(inspectable(testing.types.List__i32)) + self.assertTrue(inspectable(List__i32)) r = inspect(x) self.assertEqual(r.value, int) self.assertEqual(r.kind, NumberType.I32) @brokenInAutoMigrate() def test_set_element(self) -> None: - x = testing.types.Set__Color({Color.red, Color.blue}) + x = Set__Color({Color.red, Color.blue}) self.assertTrue(inspectable(x)) - self.assertTrue(inspectable(testing.types.Set__Color)) + self.assertTrue(inspectable(Set__Color)) r = inspect(x) self.assertEqual(r.value, Color) self.assertEqual(r.kind, NumberType.NOT_A_NUMBER) diff --git a/thrift/lib/py3/test/auto_migrate/sets.py b/thrift/lib/py3/test/auto_migrate/sets.py index 0aaee6d3dc7..cf2e10f3d89 100644 --- a/thrift/lib/py3/test/auto_migrate/sets.py +++ b/thrift/lib/py3/test/auto_migrate/sets.py @@ -19,17 +19,31 @@ import unittest from typing import AbstractSet, Sequence, Tuple -from testing.types import SetI32, SetI32Lists, SetSetI32Lists, SetTypes -from thrift.lib.py3.test.auto_migrate.auto_migrate_util import brokenInAutoMigrate +from testing.types import ( + Color, + ColorGroups, + Set__Color, + Set__i32, + Set__string, + SetI32, + SetI32Lists, + SetSetI32Lists, + SetTypes, +) +from thrift.lib.py3.test.auto_migrate.auto_migrate_util import ( + brokenInAutoMigrate, + is_auto_migrated, +) from thrift.lib.python.test.testing_utils import Untruthy -from thrift.py3.types import Container +from thrift.py3.types import Container, Set as Py3Set +from thrift.python.types import Set as PythonSet class SetTests(unittest.TestCase): def test_and(self) -> None: x = SetI32({1, 3, 4, 5}) - y = SetI32({1, 2, 4, 6}) + y = Set__i32({1, 2, 4, 6}) z = {1, 2, 4, 6} self.assertEqual(x & y, set(x) & set(y)) self.assertEqual(y & x, set(y) & set(x)) @@ -39,7 +53,7 @@ def test_and(self) -> None: def test_or(self) -> None: x = SetI32({1, 3, 4, 5}) - y = SetI32({1, 2, 4, 6}) + y = Set__i32({1, 2, 4, 6}) z = {1, 3, 4, 5} self.assertEqual(x | y, set(x) | set(y)) self.assertEqual(y | x, set(y) | set(x)) @@ -49,7 +63,7 @@ def test_or(self) -> None: def test_xor(self) -> None: x = SetI32({1, 3, 4, 5}) - y = SetI32({1, 2, 4, 6}) + y = Set__i32({1, 2, 4, 6}) z = {1, 2, 4, 6} self.assertEqual(x ^ y, set(x) ^ set(y)) self.assertEqual(y ^ x, set(y) ^ set(x)) @@ -59,7 +73,7 @@ def test_xor(self) -> None: def test_sub(self) -> None: x = SetI32({1, 3, 4, 5}) - y = SetI32({1, 2, 4, 6}) + y = Set__i32({1, 2, 4, 6}) z = {1, 2, 4, 6} self.assertEqual(x - y, set(x) - set(y)) self.assertEqual(y - x, set(y) - set(x)) @@ -67,9 +81,22 @@ def test_sub(self) -> None: self.assertEqual(x - z, set(x) - set(y)) self.assertEqual(x.difference(y), set(x) - set(y)) + def test_isinstance(self) -> None: + base_cls = PythonSet if is_auto_migrated() else Py3Set + self.assertIsInstance(Set__i32({1, 2, 4}), base_cls) + self.assertIsInstance(Set__i32({1, 2, 4}), Set__i32) + color_set = {Color.red, Color.blue} + self.assertIsInstance(ColorGroups(color_set=color_set).color_set, base_cls) + self.assertIsInstance(ColorGroups(color_set=color_set).color_set, Set__Color) + self.assertIsInstance(SetI32({1, 2, 4}), base_cls) + self.assertIsInstance(SetI32({1, 2, 4}), Set__i32) + + self.assertNotIsInstance(Set__i32({1, 2, 4}), Set__Color) + self.assertNotIsInstance(Set__string({f"str_{i}" for i in range(5)}), Set__i32) + def test_comparisons(self) -> None: x = SetI32({1, 2, 3, 4}) - y = SetI32({1, 2, 3}) + y = Set__i32({1, 2, 3}) x2 = copy.copy(x) y2 = {1, 2, 3} diff --git a/thrift/lib/python/types.pyx b/thrift/lib/python/types.pyx index 4c25f7102ad..02ff3044324 100644 --- a/thrift/lib/python/types.pyx +++ b/thrift/lib/python/types.pyx @@ -2016,6 +2016,9 @@ cdef class List(Container): def count(self, item): return self._fbthrift_elements.count(item) + def _fbthrift_same_type(self, other_elem_type): + return self._fbthrift_val_info.same_as(other_elem_type) + tag_object_as_sequence(List) Sequence.register(List) @@ -2128,6 +2131,9 @@ cdef class Set(Container): def issuperset(self, other): return self >= other + def _fbthrift_same_type(self, other_elem_type): + return self._fbthrift_val_info.same_as(other_elem_type) + pySet.register(Set) @@ -2207,6 +2213,11 @@ cdef class Map(Container): except KeyError: return default + def _fbthrift_same_type(self, other_key_type, other_val_type): + return ( + self._fbthrift_key_info.same_as(other_key_type) and + self._fbthrift_val_info.same_as(other_val_type) + ) tag_object_as_mapping(Map) Mapping.register(Map)