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

[Feature request] Typing support and migrating from redis-py #84

Open
Rafiot opened this issue Sep 2, 2024 · 20 comments
Open

[Feature request] Typing support and migrating from redis-py #84

Rafiot opened this issue Sep 2, 2024 · 20 comments
Labels

Comments

@Rafiot
Copy link

Rafiot commented Sep 2, 2024

Version: 6.0

Platform: Any

Description: The typing provided by the redis package is terrible and the recommended way is to use types-redis but this one obviously doesn't work with the valkey package, and there is no types-valkey (yet?).

I'm playing around to see if I can find a janky solution, but is there any chance you're planning to merge (and support) the types hints directly in the package? Or provide a types-valkey package at some point?

@aiven-sal
Copy link
Member

aiven-sal commented Sep 3, 2024

Hi!
I'd say that ideally we would like to have proper typing support. Of course adding types in a project of this size isn't a simple task. Re-using the work done for "types-redis" could certainly help.
Have you used that? Does it work well with recent versions of redis-py? It seems to be stuck at 4.6

@Rafiot
Copy link
Author

Rafiot commented Sep 3, 2024

Hi! Yes, I'm using it with redis-py 5.0.8 and it works perfectly fine, but I might very well not be using new features that are unsupported (python/typeshed#10592).

If I have time today, I'll have a look on how types-redis does to independently support async vs. non async calls. It might very well be a quick fix I to push to valkey-py.

@Rafiot
Copy link
Author

Rafiot commented Sep 3, 2024

Alright, so this is going to be a fun project. I may tell you things you already know, but that was new to me and there are a few questions to answer before starting to work on that.

First of all, as far as I can tell, the typing hints are completely broken and never work for anyone:

Async

import asyncio

from valkey.asyncio import Valkey


async def test() -> dict[bytes, bytes]:
    v: Valkey = Valkey()
    response_hset: int = await v.hset('foo', mapping={'bar': 'baz'})
    print(response_hset)
    h: dict[bytes, bytes] = await v.hgetall('foo')
    print(h)
    return h

asyncio.run(test())
$ (git::main) mypy test_async.py 
test_async.py:10: error: Incompatible types in "await" (actual type "Awaitable[int] | int", expected type "Awaitable[Any]")  [misc]
test_async.py:12: error: Incompatible types in "await" (actual type "Awaitable[dict[Any, Any]] | dict[Any, Any]", expected type "Awaitable[Any]")  [misc]
Found 2 errors in 1 file (checked 1 source file)

Sync

from valkey import Valkey

v: Valkey = Valkey()
v.hset('foo', mapping={'bar': 'baz'})
h: dict[bytes, bytes] = v.hgetall('foo')
print(h)
$ (git::main) mypy test.py 
test.py:7: error: Incompatible types in assignment (expression has type "Awaitable[dict[Any, Any]] | dict[Any, Any]", variable has type "dict[bytes, bytes]")  [assignment]
Found 1 error in 1 file (checked 1 source file)

That's because the way sync/async is implemented. For example, if you take hgetall, it's in valkey/commands/core.py -> HashCommands.hgetall, calls execute_command, and returns a dict.

And the Valkey inherits all the command classes so you we can do client.hgetall(...)

The way the async library works was very confusing to me at first because it's just defining the async class this way AsyncHashCommands = HashCommands. But then, execute_command is overwritten and this call returns an Awaitable.

TL;DR: It is a sane way to avoid too much code duplication, but makes typing a bit of a nightmare.

I'm not totally certain on the path forward from here but it would make sense to fix it as it seems the way to get it to work as-is looks like that, and I hate it.

I think the clean-ish way to do it without duplicating code is to integrate the .pyi files from types-redis into the valkey package, it seems to be possible.

Sorry that was pretty long, but it took me a while to understand what was going on.

What do you think?

@aiven-sal
Copy link
Member

Thanks for the through analysis!
My understanding is the the types in types-redis are not perfect (according to what I read in some comments).
But the current situation is that we can't enable type checking in the CI or in our IDEs because types are completely broken.
So if you say that types-redis works for you, using those types is probably going to be an improvement for everyone. I guess we won't be able to enable checks in CI anyway, but it should be a step in the right direction.

And yes, I agree that integrating those type annotations in valkey-py is the best way forward, rather than relying on external stubs.

@mkmkme
Copy link
Collaborator

mkmkme commented Sep 4, 2024

Hey @Rafiot ,

Thanks for the report! Do you want to handle it yourself? Otherwise I can have a look at it.

@Rafiot
Copy link
Author

Rafiot commented Sep 4, 2024

Hey @mkmkme, I'll try to get starting on it soon, but I have a few more urgent tasks first, so I'm not totally sure it will happen this week.

Regardless, it's going to take quite a bit of time, and I have a very limited understanding of the codebase (besides the report above), but I think the first thing to do is getting mypy to run on the repo, and increment from there.

If you (or anyone else) have time to work on it, it might make sense to have a dedicated branch for that?

@golgor
Copy link

golgor commented Sep 4, 2024

@Rafiot I'm a fairly new user of Redis/Valkey but I got annoyed by the lack of typing support from day 1 basically. I might be able to help out, I will at least track what you are doing and if I see something where I can help out I will try to.

Not sure if it is possible or acceptable to ask in the typeshed-repo if any of the maintainers behind types-redis is interested to support?

Thanks a lot for raising this!

@Rafiot
Copy link
Author

Rafiot commented Sep 5, 2024

Good point, I opened an issue with the maintainers of types-redis, we will see if they have ideas.

@amirreza8002
Copy link
Contributor

amirreza8002 commented Sep 6, 2024

hi @Rafiot

i was wondering if you don't mind if i send some patches on type hints that i know are wrong

one example being sismember type hinting value as str, but accepts bytes (and maybe others) :)

let me know what you think

@Rafiot
Copy link
Author

Rafiot commented Sep 6, 2024

Please all the PRs you feel are necessary. I barely started working on it and the starting point will be types-redis, so the most accurate it is, the better.

EDIT: Just to make sure, you're not talking of patching the type hints in this repo, right? As far as can tell, they are pretty much useless and they will most probably go away.

Rafiot added a commit to Rafiot/valkey-py that referenced this issue Sep 6, 2024
@Rafiot
Copy link
Author

Rafiot commented Sep 6, 2024

ok, so I did something quick and dirty (emphasis on dirty), and copied the content of types-redis in to valkey-py and renamed Redis -> Valkey / Hiredis -> Libvalkey / ...

With that, the very simple scripts above pass fine with mypy. It's not even close to be mergeable, but that's an okay starting point.

I think my next steps will be to make it possible to run mypy on valkey-py. It's gonna take a while and if some on you want to collaborate on that, it might make sense to have a branch to push changes gradually.

@aiven-sal
Copy link
Member

Awesome!

@Rafiot
Copy link
Author

Rafiot commented Sep 9, 2024

So just FYI, I'll slowly work on getting mypy to run on the branch in my repo. It's gonna take a while but if someone wants to contribute, please go for it.

And I'll also merge the changes from types-redis as they come in.

@mkmkme
Copy link
Collaborator

mkmkme commented Sep 10, 2024

Sounds great, thanks!

@Rafiot
Copy link
Author

Rafiot commented Sep 10, 2024

What's your feeling regarding PEP563? I find it much more readable and pleasant to use, but it requires python 3.7+.

@amirreza8002
Copy link
Contributor

What's your feeling regarding PEP563? I find it much more readable and pleasant to use, but it requires python 3.7+.

since this packages supports 3.8+ i think using __future__ would be good

my IDE would be a lot happier with new type hints, it doesn't work well with Union and stuff🙃

@Rafiot
Copy link
Author

Rafiot commented Sep 10, 2024

Good point, the python version won't be an issue. I might wait for a first working package without PEP 563 just so merging from the typeshed is easy-ish.

@Rafiot
Copy link
Author

Rafiot commented Sep 10, 2024

Alright, todays update: mypy passes on most of the public interface, and the tests for the commands in sync and async: https://github.com/Rafiot/valkey-py/blob/types/.mypy.ini

What do you think would be a good next step?

@mkmkme
Copy link
Collaborator

mkmkme commented Sep 11, 2024

I think one of the next steps should be to merge the signatures into the code. Having them in separate .pyi files is not that handy IMHO

@Rafiot
Copy link
Author

Rafiot commented Sep 11, 2024

On the long run, agreed, but due to the way the async is implemented, we will need to keep a .pyi file at least for that (or rewrite it completely). The main reason I'm not totally sure it is a good thing to do immediately is that it will make the merge a lot more complicated to review: I'm trying to change the minimal amount in the .py files and make sure it works.

Rafiot added a commit to Rafiot/valkey-py that referenced this issue Sep 11, 2024
@Rafiot Rafiot mentioned this issue Sep 11, 2024
5 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

5 participants