Open
Description
Describe the bug
Trying to assign None to a field that has null=True
gives a type error.
To Reproduce
import tortoise
from tortoise import fields
class Test(tortoise.Model):
id = fields.IntField(pk=True)
name = fields.CharField(max_length=255, null=True)
a = Test(name="test")
a.name = None
Resulting type checks:
git:(main) ✗ uv run mypy .
test.py:12: error: Incompatible types in assignment (expression has type "None", variable has type "str") [assignment]
Found 1 error in 1 file (checked 2 source files)
git:(main) ✗ uv run pyright .
/Users/zw/Development/tortoise-typebug/test.py
/Users/zw/Development/tortoise-typebug/test.py:12:3 - error: Cannot assign to attribute "name" for class "Test"
Argument of type "None" cannot be assigned to parameter "value" of type "str" in function "__set__"
"None" is not assignable to "str" (reportAttributeAccessIssue)
1 error, 0 warnings, 0 informations
Expected behavior
Should be allowed to set a field to None. It's a legal value and the type definition should reflect this.
Additional context
Happy to help out with a PR if needed. Would appreciate some pointers.
https://github.com/tortoise/tortoise-orm/blob/develop/tortoise/fields/base.py#L165
Here's the problematic code. This is causing an issue because CharField
is defined as follows:
class CharField(Field[str]):
...
I'm also including my current workaround which works but requires lot of copypaste boilerplate.
class RequiredUUIDField(fields.UUIDField):
def __set__(self, instance: "Model", value: uuid.UUID) -> None:
super().__set__(instance, value)
class NullableUUIDField(fields.UUIDField):
def __set__(self, instance: "Model", value: Optional[uuid.UUID]) -> None:
super().__set__(instance, value) # type: ignore
@overload
def UUIDField(null: Literal[False] = False, **kwargs) -> RequiredUUIDField: ...
@overload
def UUIDField(null: Literal[True], **kwargs) -> NullableUUIDField: ...
def UUIDField(null: bool = False, **kwargs):
if null:
return NullableUUIDField(null=True, **kwargs)
return RequiredUUIDField(**kwargs)