cunla / fakeredis-py

Implementation of Redis in python without having a Redis server running. Fully compatible with using redis-py.
https://fakeredis.moransoftware.ca/
BSD 3-Clause "New" or "Revised" License
298 stars 48 forks source link

fix: FakeRedisMixin.from_url() return type is really Self. #305

Closed ben-xo closed 6 months ago

ben-xo commented 6 months ago

This fixes issues when you have strongly typed client code using that method.

An example would be something like

REDIS_ACTION_STORE_CLIENT: FakeRedis | RedisCluster | None = None

def get_redis_client() -> FakeRedis | RedisCluster:
    if REDIS_ACTION_STORE_CLIENT is None:
        redis_class: type[FakeRedis | RedisCluster] = (
            FakeRedis
            if getattr(settings, "REDIS_TEST_BACKEND", False)
            else RedisCluster
        )
        REDIS_ACTION_STORE_CLIENT = redis_class.from_url(
            url=settings.REDIS_ACTION_STORE_URL, encoding="utf-8", decode_responses=True
        )

    return REDIS_ACTION_STORE_CLIENT

Without this patch, mypy complains that an object of type FakeRedisMixin cannot be assigned to a variable of type FakeRedis | RedisCluster, even though the class we called it on is of type FakeRedis and the returned object will also be a FakeRedis.

client code which explicitly types for FakeRedisMixin should be unaffected.

Tested locally and passes fine with poetry run mypy fakeredis/_server.py on both python 3.7 and 3.11. (a full mypy run isn't currently clean, so i limited my test just to this file).

Additionally, also fixed…

_server.py:142: error: Incompatible default for argument "lua_modules" (default has type "None", argument has type "Set[str]")  [assignment]
_server.py:142: note: PEP 484 prohibits implicit Optional. Accordingly, mypy has changed its default to no_implicit_optional=True
_server.py:142: note: Use https://github.com/hauntsaninja/no_implicit_optional to automatically upgrade your codebase

… in this file. That change seems to be needed in other files too, but I figured that was out of scope.