Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Data type for Float column should be float, not Decimal #178

Open
KKawamura1 opened this issue Oct 15, 2020 · 5 comments · May be fixed by #180
Open

Data type for Float column should be float, not Decimal #178

KKawamura1 opened this issue Oct 15, 2020 · 5 comments · May be fixed by #180

Comments

@KKawamura1
Copy link
Contributor

Related to: #131

About

#132 fixed #131, a bug that sqlalchemy.Numeric was treated as float, not decimal.Decimal.
But it may introduce a new bug, that sqlalchemy.Float is also treated as decimal.Decimal, not float.

To reproduce

Assigning a float value to sqlalchemy.Float is enough to reproduce this bug.

Below is a sample code to reproduce:

from decimal import Decimal
from sqlalchemy import Column, Float, Numeric, Integer
from sqlalchemy.ext.declarative import declarative_base


Base = declarative_base()


class Numbers(Base):
    __tablename__ = "numbers"
    id_ = Column(Integer, primary_key=True)

    c_numeric = Column(Numeric, nullable=False)
    c_numeric_as_decimal = Column(Numeric(asdecimal=True), nullable=False)
    c_numeric_as_float = Column(Numeric(asdecimal=False), nullable=False)
    c_float = Column(Float, nullable=False)


def in_float() -> None:
    number = 1.0
    numbers = Numbers(c_numeric=number, c_numeric_as_decimal=number, c_numeric_as_float=number, c_float=number)
    print(type(numbers.c_numeric), type(numbers.c_numeric_as_decimal), type(numbers.c_numeric_as_float), type(numbers.c_float))

def in_decimal() -> None:
    number = Decimal(1.0)
    numbers = Numbers(c_numeric=number, c_numeric_as_decimal=number, c_numeric_as_float=number, c_float=number)
    print(type(numbers.c_numeric), type(numbers.c_numeric_as_decimal), type(numbers.c_numeric_as_float), type(numbers.c_float))

in_float()
in_decimal()
$ mypy foo.py
foo.py:21: error: Incompatible type for "c_numeric" of "Numbers" (got "float", expected "Decimal")
foo.py:21: error: Incompatible type for "c_numeric_as_decimal" of "Numbers" (got "float", expected "Decimal")
foo.py:21: error: Incompatible type for "c_numeric_as_float" of "Numbers" (got "float", expected "Decimal")
foo.py:21: error: Incompatible type for "c_float" of "Numbers" (got "float", expected "Decimal")
Found 4 errors in 1 file (checked 1 source file)

Expected result

$ mypy foo.py
foo.py:21: error: Incompatible type for "c_numeric" of "Numbers" (got "float", expected "Decimal")
foo.py:21: error: Incompatible type for "c_numeric_as_decimal" of "Numbers" (got "float", expected "Decimal")
foo.py:26: error: Incompatible type for "c_numeric_as_float" of "Numbers" (got "Decimal", expected "float")  # this one
foo.py:26: error: Incompatible type for "c_float" of "Numbers" (got "Decimal", expected "float")  # this one
Found 4 errors in 1 file (checked 1 source file)

Environment

$ (cd sqlalchemy-stubs && git rev-parse HEAD)
55470ceab8149db983411d5c094c9fe16343c58b
$ python -c "import sqlalchemy; print(sqlalchemy.__version__)"
1.3.20
$ python -V
Python 3.8.2
$ mypy -V
mypy 0.790
@shawnwall
Copy link
Contributor

bumping this case, as this is also causing problems for me. thx @KKawamura1

@jroberts07
Copy link

Also experiencing this

@wlcx
Copy link

wlcx commented Feb 16, 2021

A workaround to avoid resorting to any # type: ignores is to use typing.cast:

def func_that_uses_the_column() -> float:
    foo = db.query(Foo).first()
    return cast(float, foo.float_column)

https://mypy.readthedocs.io/en/stable/casts.html#casts-and-type-assertions

@deanle17
Copy link

deanle17 commented Apr 9, 2021

@wlcx I think the main problem is assigning float value to a Float column. In order to do that, I have to Decimal(my_float_value) to make mypy happy. But it also leads to problem that I'm injecting to database a Decimal value which is defined as Float

from sqlalchemy import Floatclass Coordinate(Base):
    __tablename__ = 'coordinates'
    
    latitude = Column(Float) #sqlalchemy-stub infers this column as Decimal
    longitude = Column(Float)
​
	
coord = Coordinate(
    latitude=50.5, #mypy complains that this value need to be Decimal
    longitude=60.5,
)
​
from decimal import Decimal

coord_2= Coordinate(
    latitude=Decimal(50.5), #works fine
    longitude=Decimal(60.5),
)

@mthuurne
Copy link

This problem also occurs when using only Float columns:

from sqlalchemy import Column, Float, Integer
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()


class MyModel(Base):
    __tablename__ = "my_model"

    id = Column(Integer, primary_key=True)
    value = Column(Float, nullable=False)


def f(data: MyModel) -> None:
    reveal_type(data.value)

Expected output:

testcase.py:15: note: Revealed type is "builtins.float*"

Actual output:

testcase.py:15: note: Revealed type is "decimal.Decimal*"

I'm currently using the following workaround:

from typing import cast

from sqlalchemy import Float as Float_org
from sqlalchemy.sql.type_api import TypeEngine

Float = cast(type[TypeEngine[float]], Float_org)

But it would be nice if this could be fixed in the stubs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants