Repository: redis/redis-py
Pull request: Enable floating parameters in SET (ex and px)
### Pull Request check-list

_Please make sure to review and check all of these items:_

- [x] Does `$ tox` pass with this change (including linting)?
- [x] Do the CI tests pass with this change (enable it first in your forked repo and wait for the github action build to finish)?
- [x] Is the new or changed code fully tested?
- [x] Is a documentation update included (if this change modifies existing APIs, or introduces new ones)?

_NOTE: these things are not required to open a PR and can be done
afterwards / while the PR is open._

### Description of change

Closes #1576 
Now it is possible to use floating numbers without getting an error.
One thing I have in mind - If the floating number is not rounded, i.e., 10.5, the command will use the integer 10.


Problem statement:
error in set when ex is a float is confusing
**Version**: redis-py 3.5.3

**Platform**: Python 3.7.3 (default, Jan 22 2021, 20:04:44) [GCC 8.3.0] on linux

**Description**:
```py
>>> import redis
>>> r = redis.Redis(host='localhost', port=6379, db=0)
>>> r.set('foo', 'bar', ex=10.0)
Traceback (most recent call last):
  File "/redis/client.py", line 1801, in set
    return self.execute_command('SET', *pieces)
  File "/redis/client.py", line 901, in execute_command
    return self.parse_response(conn, command_name, **options)
  File "/redis/client.py", line 915, in parse_response
    response = connection.read_response()
  File "/redis/connection.py", line 756, in read_response
    raise response
redis.exceptions.ResponseError: value is not an integer or out of range
```
This exception is confusing, because it doesn't specify which value is supposed to be an integer. There is a parameter to set called "value", but that's not what caused the exception. It would be better to validate that ex is an integer and raise something like `TypeError: ex must be int or timedelta, not "float"`.

Hints from issue discussion:

Commit message: Enable floating params in SET (ex and px)

Patch to review:
diff --git a/redis/commands.py b/redis/commands.py
index 44a77354aa..fdc4441926 100644
--- a/redis/commands.py
+++ b/redis/commands.py
@@ -1173,13 +1173,21 @@ def set(self, name, value,
         if ex is not None:
             pieces.append('EX')
             if isinstance(ex, datetime.timedelta):
-                ex = int(ex.total_seconds())
-            pieces.append(ex)
+                ex = ex.total_seconds()
+            try:
+                ex = int(ex)
+                pieces.append(ex)
+            except TypeError:
+                pass
         if px is not None:
             pieces.append('PX')
             if isinstance(px, datetime.timedelta):
-                px = int(px.total_seconds() * 1000)
-            pieces.append(px)
+                px = px.total_seconds() * 1000
+            try:
+                px = int(px)
+                pieces.append(px)
+            except TypeError:
+                pass
         if exat is not None:
             pieces.append('EXAT')
             if isinstance(exat, datetime.datetime):
diff --git a/tests/test_commands.py b/tests/test_commands.py
index ceb12361b7..23374187cb 100644
--- a/tests/test_commands.py
+++ b/tests/test_commands.py
@@ -1116,6 +1116,8 @@ def test_set_px_timedelta(self, r):
     def test_set_ex(self, r):
         assert r.set('a', '1', ex=10)
         assert 0 < r.ttl('a') <= 10
+        assert r.set('a', '1', ex=10.0)
+        assert 0 < r.ttl('a') <= 10
 
     @skip_if_server_version_lt('2.6.0')
     def test_set_ex_timedelta(self, r):


Code review comments:
diff_hunk: @@ -1173,13 +1173,21 @@ def set(self, name, value,
         if ex is not None:
             pieces.append('EX')
             if isinstance(ex, datetime.timedelta):
-                ex = int(ex.total_seconds())
-            pieces.append(ex)
+                ex = ex.total_seconds()
+            try:
path: redis/commands.py
text: @user1:
What about:

if not isinstance(ex, int):
    raise DataError("something something").

Repeat