mirror of
https://github.com/davidhalter/django-stubs.git
synced 2025-12-07 20:54:29 +08:00
Specific return types for values and values list (#53)
* Instead of using Literal types, overload QuerySet.values_list in the plugin. Fixes #43. - Add a couple of extra type checks that Django makes: 1) 'flat' and 'named' can't be used together. 2) 'flat' is not valid when values_list is called with more than one field. * Determine better row types for values_list/values based on fields specified. - In the case of values_list, we use a Row type with either a single primitive, Tuple, or NamedTuple. - In the case of values, we use a TypedDict. - In both cases, Any is used as a fallback for individual fields if those fields cannot be resolved. A couple other fixes I made along the way: - Don't create reverse relation for ForeignKeys with related_name='+' - Don't skip creating other related managers in AddRelatedManagers if a dynamic value is encountered for related_name parameter, or if the type cannot be determined. * Fix for TypedDict so that they are considered anonymous. * Clean up some comments. * Implement making TypedDict anonymous in a way that doesn't crash sometimes. * Fix flake8 errors. * Remove even uglier hack about making TypedDict anonymous. * Address review comments. Write a few better comments inside tests. * Fix crash when running with mypyc ("interpreted classes cannot inherit from compiled") due to the way I extended TypedDictType. - Implemented the hack in another way that works on mypyc. - Added a couple extra tests of accessing 'id' / 'pk' via values_list. * Fix flake8 errors. * Support annotation expressions (use type Any) for TypedDicts row types returned by values_list. - Bonus points: handle values_list gracefully (use type Any) where Tuples are returned where some of the fields arguments are not string literals.
This commit is contained in:
committed by
Maxim Kurnikov
parent
5c6be7ad12
commit
5b455b729a
@@ -1,10 +1,10 @@
|
||||
from typing import Optional, cast
|
||||
|
||||
from mypy.checker import TypeChecker
|
||||
from mypy.nodes import ListExpr, NameExpr, StrExpr, TupleExpr, TypeInfo, Var
|
||||
from mypy.nodes import ListExpr, NameExpr, StrExpr, TupleExpr, TypeInfo
|
||||
from mypy.plugin import FunctionContext
|
||||
from mypy.types import (
|
||||
AnyType, CallableType, Instance, TupleType, Type, TypeOfAny, UnionType,
|
||||
AnyType, CallableType, Instance, TupleType, Type, UnionType,
|
||||
)
|
||||
|
||||
from mypy_django_plugin import helpers
|
||||
@@ -88,23 +88,13 @@ def fill_descriptor_types_for_related_field(ctx: FunctionContext) -> Type:
|
||||
return helpers.reparametrize_instance(ctx.default_return_type, new_args=args)
|
||||
|
||||
|
||||
def get_private_descriptor_type(type_info: TypeInfo, private_field_name: str, is_nullable: bool) -> Type:
|
||||
node = type_info.get(private_field_name).node
|
||||
if isinstance(node, Var):
|
||||
descriptor_type = node.type
|
||||
if is_nullable:
|
||||
descriptor_type = helpers.make_optional(descriptor_type)
|
||||
return descriptor_type
|
||||
return AnyType(TypeOfAny.unannotated)
|
||||
|
||||
|
||||
def set_descriptor_types_for_field(ctx: FunctionContext) -> Instance:
|
||||
default_return_type = cast(Instance, ctx.default_return_type)
|
||||
is_nullable = helpers.parse_bool(helpers.get_argument_by_name(ctx, 'null'))
|
||||
set_type = get_private_descriptor_type(default_return_type.type, '_pyi_private_set_type',
|
||||
is_nullable=is_nullable)
|
||||
get_type = get_private_descriptor_type(default_return_type.type, '_pyi_private_get_type',
|
||||
is_nullable=is_nullable)
|
||||
set_type = helpers.get_private_descriptor_type(default_return_type.type, '_pyi_private_set_type',
|
||||
is_nullable=is_nullable)
|
||||
get_type = helpers.get_private_descriptor_type(default_return_type.type, '_pyi_private_get_type',
|
||||
is_nullable=is_nullable)
|
||||
return helpers.reparametrize_instance(default_return_type, [set_type, get_type])
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user