Repository: opsdroid/opsdroid

Issue:
skill-seen broken with redis database?
I've been testing opsdroid with a redis database and the seen skill appears to be having problems serializing python datetime objects.

user: when did you last see user?
opsdroid: Whoops there has been an error.
opsdroid: Check the log for details.

this is the opsdroid log with DEBUG logging enabled:

```
notrexroof_1  | DEBUG opsdroid.memory: Putting seen to memory.
notrexroof_1  | DEBUG opsdroid.database.redis: Putting seen into Redis.
notrexroof_1  | ERROR opsdroid.core: Exception when running skill 'seen'.
notrexroof_1  | Traceback (most recent call last):
notrexroof_1  |   File "/usr/local/lib/python3.8/site-packages/opsdroid/core.py", line 427, in run_skill
notrexroof_1  |     return await skill(self, config, event)
notrexroof_1  |   File "/root/.local/share/opsdroid/opsdroid-modules/skill/seen/__init__.py", line 16, in last_seen
notrexroof_1  |     await message.respond("I last saw {} {}".format(name, human(seen[name], precision=1)))
notrexroof_1  |   File "/root/.local/share/opsdroid/site-packages/ago.py", line 55, in human
notrexroof_1  |     delta = get_delta_from_subject(subject)
notrexroof_1  |   File "/root/.local/share/opsdroid/site-packages/ago.py", line 16, in get_delta_from_subject
notrexroof_1  |     subject = float(subject)
notrexroof_1  | TypeError: float() argument must be a string or a number, not 'dict'
```

I know this hasn't been touched in a few years, but I'm wondering if there is a general issue with serializing objects into a redis database within opsdroid.




Discussion:
Thanks for raising this.

As you say these examples are a little old now so have perhaps gotten out of date.

From reading that error message I'm not sure this is a problem with redis but more an issue with what is being stored in redis. The `seen[name]` value seems to be coming back as a dictionary. 
thanks for following up!  

I will note that this skill works as expected if you use sqlite instead of redis.

this is what the key looks like in redis:


```
127.0.0.1:6379> get seen
"{\"null\": {\"__class__\": \"datetime\", \"year\": 2020, \"month\": 11, \"day\": 19, \"hour\": 16, \"minute\": 17, \"second\": 41, \"microsecond\": 118770}, \"notrexroof\": {\"__class__\": \"datetime\", \"year\": 2020, \"month\": 11, \"day\": 19, \"hour\": 16, \"minute\": 17, \"second\": 41, \"microsecond\": 466016}, \"rexroof\": {\"__class__\": \"datetime\", \"year\": 2020, \"month\": 11, \"day\": 19, \"hour\": 16, \"minute\": 18, \"second\": 31, \"microsecond\": 277084}, \"commanderroot\": {\"__class__\": \"datetime\", \"year\": 2020, \"month\": 11, \"day\": 19, \"hour\": 13, \"minute\": 16, \"second\": 28, \"microsecond\": 59796}, \"rubberslayer\": {\"__class__\": \"datetime\", \"year\": 2020, \"month\": 11, \"day\": 19, \"hour\": 13, \"minute\": 11, \"second\": 35, \"microsecond\": 518734}, \"crazyic\": {\"__class__\": \"datetime\", \"year\": 2020, \"month\": 11, \"day\": 19, \"hour\": 16, \"minute\": 18, \"second\": 34, \"microsecond\": 9786}, \"saddestkitty\": {\"__class__\": \"datetime\", \"year\": 2020, \"month\": 11, \"day\": 19, \"hour\": 13, \"minute\": 27, \"second\": 56, \"microsecond\": 623723}, \"pmash2\": {\"__class__\": \"datetime\", \"year\": 2020, \"month\": 11, \"day\": 19, \"hour\": 13, \"minute\": 48, \"second\": 5, \"microsecond\": 643626}, \"thiccur\": {\"__class__\": \"datetime\", \"year\": 2020, \"month\": 11, \"day\": 19, \"hour\": 13, \"minute\": 35, \"second\": 2, \"microsecond\": 931169}, \"lurxx\": {\"__class__\": \"datetime\", \"year\": 2020, \"month\": 11, \"day\": 19, \"hour\": 13, \"minute\": 38, \"second\": 32, \"microsecond\": 572882}, \"ildelara\": {\"__class__\": \"datetime\", \"year\": 2020, \"month\": 11, \"day\": 19, \"hour\": 13, \"minute\": 41, \"second\": 47, \"microsecond\": 789482}}"
127.0.0.1:6379>

```

> I will note that this skill works as expected if you use sqlite instead of redis.

Oh interesting! Both database modules serialise to JSON and back again.

I don't have time to look at this right now. But I'll move this over to the main opsdroid repo and hopefully someone can take a look.

Resolving patch:
diff --git a/opsdroid/database/redis/__init__.py b/opsdroid/database/redis/__init__.py
--- a/opsdroid/database/redis/__init__.py
+++ b/opsdroid/database/redis/__init__.py
@@ -94,7 +94,7 @@ async def get(self, key):
             data = await self.client.execute("GET", key)
 
             if data:
-                return json.loads(data, encoding=JSONDecoder)
+                return json.loads(data, object_hook=JSONDecoder())
 
             return None
 


Test patch: