Skip to content
Open
14 changes: 14 additions & 0 deletions stubs/peewee/@tests/stubtest_allowlist.txt
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,20 @@ peewee.SelectBase.peek
peewee.SelectBase.scalar
peewee.SelectBase.scalars

# Descriptor methods exist on FieldAccessor at runtime, but are declared on the
# generic Field classes in the stub so that `instance.field` resolves to the
# field's Python value and `Model.field` resolves to the field (for queries).
peewee.Field.__get__
peewee.Field.__set__
# BigBitField overrides __get__ to yield a BigBitFieldData wrapper, not bytes.
peewee.BigBitField.__get__
peewee.Field.__init__
# These fields take named constructor args, carried by their __new__ overloads.
peewee.CharField.__init__
peewee.ForeignKeyField.__init__
peewee.DecimalField.__init__
peewee.IdentityField.__init__

# Ignore missing playhouse modules and names we don't currently provide
playhouse\.\w+?
playhouse.flask_utils.PaginatedQuery
Expand Down
56 changes: 56 additions & 0 deletions stubs/peewee/@tests/test_cases/check_fields.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
from __future__ import annotations

from typing_extensions import assert_type

from peewee import BigBitField, BigBitFieldData, CharField, ForeignKeyField, IntegerField, Model


class User(Model):
username = CharField()
age = IntegerField()
nickname = CharField(null=True)


class Tweet(Model):
user = ForeignKeyField(User)
author = ForeignKeyField(User, null=True)


class Event(Model):
flags = BigBitField()


# A field is a descriptor that resolves differently depending on whether it is
# accessed on the model class or on an instance. `Model.field` is the Field
# object itself (used to build queries), while `instance.field` is the stored
# Python value.
assert_type(User.username, CharField[str])
assert_type(User().username, str)

assert_type(User.age, IntegerField[int])
assert_type(User().age, int)

# `null=True` allows the value to include None, both in the field's own
# parameterization and in the value produced on attribute access.
assert_type(User.nickname, CharField[str | None])
assert_type(User().nickname, str | None)

# Foreign keys resolve to the related model instance, or None when nullable.
assert_type(Tweet.user, ForeignKeyField[User])
assert_type(Tweet().user, User)
assert_type(Tweet().author, User | None)

# BigBitField is a special case: the instance descriptor yields a
# BigBitFieldData wrapper rather than the underlying bytes.
assert_type(Event.flags, BigBitField)
assert_type(Event().flags, BigBitFieldData)

# __set__ accepts the field's value type...
user = User()
user.username = "guido"
user.age = 42
user.nickname = None # nullable field accepts None

# ...and rejects incompatible values.
user.age = "not an int" # type: ignore
user.username = None # type: ignore # non-null field rejects None
2 changes: 1 addition & 1 deletion stubs/peewee/METADATA.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
version = "4.0.5"
version = "4.0.8"
upstream-repository = "https://github.com/coleifer/peewee"
# We're not providing stubs for all playhouse modules right now
# https://github.com/python/typeshed/pull/11731#issuecomment-2065729058
Expand Down
Loading
Loading