dropbox / sqlalchemy-stubs

Mypy plugin and stubs for SQLAlchemy
Apache License 2.0
572 stars 102 forks source link

TypeDecorator.process_bind_param only possible return value is Optional[str], but this doesn't work for binary types #214

Open synic opened 3 years ago

synic commented 3 years ago

Probably doing something wrong here, but I can't figure out how to make this work:

class EncryptedType(TypeDecorator):
    impl = LargeBinary

    def __init__(self, engine: EncryptionEngine, **kwargs: Any) -> None:
        super().__init__(**kwargs)
        self.engine = engine

    def process_bind_param(self, value: Optional[str], dialect: Dialect) -> Optional[str]:
        if value is None:
            return None
        return self.engine.encrypt(value).decode()  # convert to string, but I'd rather not

    def process_result_value(self, value: Optional[bytes], dialect: Dialect) -> Optional[str]:
        if value is None:
            return None
        return self.engine.decrypt(value)

Trying to insert data into a column results in an error like this:

StatementError: (builtins.TypeError) memoryview: a bytes-like object is required, not 'str'

Simply returning self.engine.encrypt(value) without the .decode() to convert to a string works, but then mypy complains that Return type "Optional[bytes]" of "process_bind_param" incompatible with return type "Optional[str]" in supertype "TypeDecorator"

huonw commented 3 years ago

I think this is a duplicate of #205/#206: it's just a mistake in the type annotations, so giving the functions the correct return type (and using # type: ignore on those lines) is what we're doing, and it works.