feat: Union and tuple support for is_instance_of, and Union for is_instance_of_any - #33
feat: Union and tuple support for is_instance_of, and Union for is_instance_of_any#33dpinol wants to merge 1 commit into
Conversation
09b266d to
b68b277
Compare
|
Thanks for this one. It is a real bug, and a bigger one than the title claims. Here is assert_that(Person()).is_instance_of(Person | Car) # passes
assert_that(Person()).is_instance_of((Person, Car)) # passes
assert_that(Car()).is_instance_of(Person | str) # AssertionFailure: ... instance of class <Union>
assert_that(Car()).is_instance_of((Person, str)) # AttributeError: 'tuple' object has no attribute '__name__'The tuple form does not fail, it crashes, and an What makes it slightly embarrassing is that I fixed this once already and only on one half. Go through a matcher and the same case behaves: assert_that({"who": Car()}).matches_structure({"who": match.is_instance_of((Person, str))})
# AssertionFailure: ... <Person, str>, but was <Car object> of type <Car>That path uses The rest of your change I want: The Pyright does take it under About the wall of red CI: that is mine, not yours, and there was no way to find it from the repository. Three files under uv run python scripts/generate_poll_protocols.py
uv run python scripts/generate_check_protocols.py
ASSERTPY2_UPDATE_API=1 uv run pytest tests/test_api_compatibility.pyEither way, none of that being discoverable is a problem on my side, and writing it down has gone on my list. Two small things on the tests. Catch |
|
Pushed to
Your scope is unchanged: |
How do you run pyright? With 1.1.413 (only on npm) I get no errors
And on 1.1.411 it's even more "clever"
|
Do you really want |
|
You were right, I measured 1.1.411. Both my objections fall: Only union call sites fail on 1.1.411, and On isinstance(1.5, (float, (int, str))) # True
assert_that(x).is_instance_of_any(float, (int, str)) # AttributeError: 'tuple' object has no attribute '__name__'Same bug you reported, one level in.
It is recursive on Still yours:
|
b68b277 to
fd1855f
Compare
|
Amazing, I amended my commit. Please let me know if I missed something. |
|
Keep
Removing Known limitation, ours, not typeable: isinstance(1, int | list[int]) # True, `int` matched first
isinstance("x", int | list[int]) # TypeError
isinstance(1, list[int] | int) # TypeErrorYour side, dead since you moved to -def _class_name(some_class: type | UnionType) -> str:
- if isinstance(some_class, UnionType):
- return " | ".join(arg.__name__ for arg in some_class.__args__)
- if isinstance(some_class, tuple):
- return ", ".join(_class_name(arg) for arg in some_class)
- return some_class.__name__plus its Mine, pushed to your branch once that is gone: the facade ladder in |
ClassInfo used in is_instance_of to support whatever python's isintance supports TypeForm allows converting type[U]->Assertion[U] is_instance_of signature at _typing.py uses tuple[type | UnionType, ...] instead of ClassInfo to avoid ty error: Variable of type `tuple[<class 'bool'>, <class 'int'>]` is not allowed in a type expression _type_expression_name to also strip namespace from Union'ed types for consistency Added class tests for is_instance_of_any
fd1855f to
5d2277b
Compare
|
Cool, I removed the stale |
ClassInfoused inis_instance_ofto support whatever python'sisintancesupportsTypeFormallows converting type hinttype[U]toAssertion[U]is_instance_ofsignature at _typing.py usestuple[type | UnionType, ...]instead ofClassInfoto avoid ty error: