Search code examples
pythonoverloadingmypy

Type overload makes return value unsubscriptable per Pylint


I have an overloaded method with different return types per below;

    @ overload
    def __get_db_key(self, key_suffix: str, decode_result: str) -> str: ...
    @ overload
    def __get_db_key(self, key_suffix: str, decode_result: None) -> bytes: ...
    @ overload
    def __get_db_key(self, key_suffix: str) -> bytes: ...

    def __get_db_key(self, key_suffix: str, decode_result: str | None = None) -> str | bytes:
        """return a value directly from the db by key"""
        max_tries = 3
        key = self._key_prefix + key_suffix
        for _ in range(max_tries):
            try:
                result: bytes = self._db.get(key.encode('utf8'))
                return result if decode_result is None else result.decode(decode_result)
            except plyvel.CorruptionError:
                print(traceback.format_exc())
                self.__repair()
                continue
        sys.exit(1)

I'm calling this method as below;

        db = json.loads(self.__get_db_key('s', 'utf8')[1:])
        for key in db:
            self._namespace_keys.append(str(key[0]))
        if len(self._namespace_keys) == 0:
            self._namespace_keys.append('1')
        for key in self._namespace_keys:
            result = self.__get_db_key(f"-{key}")
            if result is not None:
                if any(x in result[:1] for x in [b'\x00', b'\x01']):
                    self._collections[key] = self.__unserialize(result)

When run, this code all works fine, however PyLint is telling me that self.__get_db_key('s', 'utf8')[1:] and result[:1] are unsubscriptable even though the method can only return str or bytes, so the return value should be "slice-able".

If I remove the overloaded methods from __get_db_key the PyLint error goes away but I instead get the below MyPy error:

Unsupported operand types for in ("bytes" and "Union[str, bytes]")
Argument 1 to "__unserialize" of "LDBService" has incompatible type "Union[str, bytes]"; expected "bytes"

These two errors are specified for the two below lines of code;

                if any(x in result[:1] for x in [b'\x00', b'\x01']):
                    self._collections[key] = self.__unserialize(result)

Thanks.


Solution

  • I have no idea why this was required but it got rid of the PyLint errors..

            keys = str(self.__get_db_key('s', 'utf8'))[1:]
            for key in json.loads(keys):
                self._namespace_keys.append(str(key[0]))
            if len(self._namespace_keys) == 0:
                self._namespace_keys.append('1')
            for key in self._namespace_keys:
                result = bytes(self.__get_db_key(f"-{key}"))
                if result is not None:
                    if any(x in result[:1] for x in [b'\x00', b'\x01']):
                        self._collections[key] = self.__unserialize(result)
    

    I simply wrapped the calls in str/bytes as required before attempting to slice... even though the method was already returning those types.