Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ rayon = { version = "1.10.0" }
regex = { version = "1.10.2" }
rustc-hash = { version = "2.0.0" }
# When updating salsa, make sure to also update the revision in `fuzz/Cargo.toml`
salsa = { git = "https://github.com/salsa-rs/salsa.git", rev = "c999c713d757b857b13f23fe38acc40ec5b4134c" }
salsa = { git = "https://github.com/salsa-rs/salsa.git", rev = "b165ba7bd1b2a0112ce574a082ab8ea5102252ac" }
schemars = { version = "0.8.16" }
seahash = { version = "4.1.0" }
serde = { version = "1.0.197", features = ["derive"] }
Expand Down
24 changes: 10 additions & 14 deletions crates/red_knot_python_semantic/resources/mdtest/properties.md
Original file line number Diff line number Diff line change
Expand Up @@ -196,14 +196,10 @@ reveal_type(c.attr) # revealed: Unknown

## Behind the scenes

> TODO: This test is currently disabled pending
> [an upstream Salsa fix](https://github.com/salsa-rs/salsa/pull/741). Once that has been merged,
> re-enable this test by changing the language codes below back to `py`.

In this section, we trace through some of the steps that make properties work. We start with a
simple class `C` and a property `attr`:

```ignore
```py
class C:
def __init__(self):
self._attr: int = 0
Expand All @@ -220,7 +216,7 @@ class C:
Next, we create an instance of `C`. As we have seen above, accessing `attr` on the instance will
return an `int`:

```ignore
```py
c = C()

reveal_type(c.attr) # revealed: int
Expand All @@ -230,7 +226,7 @@ Behind the scenes, when we write `c.attr`, the first thing that happens is that
up the symbol `attr` on the meta-type of `c`, i.e. the class `C`. We can emulate this static lookup
using `inspect.getattr_static`, to see that `attr` is actually an instance of the `property` class:

```ignore
```py
from inspect import getattr_static

attr_property = getattr_static(C, "attr")
Expand All @@ -241,7 +237,7 @@ The `property` class has a `__get__` method, which makes it a descriptor. It als
method, which means that it is a *data* descriptor (if there is no setter, `__set__` is still
available but yields an `AttributeError` at runtime).

```ignore
```py
reveal_type(type(attr_property).__get__) # revealed: <wrapper-descriptor `__get__` of `property` objects>
reveal_type(type(attr_property).__set__) # revealed: <wrapper-descriptor `__set__` of `property` objects>
```
Expand All @@ -250,22 +246,22 @@ When we access `c.attr`, the `__get__` method of the `property` class is called,
property object itself as the first argument, and the class instance `c` as the second argument. The
third argument is the "owner" which can be set to `None` or to `C` in this case:

```ignore
```py
reveal_type(type(attr_property).__get__(attr_property, c, C)) # revealed: int
reveal_type(type(attr_property).__get__(attr_property, c, None)) # revealed: int
```

Alternatively, the above can also be written as a method call:

```ignore
```py
reveal_type(attr_property.__get__(c, C)) # revealed: int
```

When we access `attr` on the class itself, the descriptor protocol is also invoked, but the instance
argument is set to `None`. When `instance` is `None`, the call to `property.__get__` returns the
property instance itself. So the following expressions are all equivalent

```ignore
```py
reveal_type(attr_property) # revealed: property
reveal_type(C.attr) # revealed: property
reveal_type(attr_property.__get__(None, C)) # revealed: property
Expand All @@ -275,7 +271,7 @@ reveal_type(type(attr_property).__get__(attr_property, None, C)) # revealed: pr
When we set the property using `c.attr = "a"`, the `__set__` method of the property class is called.
This attribute access desugars to

```ignore
```py
type(attr_property).__set__(attr_property, c, "a")

# error: [call-non-callable] "Call of wrapper descriptor `property.__set__` failed: calling the setter failed"
Expand All @@ -284,7 +280,7 @@ type(attr_property).__set__(attr_property, c, 1)

which is also equivalent to the following expressions:

```ignore
```py
attr_property.__set__(c, "a")
# error: [call-non-callable]
attr_property.__set__(c, 1)
Expand All @@ -297,7 +293,7 @@ C.attr.__set__(c, 1)
Properties also have `fget` and `fset` attributes that can be used to retrieve the original getter
and setter functions, respectively.

```ignore
```py
reveal_type(attr_property.fget) # revealed: Literal[attr]
reveal_type(attr_property.fget(c)) # revealed: int

Expand Down
2 changes: 1 addition & 1 deletion fuzz/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ ruff_python_formatter = { path = "../crates/ruff_python_formatter" }
ruff_text_size = { path = "../crates/ruff_text_size" }

libfuzzer-sys = { git = "https://github.com/rust-fuzz/libfuzzer", default-features = false }
salsa = { git = "https://github.com/salsa-rs/salsa.git", rev = "c999c713d757b857b13f23fe38acc40ec5b4134c" }
salsa = { git = "https://github.com/salsa-rs/salsa.git", rev = "b165ba7bd1b2a0112ce574a082ab8ea5102252ac" }
similar = { version = "2.5.0" }
tracing = { version = "0.1.40" }

Expand Down
Loading