Skip to content

support for psycopg 3 Range types in django.contrib.postgres.fields.ranges #2687

@jorenham

Description

@jorenham

In django.contrib.postgres.fields.ranges the Range types are imported from psycopg2, which has been superseded by psycopg 3:

from psycopg2.extras import DateRange, DateTimeTZRange, NumericRange, Range # type: ignore [import-untyped]

the types-psycopg2 typeshed stubs package could help with the # type: ignore, btw

The range fields use the psycopg2 Range type as upper bound for the generic type parameters of the range fields:

_RangeT = TypeVar("_RangeT", bound=Range[Any])
class RangeField(models.Field[Any, _RangeT]):

Ok, so what's the problem?

So I'm not able to use the psycopg 3 psycopg.types.range.Range as type argument here. Note that _RangeT has no default, so I'm required to pass a type argument here.

Working around it

The least invalid workaround would be to pass Any as type argument. But if you don't mind getting your hands dirty, you could also ignore the upper bound, and throw some of those # type: ignore[misc] and/or # pyright: ignore[reportVerboseDescriptionOfAnErrorThatCouldAlsoBeWrittenInOneWOrd] onto it, and it'll probably work regardless.

And I hate to say it, so please forgive me for putting it in such strong terms, but I consider both workarounds to be suboptimal.

Why it's impossible to solve, and some possible solutions.

That's, well, not possible... Or at least, not if you want to support both psycopg2 and psycopg 3. Because try: import ... isn't a thing in stubs, unfortunately.

However, it looks like both Range types from v2 and v3 are structurally equivalent. So another option would be to copy-paste the typeshed code of Range, swap the Generic for a Protocol, and voilà.

Another option would be to just get rid of the _RangeT upper bound altogether.

Covariance, maybe?

Since _RangeT only annotates range_type: type[_RangeT], and assuming that it's intended as a read-only attribute, perhaps it makes sense to slap a _co on the _RangeT?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions