keleshev / schema

Schema validation just got Pythonic
MIT License
2.86k stars 214 forks source link

Type checker reports error when using the `Use` class in a boolean operator #322

Open PleasantFuban opened 1 month ago

PleasantFuban commented 1 month ago

Here is a minimal example:

schema = Schema({
    'party': And(str, Use(str.lower), lambda s: s in ('alice', 'bob'))
})

This code works fine. However, the type checker reports an error saying that a Use instance cannot be used as an argument of And(). This is true in both VS Code (which uses pyright by default) and PyCharm.

I'm using similar validation rules in many places. As a result, my code is full of # type: ignores because otherwise I will have to disable type checking completely.

Is it possible to solve this issue?

mutricyl commented 2 weeks ago

I am not able to reproduce your issue. Is mypy also complaining ? what version of python/schema are you using ?

PleasantFuban commented 2 weeks ago

Mypy does not complain in that minimal example (even when in strict mode), but does complain when moving And out of the schema:

And(str, Use(str.lower), lambda s: s in ('alice', 'bob'))
# Mypy reports: Argument 2 to "And" has incompatible type "Use"; expected "Callable[..., Any]"
# VS Code (pyright) reports: The type 'Use' is incompatible with the types 'Schema' and '(...) -> Any'
# PyCharm reports something similar to VS Code

{'party': And(str, Use(str.lower), lambda s: s in ('alice', 'bob'))}
# Mypy still complains

Schema({'party': And(str, Use(str.lower), lambda s: s in ('alice', 'bob'))})
# Mypy does not report anything

I haven't used Mypy before, so I'm not sure if it is a bug.

I'm using schema 0.7.7 on Python 3.12. Mypy's version 1.11.1.

mutricyl commented 2 weeks ago

ok, I now have the same issue. No solution yet but as a dirty workaround you can replace

Use(str.lower)

with

eval("Use(str.lower)")
HorridModz commented 1 week ago

ok, I now have the same issue. No solution yet but as a dirty workaround you can replace

Use(str.lower)

with

eval("Use(str.lower)")

That's really ugly. Why not just ignore the error?

# type: ignore
HorridModz commented 1 week ago

@mutricyl By the way, not to criticize, but I noticed your markdown code snippet looks like this (copy and pasted from your comment):

> ```python
> print("Hello World!")
> ```

Those greater than symbols are unnecessary. Just typing ``` is sufficient:

```python
print("Hello World!")


Hope this helps!
PleasantFuban commented 1 week ago

ok, I now have the same issue. No solution yet but as a dirty workaround you can replace

Use(str.lower)

with

eval("Use(str.lower)")

Understood, thank you. Now I've put all schemas in a single file, so I can just disable type checking for that file. I'm comfortable with this.

mutricyl commented 1 week ago

I agree that the eval trick is ugly. You can narrow the type ignore to the specific issue : # type: ignore[call-arg] likewise if pyright complains: # pyright: ignore[<whateverPyrightIssueName>]

Apparently mypy does not consider Use as being a callable. I have added a __call__ function to Use class and it looks to solve the issue.

class Use:

(...)

    def __call__(self, *args: Any, **kwds: Any) -> Any:
        pass

However I still have an issue mixing And and Or.