Skip to content

db_default narrows too much #3363

Description

@UnknownPlatypus

mypy primer diff look mostly great, just noticed a pre-existing issue with db_default

class AbstractMessage(models.Model):
    class MessageType(models.IntegerChoices):
        NORMAL = 1
        RESOLVE_TOPIC_NOTIFICATION = 2

    type = models.PositiveSmallIntegerField(
        choices=MessageType.choices,
        default=MessageType.NORMAL,
        # Note: db_default is a new feature in Django 5.0, so we don't use
        # it across the codebase yet. It's useful here to simplify the
        # associated database migration, so we're making use of it.
        db_default=MessageType.NORMAL,
    )
- zerver/actions/message_send.py:1872: error: Incompatible types in assignment (expression has type "int", variable has type "MessageType")  [assignment]
+ zerver/actions/message_send.py:1872: error: No overload variant of "__set__" of "Field" matches argument types "Message", "int"  [call-overload]
+ zerver/actions/message_send.py:1872: note: Possible overload variants:
+ zerver/actions/message_send.py:1872: note:     def __set__(self, instance: Any, value: MessageType | Combinable) -> None

The problem is that because _ST is contravariant and part of the db_default type, the instantiation narrow _ST=MessageType which then reject int while it was a valid choice before

Not sure how to handle this but I don't think it should be a blocker for this, this is a preexisting issue I believe.
I can open a new issue for it, maybe just duplicating the type union we use in _ST default and using it in db_default would be ok ?

Similarly, this causes issue now:

  class M(models.Model):                                                                                                                                        
      a = models.JSONField(default=dict, db_default={})  # error: Need type annotation for "a" 

mypy tries to bind _ST_JSON from the empty-dict literal in the union, fails to commit to a type, and the field is left unparameterized. I've changed this one to Any since we don't loose type strictness versus before but doing so in other places would be a regression.

Originally posted by @UnknownPlatypus in #3317 (comment)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions