[ty] Improve rendering of default values for function args (#22010)

## Summary

We're actually quite good at computing this but the main issue is just
that we compute it at the type-level and so wrap it in `Literal[...]`.
So just special-case the rendering of these to omit `Literal[...]` and
fallback to `...` in cases where the thing we'll show is probably
useless (i.e. `x: str = str`).

Fixes https://github.com/astral-sh/ty/issues/1882
This commit is contained in:
Aria Desires 2025-12-16 13:39:19 -05:00 committed by GitHub
parent 2214a46139
commit ad3de4e488
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
20 changed files with 93 additions and 71 deletions

View File

@ -3212,7 +3212,7 @@ quux.<CURSOR>
assert_snapshot!( assert_snapshot!(
builder.skip_keywords().skip_builtins().type_signatures().build().snapshot(), @r" builder.skip_keywords().skip_builtins().type_signatures().build().snapshot(), @r"
count :: bound method Quux.count(value: Any, /) -> int count :: bound method Quux.count(value: Any, /) -> int
index :: bound method Quux.index(value: Any, start: SupportsIndex = Literal[0], stop: SupportsIndex = int, /) -> int index :: bound method Quux.index(value: Any, start: SupportsIndex = 0, stop: SupportsIndex = ..., /) -> int
x :: int x :: int
y :: str y :: str
__add__ :: Overload[(value: tuple[int | str, ...], /) -> tuple[int | str, ...], (value: tuple[_T@__add__, ...], /) -> tuple[int | str | _T@__add__, ...]] __add__ :: Overload[(value: tuple[int | str, ...], /) -> tuple[int | str, ...], (value: tuple[_T@__add__, ...], /) -> tuple[int | str | _T@__add__, ...]]

View File

@ -57,7 +57,7 @@ We can access attributes on objects of all kinds:
import sys import sys
reveal_type(inspect.getattr_static(sys, "dont_write_bytecode")) # revealed: bool reveal_type(inspect.getattr_static(sys, "dont_write_bytecode")) # revealed: bool
# revealed: def getattr_static(obj: object, attr: str, default: Any | None = EllipsisType) -> Any # revealed: def getattr_static(obj: object, attr: str, default: Any | None = ...) -> Any
reveal_type(inspect.getattr_static(inspect, "getattr_static")) reveal_type(inspect.getattr_static(inspect, "getattr_static"))
reveal_type(inspect.getattr_static(1, "real")) # revealed: property reveal_type(inspect.getattr_static(1, "real")) # revealed: property
@ -144,7 +144,7 @@ from typing import Any
def _(a: Any, tuple_of_any: tuple[Any]): def _(a: Any, tuple_of_any: tuple[Any]):
reveal_type(inspect.getattr_static(a, "x", "default")) # revealed: Any | Literal["default"] reveal_type(inspect.getattr_static(a, "x", "default")) # revealed: Any | Literal["default"]
# revealed: def index(self, value: Any, start: SupportsIndex = Literal[0], stop: SupportsIndex = int, /) -> int # revealed: def index(self, value: Any, start: SupportsIndex = 0, stop: SupportsIndex = ..., /) -> int
reveal_type(inspect.getattr_static(tuple_of_any, "index", "default")) reveal_type(inspect.getattr_static(tuple_of_any, "index", "default"))
``` ```

View File

@ -598,9 +598,9 @@ from typing_extensions import Self
reveal_type(object.__new__) # revealed: def __new__(cls) -> Self@__new__ reveal_type(object.__new__) # revealed: def __new__(cls) -> Self@__new__
reveal_type(object().__new__) # revealed: def __new__(cls) -> Self@__new__ reveal_type(object().__new__) # revealed: def __new__(cls) -> Self@__new__
# revealed: Overload[(cls, x: str | Buffer | SupportsInt | SupportsIndex | SupportsTrunc = Literal[0], /) -> Self@__new__, (cls, x: str | bytes | bytearray, /, base: SupportsIndex) -> Self@__new__] # revealed: Overload[(cls, x: str | Buffer | SupportsInt | SupportsIndex | SupportsTrunc = 0, /) -> Self@__new__, (cls, x: str | bytes | bytearray, /, base: SupportsIndex) -> Self@__new__]
reveal_type(int.__new__) reveal_type(int.__new__)
# revealed: Overload[(cls, x: str | Buffer | SupportsInt | SupportsIndex | SupportsTrunc = Literal[0], /) -> Self@__new__, (cls, x: str | bytes | bytearray, /, base: SupportsIndex) -> Self@__new__] # revealed: Overload[(cls, x: str | Buffer | SupportsInt | SupportsIndex | SupportsTrunc = 0, /) -> Self@__new__, (cls, x: str | bytes | bytearray, /, base: SupportsIndex) -> Self@__new__]
reveal_type((42).__new__) reveal_type((42).__new__)
class X: class X:

View File

@ -36,7 +36,7 @@ class Point:
x: int x: int
y: int y: int
reveal_type(Point.__replace__) # revealed: (self: Point, *, x: int = int, y: int = int) -> Point reveal_type(Point.__replace__) # revealed: (self: Point, *, x: int = ..., y: int = ...) -> Point
``` ```
The `__replace__` method can either be called directly or through the `replace` function: The `__replace__` method can either be called directly or through the `replace` function:

View File

@ -87,25 +87,25 @@ class C:
def inner_a(positional=self.a): def inner_a(positional=self.a):
return return
self.a = inner_a self.a = inner_a
# revealed: def inner_a(positional=Unknown | (def inner_a(positional=Unknown) -> Unknown)) -> Unknown # revealed: def inner_a(positional=...) -> Unknown
reveal_type(inner_a) reveal_type(inner_a)
def inner_b(*, kw_only=self.b): def inner_b(*, kw_only=self.b):
return return
self.b = inner_b self.b = inner_b
# revealed: def inner_b(*, kw_only=Unknown | (def inner_b(*, kw_only=Unknown) -> Unknown)) -> Unknown # revealed: def inner_b(*, kw_only=...) -> Unknown
reveal_type(inner_b) reveal_type(inner_b)
def inner_c(positional_only=self.c, /): def inner_c(positional_only=self.c, /):
return return
self.c = inner_c self.c = inner_c
# revealed: def inner_c(positional_only=Unknown | (def inner_c(positional_only=Unknown, /) -> Unknown), /) -> Unknown # revealed: def inner_c(positional_only=..., /) -> Unknown
reveal_type(inner_c) reveal_type(inner_c)
def inner_d(*, kw_only=self.d): def inner_d(*, kw_only=self.d):
return return
self.d = inner_d self.d = inner_d
# revealed: def inner_d(*, kw_only=Unknown | (def inner_d(*, kw_only=Unknown) -> Unknown)) -> Unknown # revealed: def inner_d(*, kw_only=...) -> Unknown
reveal_type(inner_d) reveal_type(inner_d)
``` ```
@ -114,7 +114,7 @@ We do, however, still check assignability of the default value to the parameter
```py ```py
class D: class D:
def f(self: "D"): def f(self: "D"):
# error: [invalid-parameter-default] "Default value of type `Unknown | (def inner_a(a: int = Unknown | (def inner_a(a: int = Unknown) -> Unknown)) -> Unknown)` is not assignable to annotated parameter type `int`" # error: [invalid-parameter-default] "Default value of type `Unknown | (def inner_a(a: int = ...) -> Unknown)` is not assignable to annotated parameter type `int`"
def inner_a(a: int = self.a): ... def inner_a(a: int = self.a): ...
self.a = inner_a self.a = inner_a
``` ```
@ -129,16 +129,16 @@ class C:
self.c = lambda positional_only=self.c, /: positional_only self.c = lambda positional_only=self.c, /: positional_only
self.d = lambda *, kw_only=self.d: kw_only self.d = lambda *, kw_only=self.d: kw_only
# revealed: (positional=Unknown | ((positional=Unknown) -> Unknown)) -> Unknown # revealed: (positional=...) -> Unknown
reveal_type(self.a) reveal_type(self.a)
# revealed: (*, kw_only=Unknown | ((*, kw_only=Unknown) -> Unknown)) -> Unknown # revealed: (*, kw_only=...) -> Unknown
reveal_type(self.b) reveal_type(self.b)
# revealed: (positional_only=Unknown | ((positional_only=Unknown, /) -> Unknown), /) -> Unknown # revealed: (positional_only=..., /) -> Unknown
reveal_type(self.c) reveal_type(self.c)
# revealed: (*, kw_only=Unknown | ((*, kw_only=Unknown) -> Unknown)) -> Unknown # revealed: (*, kw_only=...) -> Unknown
reveal_type(self.d) reveal_type(self.d)
``` ```

View File

@ -749,8 +749,8 @@ class Outer:
outer_a: int = outer_field(init=False) outer_a: int = outer_field(init=False)
outer_b: str = inner_field(init=False) outer_b: str = inner_field(init=False)
reveal_type(Outer.__init__) # revealed: (self: Outer, outer_b: str = Any) -> None reveal_type(Outer.__init__) # revealed: (self: Outer, outer_b: str = ...) -> None
reveal_type(Outer.Inner.__init__) # revealed: (self: Inner, inner_b: str = Any) -> None reveal_type(Outer.Inner.__init__) # revealed: (self: Inner, inner_b: str = ...) -> None
``` ```
## Overloaded dataclass-like decorators ## Overloaded dataclass-like decorators

View File

@ -69,7 +69,7 @@ class D:
y: str = "default" y: str = "default"
z: int | None = 1 + 2 z: int | None = 1 + 2
reveal_type(D.__init__) # revealed: (self: D, x: int, y: str = Literal["default"], z: int | None = Literal[3]) -> None reveal_type(D.__init__) # revealed: (self: D, x: int, y: str = "default", z: int | None = 3) -> None
``` ```
This also works if the declaration and binding are split: This also works if the declaration and binding are split:
@ -221,7 +221,7 @@ class D:
(x): int = 1 (x): int = 1
# TODO: should ideally not include a `x` parameter # TODO: should ideally not include a `x` parameter
reveal_type(D.__init__) # revealed: (self: D, x: int = Literal[1]) -> None reveal_type(D.__init__) # revealed:(self: D, x: int = 1) -> None
``` ```
## `@dataclass` calls with arguments ## `@dataclass` calls with arguments
@ -670,7 +670,7 @@ class A:
a: str = field(kw_only=False) a: str = field(kw_only=False)
b: int = 0 b: int = 0
reveal_type(A.__init__) # revealed: (self: A, a: str, *, b: int = Literal[0]) -> None reveal_type(A.__init__) # revealed:(self: A, a: str, *, b: int = 0) -> None
A("hi") A("hi")
``` ```
@ -991,7 +991,7 @@ class C:
class_variable1: ClassVar[Final[int]] = 1 class_variable1: ClassVar[Final[int]] = 1
class_variable2: ClassVar[Final[int]] = 1 class_variable2: ClassVar[Final[int]] = 1
reveal_type(C.__init__) # revealed: (self: C, instance_variable_no_default: int, instance_variable: int = Literal[1]) -> None reveal_type(C.__init__) # revealed:(self: C, instance_variable_no_default: int, instance_variable: int = 1) -> None
c = C(1) c = C(1)
# error: [invalid-assignment] "Cannot assign to final attribute `instance_variable` on type `C`" # error: [invalid-assignment] "Cannot assign to final attribute `instance_variable` on type `C`"
@ -1082,7 +1082,7 @@ class C(Base):
z: int = 10 z: int = 10
x: int = 15 x: int = 15
reveal_type(C.__init__) # revealed: (self: C, x: int = Literal[15], y: int = Literal[0], z: int = Literal[10]) -> None reveal_type(C.__init__) # revealed:(self: C, x: int = 15, y: int = 0, z: int = 10) -> None
``` ```
## Conditionally defined fields ## Conditionally defined fields
@ -1243,7 +1243,7 @@ class UppercaseString:
class C: class C:
upper: UppercaseString = UppercaseString() upper: UppercaseString = UppercaseString()
reveal_type(C.__init__) # revealed: (self: C, upper: str = str) -> None reveal_type(C.__init__) # revealed: (self: C, upper: str = ...) -> None
c = C("abc") c = C("abc")
reveal_type(c.upper) # revealed: str reveal_type(c.upper) # revealed: str
@ -1289,7 +1289,7 @@ class ConvertToLength:
class C: class C:
converter: ConvertToLength = ConvertToLength() converter: ConvertToLength = ConvertToLength()
reveal_type(C.__init__) # revealed: (self: C, converter: str = Literal[""]) -> None reveal_type(C.__init__) # revealed: (self: C, converter: str = "") -> None
c = C("abc") c = C("abc")
reveal_type(c.converter) # revealed: int reveal_type(c.converter) # revealed: int
@ -1328,7 +1328,7 @@ class AcceptsStrAndInt:
class C: class C:
field: AcceptsStrAndInt = AcceptsStrAndInt() field: AcceptsStrAndInt = AcceptsStrAndInt()
reveal_type(C.__init__) # revealed: (self: C, field: str | int = int) -> None reveal_type(C.__init__) # revealed: (self: C, field: str | int = ...) -> None
``` ```
## `dataclasses.field` ## `dataclasses.field`

View File

@ -11,7 +11,7 @@ class Member:
role: str = field(default="user") role: str = field(default="user")
tag: str | None = field(default=None, init=False) tag: str | None = field(default=None, init=False)
# revealed: (self: Member, name: str, role: str = Literal["user"]) -> None # revealed: (self: Member, name: str, role: str = "user") -> None
reveal_type(Member.__init__) reveal_type(Member.__init__)
alice = Member(name="Alice", role="admin") alice = Member(name="Alice", role="admin")
@ -37,7 +37,7 @@ class Data:
content: list[int] = field(default_factory=list) content: list[int] = field(default_factory=list)
timestamp: datetime = field(default_factory=datetime.now, init=False) timestamp: datetime = field(default_factory=datetime.now, init=False)
# revealed: (self: Data, content: list[int] = list[int]) -> None # revealed: (self: Data, content: list[int] = ...) -> None
reveal_type(Data.__init__) reveal_type(Data.__init__)
data = Data([1, 2, 3]) data = Data([1, 2, 3])
@ -63,7 +63,7 @@ class Person:
age: int | None = field(default=None, kw_only=True) age: int | None = field(default=None, kw_only=True)
role: str = field(default="user", kw_only=True) role: str = field(default="user", kw_only=True)
# revealed: (self: Person, name: str, *, age: int | None = None, role: str = Literal["user"]) -> None # revealed: (self: Person, name: str, *, age: int | None = None, role: str = "user") -> None
reveal_type(Person.__init__) reveal_type(Person.__init__)
alice = Person(role="admin", name="Alice") alice = Person(role="admin", name="Alice")

View File

@ -591,9 +591,9 @@ try:
reveal_type(x) # revealed: B | D reveal_type(x) # revealed: B | D
reveal_type(x) # revealed: B | D reveal_type(x) # revealed: B | D
x = foo x = foo
reveal_type(x) # revealed: def foo(param=A) -> Unknown reveal_type(x) # revealed: def foo(param=...) -> Unknown
except: except:
reveal_type(x) # revealed: Literal[1] | (def foo(param=A) -> Unknown) reveal_type(x) # revealed: Literal[1] | (def foo(param=...) -> Unknown)
class Bar: class Bar:
x = could_raise_returns_E() x = could_raise_returns_E()
@ -603,9 +603,9 @@ except:
reveal_type(x) # revealed: <class 'Bar'> reveal_type(x) # revealed: <class 'Bar'>
finally: finally:
# TODO: should be `Literal[1] | <class 'foo'> | <class 'Bar'>` # TODO: should be `Literal[1] | <class 'foo'> | <class 'Bar'>`
reveal_type(x) # revealed: (def foo(param=A) -> Unknown) | <class 'Bar'> reveal_type(x) # revealed: (def foo(param=...) -> Unknown) | <class 'Bar'>
reveal_type(x) # revealed: (def foo(param=A) -> Unknown) | <class 'Bar'> reveal_type(x) # revealed: (def foo(param=...) -> Unknown) | <class 'Bar'>
``` ```
[1]: https://astral-sh.notion.site/Exception-handler-control-flow-11348797e1ca80bb8ce1e9aedbbe439d [1]: https://astral-sh.notion.site/Exception-handler-control-flow-11348797e1ca80bb8ce1e9aedbbe439d

View File

@ -24,8 +24,8 @@ reveal_type(lambda a, b: a + b) # revealed: (a, b) -> Unknown
But, it can have default values: But, it can have default values:
```py ```py
reveal_type(lambda a=1: a) # revealed: (a=Literal[1]) -> Unknown reveal_type(lambda a=1: a) # revealed: (a=1) -> Unknown
reveal_type(lambda a, b=2: a) # revealed: (a, b=Literal[2]) -> Unknown reveal_type(lambda a, b=2: a) # revealed: (a, b=2) -> Unknown
``` ```
And, positional-only parameters: And, positional-only parameters:
@ -37,7 +37,7 @@ reveal_type(lambda a, b, /, c: c) # revealed: (a, b, /, c) -> Unknown
And, keyword-only parameters: And, keyword-only parameters:
```py ```py
reveal_type(lambda a, *, b=2, c: b) # revealed: (a, *, b=Literal[2], c) -> Unknown reveal_type(lambda a, *, b=2, c: b) # revealed: (a, *, b=2, c) -> Unknown
``` ```
And, variadic parameter: And, variadic parameter:
@ -55,7 +55,7 @@ reveal_type(lambda **kwargs: kwargs) # revealed: (**kwargs) -> Unknown
Mixing all of them together: Mixing all of them together:
```py ```py
# revealed: (a, b, /, c=Literal[True], *args, *, d=Literal["default"], e=Literal[5], **kwargs) -> Unknown # revealed: (a, b, /, c=True, *args, *, d="default", e=5, **kwargs) -> Unknown
reveal_type(lambda a, b, /, c=True, *args, d="default", e=5, **kwargs: None) reveal_type(lambda a, b, /, c=True, *args, d="default", e=5, **kwargs: None)
``` ```
@ -94,7 +94,7 @@ Here, a `lambda` expression is used as the default value for a parameter in anot
expression. expression.
```py ```py
reveal_type(lambda a=lambda x, y: 0: 2) # revealed: (a=(x, y) -> Unknown) -> Unknown reveal_type(lambda a=lambda x, y: 0: 2) # revealed: (a=...) -> Unknown
``` ```
## Assignment ## Assignment

View File

@ -38,7 +38,7 @@ class Product(BaseModel):
name: str = Field(..., kw_only=False, min_length=1) name: str = Field(..., kw_only=False, min_length=1)
internal_price_cent: int = Field(..., gt=0, alias="price_cent") internal_price_cent: int = Field(..., gt=0, alias="price_cent")
reveal_type(Product.__init__) # revealed: (self: Product, name: str = Any, *, price_cent: int = Any) -> None reveal_type(Product.__init__) # revealed: (self: Product, name: str = ..., *, price_cent: int = ...) -> None
product = Product("Laptop", price_cent=999_00) product = Product("Laptop", price_cent=999_00)

View File

@ -19,7 +19,7 @@ class User:
id: int id: int
role: str = strawberry.field(default="user") role: str = strawberry.field(default="user")
reveal_type(User.__init__) # revealed: (self: User, *, id: int, role: str = Any) -> None reveal_type(User.__init__) # revealed: (self: User, *, id: int, role: str = ...) -> None
user = User(id=1) user = User(id=1)
reveal_type(user.id) # revealed: int reveal_type(user.id) # revealed: int

View File

@ -477,7 +477,7 @@ def keyword_only_with_default_2(*, y: int = 42) -> int:
# parameter list i.e., `()` # parameter list i.e., `()`
# TODO: This shouldn't error # TODO: This shouldn't error
# error: [invalid-argument-type] # error: [invalid-argument-type]
# revealed: (*, x: int = Literal[42]) -> bool # revealed: (*, x: int = 42) -> bool
reveal_type(multiple(keyword_only_with_default_1, keyword_only_with_default_2)) reveal_type(multiple(keyword_only_with_default_1, keyword_only_with_default_2))
def keyword_only1(*, x: int) -> int: def keyword_only1(*, x: int) -> int:

View File

@ -97,7 +97,7 @@ inside the module:
import typing import typing
reveal_type(typing.__name__) # revealed: str reveal_type(typing.__name__) # revealed: str
reveal_type(typing.__init__) # revealed: bound method ModuleType.__init__(name: str, doc: str | None = EllipsisType) -> None reveal_type(typing.__init__) # revealed: bound method ModuleType.__init__(name: str, doc: str | None = ...) -> None
# For a stub module, we don't know that `__file__` is a string (at runtime it may be entirely # For a stub module, we don't know that `__file__` is a string (at runtime it may be entirely
# unset, but we follow typeshed here): # unset, but we follow typeshed here):

View File

@ -73,8 +73,8 @@ error[missing-argument]: No argument provided for required parameter `a` of func
13 | 13 |
14 | Foo().method() # error: [missing-argument] 14 | Foo().method() # error: [missing-argument]
| |
info: Union variant `def f(a, b=Literal[42]) -> Unknown` is incompatible with this call site info: Union variant `def f(a, b=42) -> Unknown` is incompatible with this call site
info: Attempted to call union type `(def f(a, b=Literal[42]) -> Unknown) | (def g(a, b) -> Unknown)` info: Attempted to call union type `(def f(a, b=42) -> Unknown) | (def g(a, b) -> Unknown)`
info: rule `missing-argument` is enabled by default info: rule `missing-argument` is enabled by default
``` ```
@ -91,7 +91,7 @@ error[missing-argument]: No argument provided for required parameter `a` of func
14 | Foo().method() # error: [missing-argument] 14 | Foo().method() # error: [missing-argument]
| |
info: Union variant `def g(a, b) -> Unknown` is incompatible with this call site info: Union variant `def g(a, b) -> Unknown` is incompatible with this call site
info: Attempted to call union type `(def f(a, b=Literal[42]) -> Unknown) | (def g(a, b) -> Unknown)` info: Attempted to call union type `(def f(a, b=42) -> Unknown) | (def g(a, b) -> Unknown)`
info: rule `missing-argument` is enabled by default info: rule `missing-argument` is enabled by default
``` ```

View File

@ -73,8 +73,8 @@ error[too-many-positional-arguments]: Too many positional arguments to function
13 | 13 |
14 | Foo().method(1, 2) # error: [too-many-positional-arguments] 14 | Foo().method(1, 2) # error: [too-many-positional-arguments]
| |
info: Union variant `def f(a, b=Literal[42]) -> Unknown` is incompatible with this call site info: Union variant `def f(a, b=42) -> Unknown` is incompatible with this call site
info: Attempted to call union type `(def f(a, b=Literal[42]) -> Unknown) | (def g(a, b) -> Unknown)` info: Attempted to call union type `(def f(a, b=42) -> Unknown) | (def g(a, b) -> Unknown)`
info: rule `too-many-positional-arguments` is enabled by default info: rule `too-many-positional-arguments` is enabled by default
``` ```
@ -91,7 +91,7 @@ error[too-many-positional-arguments]: Too many positional arguments to function
14 | Foo().method(1, 2) # error: [too-many-positional-arguments] 14 | Foo().method(1, 2) # error: [too-many-positional-arguments]
| |
info: Union variant `def g(a, b) -> Unknown` is incompatible with this call site info: Union variant `def g(a, b) -> Unknown` is incompatible with this call site
info: Attempted to call union type `(def f(a, b=Literal[42]) -> Unknown) | (def g(a, b) -> Unknown)` info: Attempted to call union type `(def f(a, b=42) -> Unknown) | (def g(a, b) -> Unknown)`
info: rule `too-many-positional-arguments` is enabled by default info: rule `too-many-positional-arguments` is enabled by default
``` ```

View File

@ -73,8 +73,8 @@ error[unknown-argument]: Argument `d` does not match any known parameter of func
13 | 13 |
14 | Foo().method(a=1, b=2, c=3) # error: [unknown-argument] 14 | Foo().method(a=1, b=2, c=3) # error: [unknown-argument]
| |
info: Union variant `def f(a, b, c=Literal[42]) -> Unknown` is incompatible with this call site info: Union variant `def f(a, b, c=42) -> Unknown` is incompatible with this call site
info: Attempted to call union type `(def f(a, b, c=Literal[42]) -> Unknown) | (def g(a, b) -> Unknown)` info: Attempted to call union type `(def f(a, b, c=42) -> Unknown) | (def g(a, b) -> Unknown)`
info: rule `unknown-argument` is enabled by default info: rule `unknown-argument` is enabled by default
``` ```
@ -91,7 +91,7 @@ error[unknown-argument]: Argument `d` does not match any known parameter of func
14 | Foo().method(a=1, b=2, c=3) # error: [unknown-argument] 14 | Foo().method(a=1, b=2, c=3) # error: [unknown-argument]
| |
info: Union variant `def g(a, b) -> Unknown` is incompatible with this call site info: Union variant `def g(a, b) -> Unknown` is incompatible with this call site
info: Attempted to call union type `(def f(a, b, c=Literal[42]) -> Unknown) | (def g(a, b) -> Unknown)` info: Attempted to call union type `(def f(a, b, c=42) -> Unknown) | (def g(a, b) -> Unknown)`
info: rule `unknown-argument` is enabled by default info: rule `unknown-argument` is enabled by default
``` ```

View File

@ -67,7 +67,7 @@ class Person:
metadata: InitVar[str] = "default" metadata: InitVar[str] = "default"
reveal_type(Person.__init__) # revealed: (self: Person, name: str, age: int, metadata: str = Literal["default"]) -> None reveal_type(Person.__init__) # revealed: (self: Person, name: str, age: int, metadata: str = "default") -> None
alice = Person("Alice", 30) alice = Person("Alice", 30)
bob = Person("Bob", 25, "custom metadata") bob = Person("Bob", 25, "custom metadata")

View File

@ -1838,15 +1838,39 @@ impl<'db> FmtDetailed<'db> for DisplayParameter<'_, 'db> {
} }
} }
// Default value can only be specified if `name` is given. // Default value can only be specified if `name` is given.
if let Some(default_ty) = self.param.default_type() { if let Some(default_type) = self.param.default_type() {
if self.param.annotated_type().is_some() { if self.param.annotated_type().is_some() {
f.write_str(" = ")?; f.write_str(" = ")?;
} else { } else {
f.write_str("=")?; f.write_str("=")?;
} }
default_ty match default_type {
.display_with(self.db, self.settings.clone()) Type::IntLiteral(_)
.fmt_detailed(f)?; | Type::BooleanLiteral(_)
| Type::StringLiteral(_)
| Type::EnumLiteral(_)
| Type::BytesLiteral(_) => {
// For Literal types display the value without `Literal[..]` wrapping
let representation =
default_type.representation(self.db, self.settings.clone());
representation.fmt_detailed(f)?;
}
Type::NominalInstance(instance) => {
// Some key default types like `None` are worth showing
let class = instance.class(self.db);
match (class, class.known(self.db)) {
(_, Some(KnownClass::NoneType)) => {
f.with_type(default_type).write_str("None")?;
}
(_, Some(KnownClass::NoDefaultType)) => {
f.with_type(default_type).write_str("NoDefault")?;
}
_ => f.write_str("...")?,
}
}
_ => f.write_str("...")?,
}
} }
} else if let Some(ty) = self.param.annotated_type() { } else if let Some(ty) = self.param.annotated_type() {
// This case is specifically for the `Callable` signature where name and default value // This case is specifically for the `Callable` signature where name and default value
@ -2598,7 +2622,7 @@ mod tests {
], ],
Some(Type::none(&db)) Some(Type::none(&db))
), ),
@"(x=int, y: str = str) -> None" @"(x=..., y: str = ...) -> None"
); );
// All positional only parameters. // All positional only parameters.
@ -2683,9 +2707,7 @@ mod tests {
], ],
Some(KnownClass::Bytes.to_instance(&db)) Some(KnownClass::Bytes.to_instance(&db))
), ),
@"(a, b: int, c=Literal[1], d: int = Literal[2], \ @"(a, b: int, c=1, d: int = 2, /, e=3, f: int = 4, *args: object, *, g=5, h: int = 6, **kwargs: str) -> bytes"
/, e=Literal[3], f: int = Literal[4], *args: object, \
*, g=Literal[5], h: int = Literal[6], **kwargs: str) -> bytes"
); );
} }
@ -2727,8 +2749,8 @@ mod tests {
), ),
@r" @r"
( (
x=int, x=...,
y: str = str y: str = ...
) -> None ) -> None
" "
); );
@ -2843,15 +2865,15 @@ mod tests {
( (
a, a,
b: int, b: int,
c=Literal[1], c=1,
d: int = Literal[2], d: int = 2,
/, /,
e=Literal[3], e=3,
f: int = Literal[4], f: int = 4,
*args: object, *args: object,
*, *,
g=Literal[5], g=5,
h: int = Literal[6], h: int = 6,
**kwargs: str **kwargs: str
) -> bytes ) -> bytes
" "

View File

@ -5,7 +5,7 @@ expression: signature_help
{ {
"signatures": [ "signatures": [
{ {
"label": "(pattern: str | Pattern[str], string: str, flags: int = Literal[0]) -> Match[str] | None", "label": "(pattern: str | Pattern[str], string: str, flags: int = 0) -> Match[str] | None",
"documentation": "Try to apply the pattern at the start of the string, returning/na Match object, or None if no match was found.\n", "documentation": "Try to apply the pattern at the start of the string, returning/na Match object, or None if no match was found.\n",
"parameters": [ "parameters": [
{ {
@ -15,12 +15,12 @@ expression: signature_help
"label": "string: str" "label": "string: str"
}, },
{ {
"label": "flags: int = Literal[0]" "label": "flags: int = 0"
} }
] ]
}, },
{ {
"label": "(pattern: bytes | Pattern[bytes], string: Buffer, flags: int = Literal[0]) -> Match[bytes] | None", "label": "(pattern: bytes | Pattern[bytes], string: Buffer, flags: int = 0) -> Match[bytes] | None",
"parameters": [ "parameters": [
{ {
"label": "pattern: bytes | Pattern[bytes]" "label": "pattern: bytes | Pattern[bytes]"
@ -29,7 +29,7 @@ expression: signature_help
"label": "string: Buffer" "label": "string: Buffer"
}, },
{ {
"label": "flags: int = Literal[0]" "label": "flags: int = 0"
} }
] ]
} }