Q:

Redis: How to HMSET a dictionary from a Lua script?

I am trying to pass a Python dict as an argument to a Lua script and HMSET it to a Redis key from the script.
I have two questions.
How am I supposed to pass the dict from Python to Lua script and from the Lua script to Redis?
Passing it to Lua seems straightforward, with a json.dumps(). However, how do I convert it back to a dict (or Lua table I guess?) in Lua (I can not use Lua's require inside Redis' EVAL).
Although I still don't know how to pass a real dict to Redis from Lua, I am still playing with HMSET inside the Lua script and trying to assign to the key a string.
Why am I getting this error:
redis.exceptions.ResponseError: Error running script (call to f_2591f0a1987b36dd027b752af3591c92be845cd4):
@user_script:7: @user_script: 7: Wrong number of args calling Redis command From Lua script

provided that my Lua code uses the same number of args as my Python HMSET:
local key_name = KEYS[1]
redis.call('hmset', key_name, "some_val")

A:

First, please note that a Pythonic dict is not the same as a Redis Hash: while a dict can store any type as value and supports nesting, hashes are only 1-level deep and store strings. So, if your dict is nested and/or contains non-string values the mapping is non-trivial.
Now, assuming that the dict is indeed non-nested.

How am I supposed to pass the dict from Python to Lua script and from the Lua script to Redis?

As you're passing the JSONified representation, you can use Redis' Lua cjson library to parse it into a Lua table, likeso:
local dict = cjson.decode(ARGS[1])

Why am I getting this error:

The error is raised because you're calling HMSET (deprecated btw, replaced by HSET) without the field name argument. A correct way to do it (i.e. save the dict to a hash) would be something like the following:
local key_name = KEYS[1]
local dict = cjson.decode(ARGS[1])
for k, v in pairs(dict) do
  redis.call('HSET', key_name, k, v)
end

Or perhaps this slightly faster variant:
local key_name = KEYS[1]
local dict = cjson.decode(ARGS[1])
local payload = {}
for k, v in pairs(dict) do
  table.insert(payload, k)
  table.insert(payload, v)
end
redis.call('HSET', key_name, unpack(payload))

