Skip to content

Commit

Permalink
[red-knot] have mdformat wrap mdtest files to 100 columns (astral-sh#…
Browse files Browse the repository at this point in the history
…14020)

This makes it easier to read and edit (and review changes to) these
files as source, even though it doesn't affect the rendering.
  • Loading branch information
carljm authored Oct 31, 2024
1 parent b372fe7 commit b8acadd
Show file tree
Hide file tree
Showing 22 changed files with 210 additions and 249 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
wrap = 100
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,10 @@ foo = 1
reveal_type(x)
```

Note: in this particular example, one could argue that the most likely error would
be a wrong order of the `x`/`foo` definitions, and so it could be desirable to infer
`Literal[1]` for the type of `x`. On the other hand, there might be a variable `fob`
a little higher up in this file, and the actual error might have been just a typo.
Inferring `Unknown` thus seems like the safest option.
Note: in this particular example, one could argue that the most likely error would be a wrong order
of the `x`/`foo` definitions, and so it could be desirable to infer `Literal[1]` for the type of
`x`. On the other hand, there might be a variable `fob` a little higher up in this file, and the
actual error might have been just a typo. Inferring `Unknown` thus seems like the safest option.

## Unbound class variable

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ For references, see:

## Operations

We support inference for all Python's binary operators:
`+`, `-`, `*`, `@`, `/`, `//`, `%`, `**`, `<<`, `>>`, `&`, `^`, and `|`.
We support inference for all Python's binary operators: `+`, `-`, `*`, `@`, `/`, `//`, `%`, `**`,
`<<`, `>>`, `&`, `^`, and `|`.

```py
class A:
Expand Down Expand Up @@ -152,9 +152,8 @@ reveal_type(B() - A()) # revealed: int

## Non-reflected precedence in general

In general, if the left-hand side defines `__add__` and the right-hand side
defines `__radd__` and the right-hand side is not a subtype of the left-hand
side, `lhs.__add__` will take precedence:
In general, if the left-hand side defines `__add__` and the right-hand side defines `__radd__` and
the right-hand side is not a subtype of the left-hand side, `lhs.__add__` will take precedence:

```py
class A:
Expand All @@ -181,9 +180,8 @@ reveal_type(C() + C()) # revealed: int

## Reflected precedence for subtypes (in some cases)

If the right-hand operand is a subtype of the left-hand operand and has a
different implementation of the reflected method, the reflected method on the
right-hand operand takes precedence.
If the right-hand operand is a subtype of the left-hand operand and has a different implementation
of the reflected method, the reflected method on the right-hand operand takes precedence.

```py
class A:
Expand Down Expand Up @@ -213,9 +211,8 @@ reveal_type(A() + C()) # revealed: str

## Reflected precedence 2

If the right-hand operand is a subtype of the left-hand operand, but does not
override the reflected method, the left-hand operand's non-reflected method
still takes precedence:
If the right-hand operand is a subtype of the left-hand operand, but does not override the reflected
method, the left-hand operand's non-reflected method still takes precedence:

```py
class A:
Expand All @@ -232,17 +229,15 @@ reveal_type(A() + B()) # revealed: str

## Only reflected supported

For example, at runtime, `(1).__add__(1.2)` is `NotImplemented`, but
`(1.2).__radd__(1) == 2.2`, meaning that `1 + 1.2` succeeds at runtime
(producing `2.2`). The runtime tries the second one only if the first one
returns `NotImplemented` to signal failure.
For example, at runtime, `(1).__add__(1.2)` is `NotImplemented`, but `(1.2).__radd__(1) == 2.2`,
meaning that `1 + 1.2` succeeds at runtime (producing `2.2`). The runtime tries the second one only
if the first one returns `NotImplemented` to signal failure.

Typeshed and other stubs annotate dunder-method calls that would return
`NotImplemented` as being "illegal" calls. `int.__add__` is annotated as only
"accepting" `int`s, even though it strictly-speaking "accepts" any other object
without raising an exception -- it will simply return `NotImplemented`,
allowing the runtime to try the `__radd__` method of the right-hand operand
as well.
Typeshed and other stubs annotate dunder-method calls that would return `NotImplemented` as being
"illegal" calls. `int.__add__` is annotated as only "accepting" `int`s, even though it
strictly-speaking "accepts" any other object without raising an exception -- it will simply return
`NotImplemented`, allowing the runtime to try the `__radd__` method of the right-hand operand as
well.

```py
class A:
Expand Down Expand Up @@ -308,8 +303,8 @@ reveal_type(y + 4.12) # revealed: int

## With literal types

When we have a literal type for one operand, we're able to fall back to the
instance handling for its instance super-type.
When we have a literal type for one operand, we're able to fall back to the instance handling for
its instance super-type.

```py
class A:
Expand Down Expand Up @@ -348,15 +343,13 @@ reveal_type(literal_string_instance + A()) # revealed: @Todo

## Operations involving instances of classes inheriting from `Any`

`Any` and `Unknown` represent a set of possible runtime objects, wherein the
bounds of the set are unknown. Whether the left-hand operand's dunder or the
right-hand operand's reflected dunder depends on whether the right-hand operand
is an instance of a class that is a subclass of the left-hand operand's class
and overrides the reflected dunder. In the following example, because of the
unknowable nature of `Any`/`Unknown`, we must consider both possibilities:
`Any`/`Unknown` might resolve to an unknown third class that inherits from `X`
and overrides `__radd__`; but it also might not. Thus, the correct answer here
for the `reveal_type` is `int | Unknown`.
`Any` and `Unknown` represent a set of possible runtime objects, wherein the bounds of the set are
unknown. Whether the left-hand operand's dunder or the right-hand operand's reflected dunder depends
on whether the right-hand operand is an instance of a class that is a subclass of the left-hand
operand's class and overrides the reflected dunder. In the following example, because of the
unknowable nature of `Any`/`Unknown`, we must consider both possibilities: `Any`/`Unknown` might
resolve to an unknown third class that inherits from `X` and overrides `__radd__`; but it also might
not. Thus, the correct answer here for the `reveal_type` is `int | Unknown`.

```py
from does_not_exist import Foo # error: [unresolved-import]
Expand Down Expand Up @@ -426,10 +419,9 @@ reveal_type(B() + C())

### Reflected dunder is not tried between two objects of the same type

For the specific case where the left-hand operand is the exact same type as the
right-hand operand, the reflected dunder of the right-hand operand is not
tried; the runtime short-circuits after trying the unreflected dunder of the
left-hand operand. For context, see
For the specific case where the left-hand operand is the exact same type as the right-hand operand,
the reflected dunder of the right-hand operand is not tried; the runtime short-circuits after trying
the unreflected dunder of the left-hand operand. For context, see
[this mailing list discussion](https://mail.python.org/archives/list/python-dev@python.org/thread/7NZUCODEAPQFMRFXYRMGJXDSIS3WJYIV/).

```py
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Comparison: Byte literals

These tests assert that we infer precise `Literal` types for comparisons between objects
inferred as having `Literal` bytes types:
These tests assert that we infer precise `Literal` types for comparisons between objects inferred as
having `Literal` bytes types:

```py
reveal_type(b"abc" == b"abc") # revealed: Literal[True]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# Comparison: Membership Test

In Python, the term "membership test operators" refers to the operators
`in` and `not in`. To customize their behavior, classes can implement one of
the special methods `__contains__`, `__iter__`, or `__getitem__`.
In Python, the term "membership test operators" refers to the operators `in` and `not in`. To
customize their behavior, classes can implement one of the special methods `__contains__`,
`__iter__`, or `__getitem__`.

For references, see:

Expand All @@ -28,8 +28,8 @@ reveal_type(42 not in A()) # revealed: bool

## Implements `__iter__`

Classes that don't implement `__contains__`, but do implement `__iter__`, also
support containment checks; the needle will be sought in their iterated items:
Classes that don't implement `__contains__`, but do implement `__iter__`, also support containment
checks; the needle will be sought in their iterated items:

```py
class StringIterator:
Expand All @@ -48,11 +48,10 @@ reveal_type(42 not in A()) # revealed: bool

## Implements `__getitems__`

The final fallback is to implement `__getitem__` for integer keys. Python will
call `__getitem__` with `0`, `1`, `2`... until either the needle is found
(leading the membership test to evaluate to `True`) or `__getitem__` raises
`IndexError` (the raised exception is swallowed, but results in the membership
test evaluating to `False`).
The final fallback is to implement `__getitem__` for integer keys. Python will call `__getitem__`
with `0`, `1`, `2`... until either the needle is found (leading the membership test to evaluate to
`True`) or `__getitem__` raises `IndexError` (the raised exception is swallowed, but results in the
membership test evaluating to `False`).

```py
class A:
Expand All @@ -67,8 +66,8 @@ reveal_type(42 not in A()) # revealed: bool

## Wrong Return Type

Python coerces the results of containment checks to `bool`, even if `__contains__`
returns a non-bool:
Python coerces the results of containment checks to `bool`, even if `__contains__` returns a
non-bool:

```py
class A:
Expand All @@ -81,8 +80,7 @@ reveal_type("hello" not in A()) # revealed: bool

## Literal Result for `in` and `not in`

`__contains__` with a literal return type may result in a `BooleanLiteral`
outcome.
`__contains__` with a literal return type may result in a `BooleanLiteral` outcome.

```py
from typing import Literal
Expand All @@ -106,9 +104,8 @@ reveal_type(42 not in AlwaysFalse()) # revealed: @Todo

## No Fallback for `__contains__`

If `__contains__` is implemented, checking membership of a type it doesn't
accept is an error; it doesn't result in a fallback to `__iter__` or
`__getitem__`:
If `__contains__` is implemented, checking membership of a type it doesn't accept is an error; it
doesn't result in a fallback to `__iter__` or `__getitem__`:

```py
class CheckContains: ...
Expand Down Expand Up @@ -151,8 +148,8 @@ reveal_type(CheckGetItem() in B()) # revealed: bool

## Invalid Old-Style Iteration

If `__getitem__` is implemented but does not accept integer arguments, then
the membership test is not supported and should trigger a diagnostic.
If `__getitem__` is implemented but does not accept integer arguments, then the membership test is
not supported and should trigger a diagnostic.

```py
class A:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
# Comparison: Rich Comparison

Rich comparison operations (`==`, `!=`, `<`, `<=`, `>`, `>=`) in Python are
implemented through double-underscore methods that allow customization of
comparison behavior.
Rich comparison operations (`==`, `!=`, `<`, `<=`, `>`, `>=`) in Python are implemented through
double-underscore methods that allow customization of comparison behavior.

For references, see:

Expand All @@ -11,9 +10,8 @@ For references, see:

## Rich Comparison Dunder Implementations For Same Class

Classes can support rich comparison by implementing dunder methods like
`__eq__`, `__ne__`, etc. The most common case involves implementing these
methods for the same type:
Classes can support rich comparison by implementing dunder methods like `__eq__`, `__ne__`, etc. The
most common case involves implementing these methods for the same type:

```py
from __future__ import annotations
Expand Down Expand Up @@ -47,8 +45,8 @@ reveal_type(A() >= A()) # revealed: set

## Rich Comparison Dunder Implementations for Other Class

In some cases, classes may implement rich comparison dunder methods for
comparisons with a different type:
In some cases, classes may implement rich comparison dunder methods for comparisons with a different
type:

```py
from __future__ import annotations
Expand Down Expand Up @@ -84,10 +82,9 @@ reveal_type(A() >= B()) # revealed: set

## Reflected Comparisons

Fallback to the right-hand side’s comparison methods occurs when the left-hand
side does not define them. Note: class `B` has its own `__eq__` and `__ne__`
methods to override those of `object`, but these methods will be ignored here
because they require a mismatched operand type.
Fallback to the right-hand side’s comparison methods occurs when the left-hand side does not define
them. Note: class `B` has its own `__eq__` and `__ne__` methods to override those of `object`, but
these methods will be ignored here because they require a mismatched operand type.

```py
from __future__ import annotations
Expand Down Expand Up @@ -148,9 +145,9 @@ reveal_type(C() <= C()) # revealed: float

## Reflected Comparisons with Subclasses

When subclasses override comparison methods, these overridden methods take
precedence over those in the parent class. Class `B` inherits from `A` and
redefines comparison methods to return types other than `A`.
When subclasses override comparison methods, these overridden methods take precedence over those in
the parent class. Class `B` inherits from `A` and redefines comparison methods to return types other
than `A`.

```py
from __future__ import annotations
Expand Down Expand Up @@ -205,9 +202,8 @@ reveal_type(A() >= B()) # revealed: bytes

## Reflected Comparisons with Subclass But Falls Back to LHS

In the case of a subclass, the right-hand side has priority. However, if the
overridden dunder method has an mismatched type to operand, the comparison will
fall back to the left-hand side.
In the case of a subclass, the right-hand side has priority. However, if the overridden dunder
method has an mismatched type to operand, the comparison will fall back to the left-hand side.

```py
from __future__ import annotations
Expand All @@ -233,15 +229,13 @@ reveal_type(A() > B()) # revealed: B

## Operations involving instances of classes inheriting from `Any`

`Any` and `Unknown` represent a set of possible runtime objects, wherein the
bounds of the set are unknown. Whether the left-hand operand's dunder or the
right-hand operand's reflected dunder depends on whether the right-hand operand
is an instance of a class that is a subclass of the left-hand operand's class
and overrides the reflected dunder. In the following example, because of the
unknowable nature of `Any`/`Unknown`, we must consider both possibilities:
`Any`/`Unknown` might resolve to an unknown third class that inherits from `X`
and overrides `__gt__`; but it also might not. Thus, the correct answer here for
the `reveal_type` is `int | Unknown`.
`Any` and `Unknown` represent a set of possible runtime objects, wherein the bounds of the set are
unknown. Whether the left-hand operand's dunder or the right-hand operand's reflected dunder depends
on whether the right-hand operand is an instance of a class that is a subclass of the left-hand
operand's class and overrides the reflected dunder. In the following example, because of the
unknowable nature of `Any`/`Unknown`, we must consider both possibilities: `Any`/`Unknown` might
resolve to an unknown third class that inherits from `X` and overrides `__gt__`; but it also might
not. Thus, the correct answer here for the `reveal_type` is `int | Unknown`.

(This test is referenced from `mdtest/binary/instances.md`)

Expand All @@ -262,12 +256,10 @@ reveal_type(X() < Y()) # revealed: int

## Equality and Inequality Fallback

This test confirms that `==` and `!=` comparisons default to identity
comparisons (`is`, `is not`) when argument types do not match the method
signature.
This test confirms that `==` and `!=` comparisons default to identity comparisons (`is`, `is not`)
when argument types do not match the method signature.

Please refer to the
[docs](https://docs.python.org/3/reference/datamodel.html#object.__eq__)
Please refer to the [docs](https://docs.python.org/3/reference/datamodel.html#object.__eq__)

```py
from __future__ import annotations
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ Walking through examples:
- `a = A() < B() < C()`

1. `A() < B() and B() < C()` - split in N comparison
1. `A()` and `B()` - evaluate outcome types
1. `bool` and `bool` - evaluate truthiness
1. `A | B` - union of "first true" types
1. `A()` and `B()` - evaluate outcome types
1. `bool` and `bool` - evaluate truthiness
1. `A | B` - union of "first true" types

- `b = 0 < 1 < A() < 3`

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,8 @@ reveal_type(a >= b) # revealed: bool

#### Comparison Unsupported

If two tuples contain types that do not support comparison, the result may be `Unknown`.
However, `==` and `!=` are exceptions and can still provide definite results.
If two tuples contain types that do not support comparison, the result may be `Unknown`. However,
`==` and `!=` are exceptions and can still provide definite results.

```py
a = (1, 2)
Expand All @@ -102,8 +102,8 @@ reveal_type(a > b) # revealed: bool
reveal_type(a >= b) # revealed: bool
```

However, if the lexicographic comparison completes without reaching a point where str and int are compared,
Python will still produce a result based on the prior elements.
However, if the lexicographic comparison completes without reaching a point where str and int are
compared, Python will still produce a result based on the prior elements.

```py path=short_circuit.py
a = (1, 2)
Expand Down
Loading

0 comments on commit b8acadd

Please sign in to comment.