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

Change the way sets and dicts are handled in the library #2

Closed
wants to merge 3 commits into from

Conversation

mkmkme
Copy link
Collaborator

@mkmkme mkmkme commented Jul 15, 2024

This pull request backports yet unmerged PR from hiredis and additionally changes the way dicts are handled.

This changes are necessary because RESP3 allows:

  • dict value to be a set
  • dict key to be a set or an array
  • have a dict inside a set

None of these things are allowed in Python. Therefore it was decided to replace sets with lists and dicts with lists of tuples. The client is supposed to handle the types and convert if necessary themselves.

This is a breaking change

gerzse and others added 3 commits July 15, 2024 11:37
In some (rare) cases, the sets from a Redis response contain nested
types that are not hashable in Python, for example maps. To handle these
cases uniformly, always return Python lists for Redis sets. The elements
will still be unique, relying on the correctness of data arriving from
the server.
Previous commit changed the way sets were handled. Since sets cannot be
used as dict values, they have been replaced as lists internally.

There is, however, the opposite side of the issue: sets or arrays being
used as *keys* in the dict. It is absolutely valid RESP3-wise, but
invalid from Python perspective as sets and lists are not hashable.

This commit changes the way dicts are handled by making them lists of
tuples instead. The library client is supposed to handle the conversion
into proper types themselves.

As previous commit, this commit introduces a breaking change.

Signed-off-by: Mikhail Koviazin <[email protected]>
@mkmkme
Copy link
Collaborator Author

mkmkme commented Jul 15, 2024

huh, apparently PyPy works in a slightly different. Investigating.

@mkmkme mkmkme marked this pull request as draft July 15, 2024 13:41
@zuiderkwast
Copy link
Collaborator

zuiderkwast commented Jul 15, 2024

When you say RESP3 dict, it's a RESP3 map, right? (Dict is a Python term, and a Valkey internal datastructure.)

Even if RESP3 allows complex map keys and set elements, I don't think Valkey ever returns values like that. Hm... COMMAND seems to be the exception. How about some special handling just for COMMAND, replacing the set with a list only for COMMAND's response?

I guess modules can return stuff like that too. We could possibly forbid modules from doing that in Valkey. That would be a breaking change too, but I think could be good to forbid values like that, not only for Python but also JavaScript and probably other languages too.

Alternatives:

  • Add an option to return list for sets and list-of-pairs for maps.
  • Simply fail if some response contains these values, if the new option is off.

PyObject *t = PyTuple_New(2);
PyTuple_SET_ITEM(t, 0, obj);
PyTuple_SET_ITEM(t, 1, Py_None);
PyList_Append(parent, t);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I'm not mistaken there is a memleak here. You need a Py_DECREF after append.

@aiven-sal
Copy link
Member

aiven-sal commented Jul 15, 2024

Even if RESP3 allows complex map keys and set elements, I don't think Valkey ever returns values like that. Hm... COMMAND seems to be the exception. How about some special handling just for COMMAND, replacing the set with a list only for COMMAND's response?

AFAIK the API exposed by libvalkey-py is that of a simple RESP2/3 parser. With no knowledge about commands etc.

I think the best way to go is:

  • Add an option to return list for sets and list-of-pairs for maps.
  • Simply fail if some response contains these values, if the new option is off.

And we will just keep it always on in valkey-py.

@mkmkme
Copy link
Collaborator Author

mkmkme commented Jul 15, 2024

Thanks @aiven-sal and @zuiderkwast ! I'll fix it accordingly

@zuiderkwast
Copy link
Collaborator

we will just keep it always on in valkey-py

@aiven-sal so this only affects the communication beween valkey-py and libvalkey-py? It does not affect how valkey-py returns the replies to the end users?

@mkmkme
Copy link
Collaborator Author

mkmkme commented Jul 16, 2024

we will just keep it always on in valkey-py

@aiven-sal so this only affects the communication beween valkey-py and libvalkey-py? It does not affect how valkey-py returns the replies to the end users?

No, it's only about communication between valkey-py and libvalkey-py. By "client" here I meant exactly valkey-py :)

There won't be any breaking changes in valkey-py as it's meant to be widely-used

@mkmkme
Copy link
Collaborator Author

mkmkme commented Jul 16, 2024

I think I'll close this one in favour of creating a new one from scratch, as the proposed changes would require me to change even a commit that doesn't belong to me.

@mkmkme mkmkme closed this Jul 16, 2024
@mkmkme mkmkme deleted the mkmkme/fix-resp3 branch July 16, 2024 08:02
@mkmkme mkmkme restored the mkmkme/fix-resp3 branch July 18, 2024 15:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants