Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix isinstance to support Generic type object #2952

Merged
merged 4 commits into from Aug 26, 2021

Conversation

@Snowapril
Copy link
Contributor

@Snowapril Snowapril commented Aug 24, 2021

This revision fix issue #2936.

In original codes, there are problem in both builtins::isinstance and vm.isinstance.

builtins::isinstance use single_or_tuple_any function for checking
given object is <class 'type'> or if it is tuple, iterating over them
recursively.
But it did not check given object have __instancecheck__ if it isn't <class 'type'>.

vm.isinstance get second argument as PyTypeRef.
Because of it, call_special_method use instancecheck of TypeProtocol's one and
never reach to user defined __instancecheck__

Therefore I fixed it with referenced cpython implementation.
And also add extra test about it.

Before

>>>>> from typing import Sequence
>>>>> isinstance([], Sequence)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: isinstance() arg 2 must be a type or tuple of types, not _GenericAlias

>>>>> class G:
.....     def __instancecheck__(self, obj):
.....             return True
.....
>>>>> isinstance([], G())
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: isinstance() arg 2 must be a type or tuple of types, not G

After

>>>>> from typing import Sequence
>>>>> isinstance([], Sequence)
True

>>>>> class G:
.....   def __instancecheck__(self, other):
.....           return True
..... 
>>>>> isinstance([], G())
True

issue #2943 is almost same with this PR, but I want to know If I'm going right way. Thanks.

@Snowapril Snowapril changed the title Fix isinstance Fix isinstance to support Generic type object Aug 24, 2021
@Snowapril Snowapril marked this pull request as draft Aug 24, 2021
@Snowapril
Copy link
Contributor Author

@Snowapril Snowapril commented Aug 24, 2021

I found test_isinstance.py in cpython repository, and current implementation(also original one) fail it. As far as I fixed it, I'll reopen it. Sorry

@Snowapril Snowapril closed this Aug 24, 2021
@Snowapril Snowapril reopened this Aug 24, 2021
vm/src/vm.rs Outdated Show resolved Hide resolved
@Snowapril
Copy link
Contributor Author

@Snowapril Snowapril commented Aug 24, 2021

@youknowone I think failed tests in newly added test_isinstance.py is little complex to fix in this PR and there is also issubclass test not isinstance. How about open failed tests as TODO for future contributors?

@DimitrisJim
Copy link
Member

@DimitrisJim DimitrisJim commented Aug 24, 2021

@Snowapril yeah, you've done the right thing to mark them as TODO's. The rest of the test cases can be fixed in the future.

extra_tests/snippets/isinstance.py Outdated Show resolved Hide resolved
vm/src/vm.rs Outdated Show resolved Hide resolved
@youknowone
Copy link
Member

@youknowone youknowone commented Aug 24, 2021

totally positive. you don't need to make everything working to add a test file.

@Snowapril Snowapril marked this pull request as ready for review Aug 24, 2021
This commit fix issue RustPython#2936.

In original codes, there are problem in both `builtins::isinstance` and
`vm.isinstance`.

`builtins::isinstance` use `single_or_tuple_any` function for checking
given object is `<class 'type'>` or if it is tuple, iterating over them
recursively.
But it did not check given object have `__instancecheck__`
if it is not `<class 'type'>`.

`vm.isinstance` get second argument as `PyTypeRef`. Because of it,
`call_special_method` use `instancecheck` of `TypeProtocol`'s one and
never reach to user defined `__instancecheck__`

Therefore I referenced cpython implementation and fix it.

Signed-off-by: snowapril <sinjihng@gmail.com>
Snowapril added 3 commits Aug 25, 2021
Signed-off-by: snowapril <sinjihng@gmail.com>
Signed-off-by: snowapril <sinjihng@gmail.com>
Signed-off-by: snowapril <sinjihng@gmail.com>
},
vm,
)
vm.isinstance(&obj, &typ)
Copy link
Member

@youknowone youknowone Aug 26, 2021

mm, i don't remember very well, but maybe this function was written like this because vm.isinstance was used when we don't want tuple comparision but builtins::isinstance is used when python isinstance is required.

@coolreader18 do you have any idea about this?

Copy link
Member

@youknowone youknowone Aug 26, 2021

Ok, I found vm.isinstance practically doesn't have any difference, and even not used that much.

@youknowone
Copy link
Member

@youknowone youknowone commented Aug 26, 2021

The approach looks good. But let me check about the vm.isinstance use cases before merge.

},
vm,
)
vm.isinstance(&obj, &typ)
Copy link
Member

@youknowone youknowone Aug 26, 2021

Ok, I found vm.isinstance practically doesn't have any difference, and even not used that much.

@youknowone youknowone merged commit fbea3f0 into RustPython:main Aug 26, 2021
10 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
Linked issues

Successfully merging this pull request may close these issues.

None yet

4 participants