Compare commits

...

9 Commits

Author SHA1 Message Date
Dhruv Manilawala
2d0468137c Extract creating workspaces in the server 2024-10-16 14:51:23 +05:30
Dhruv Manilawala
c6b311c546 Update setup image for PyCharm External Tool (#13767)
## Summary

fixes: #13765 

## Preview

<img width="624" alt="Screenshot 2024-10-16 at 10 05 57"
src="https://github.com/user-attachments/assets/c0eccda5-3cf1-4119-a9b5-d86b01a8c64c">
2024-10-16 04:41:37 +00:00
Dhruv Manilawala
b16f665a81 [red-knot] Infer target types for unpacked tuple assignment (#13316)
## Summary

This PR adds support for unpacking tuple expression in an assignment
statement where the target expression can be a tuple or a list (the
allowed sequence targets).

The implementation introduces a new `infer_assignment_target` which can
then be used for other targets like the ones in for loops as well. This
delegates it to the `infer_definition`. The final implementation uses a
recursive function that visits the target expression in source order and
compares the variable node that corresponds to the definition. At the
same time, it keeps track of where it is on the assignment value type.

The logic also accounts for the number of elements on both sides such
that it matches even if there's a gap in between. For example, if
there's a starred expression like `(a, *b, c) = (1, 2, 3)`, then the
type of `a` will be `Literal[1]` and the type of `b` will be
`Literal[2]`.

There are a couple of follow-ups that can be done:
* Use this logic for other target positions like `for` loop
* Add diagnostics for mis-match length between LHS and RHS

## Test Plan

Add various test cases using the new markdown test framework.
Validate that existing test cases pass.

---------

Co-authored-by: Carl Meyer <carl@astral.sh>
2024-10-15 19:07:11 +00:00
Alex
d77480768d [red-knot] Port type inference tests to new test framework (#13719)
## Summary

Porting infer tests to new markdown tests framework.

Link to the corresponding issue: #13696

---------

Co-authored-by: Carl Meyer <carl@astral.sh>
2024-10-15 11:23:46 -07:00
github-actions[bot]
5fa82fb0cd Sync vendored typeshed stubs (#13753) 2024-10-15 13:36:11 +00:00
David Peter
74bf4b0653 [red knot] Fix narrowing for '… is not …' type guards, add '… is …' type guards (#13758)
## Summary

- Fix a bug with `… is not …` type guards.
 
  Previously, in an example like
  ```py
  x = [1]
  y = [1]
  
  if x is not y:
      reveal_type(x)
  ```
  we would infer a type of `list[int] & ~list[int] == Never` for `x`
  inside the conditional (instead of `list[int]`), since we built a
  (negative) intersection with the type of the right hand side (`y`).
  However, as this example shows, this assumption can only be made for
  singleton types (types with a single inhabitant) such as `None`.
- Add support for `… is …` type guards.

closes #13715

## Test Plan

Moved existing `narrow_…` tests to Markdown-based tests and added new
ones (including a regression test for the bug described above). Note
that will create some conflicts with
https://github.com/astral-sh/ruff/pull/13719. I tried to establish the
correct organizational structure as proposed in
https://github.com/astral-sh/ruff/pull/13719#discussion_r1800188105
2024-10-15 14:49:32 +02:00
Micha Reiser
5f65e842e8 Upgrade salsa (#13757) 2024-10-15 11:06:32 +00:00
Micha Reiser
72ac6cd5a5 Fix TODO directive out of bounds acccess (#13756) 2024-10-15 10:49:53 +02:00
David Peter
04b636cba2 [red knot] Use memmem::find instead of custom version (#13750)
This is a follow-up on #13746:

- Use `memmem::find` instead of rolling our own inferior version.
- Avoid `x.as_ref()` calls using `&**x`
2024-10-14 15:17:19 +02:00
159 changed files with 7671 additions and 6957 deletions

8
Cargo.lock generated
View File

@@ -2083,6 +2083,7 @@ dependencies = [
"hashbrown 0.15.0",
"insta",
"itertools 0.13.0",
"memchr",
"ordermap",
"red_knot_test",
"red_knot_vendored",
@@ -2832,6 +2833,7 @@ dependencies = [
"serde",
"serde_json",
"shellexpand",
"thiserror",
"tracing",
"tracing-subscriber",
]
@@ -3008,7 +3010,7 @@ checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1"
[[package]]
name = "salsa"
version = "0.18.0"
source = "git+https://github.com/salsa-rs/salsa.git?rev=4a7c955255e707e64e43f3ce5eabb771ae067768#4a7c955255e707e64e43f3ce5eabb771ae067768"
source = "git+https://github.com/salsa-rs/salsa.git?rev=b14be5c0392f4c55eca60b92e457a35549372382#b14be5c0392f4c55eca60b92e457a35549372382"
dependencies = [
"append-only-vec",
"arc-swap",
@@ -3028,12 +3030,12 @@ dependencies = [
[[package]]
name = "salsa-macro-rules"
version = "0.1.0"
source = "git+https://github.com/salsa-rs/salsa.git?rev=4a7c955255e707e64e43f3ce5eabb771ae067768#4a7c955255e707e64e43f3ce5eabb771ae067768"
source = "git+https://github.com/salsa-rs/salsa.git?rev=b14be5c0392f4c55eca60b92e457a35549372382#b14be5c0392f4c55eca60b92e457a35549372382"
[[package]]
name = "salsa-macros"
version = "0.18.0"
source = "git+https://github.com/salsa-rs/salsa.git?rev=4a7c955255e707e64e43f3ce5eabb771ae067768#4a7c955255e707e64e43f3ce5eabb771ae067768"
source = "git+https://github.com/salsa-rs/salsa.git?rev=b14be5c0392f4c55eca60b92e457a35549372382#b14be5c0392f4c55eca60b92e457a35549372382"
dependencies = [
"heck",
"proc-macro2",

View File

@@ -117,7 +117,7 @@ rayon = { version = "1.10.0" }
regex = { version = "1.10.2" }
rstest = { version = "0.22.0", default-features = false }
rustc-hash = { version = "2.0.0" }
salsa = { git = "https://github.com/salsa-rs/salsa.git", rev = "4a7c955255e707e64e43f3ce5eabb771ae067768" }
salsa = { git = "https://github.com/salsa-rs/salsa.git", rev = "b14be5c0392f4c55eca60b92e457a35549372382" }
schemars = { version = "0.8.16" }
seahash = { version = "4.1.0" }
serde = { version = "1.0.197", features = ["derive"] }

View File

@@ -501,7 +501,10 @@ fn directory_moved_to_workspace() -> anyhow::Result<()> {
.with_context(|| "Failed to create __init__.py")?;
std::fs::write(a_original_path.as_std_path(), "").with_context(|| "Failed to create a.py")?;
let sub_a_module = resolve_module(case.db().upcast(), ModuleName::new_static("sub.a").unwrap());
let sub_a_module = resolve_module(
case.db().upcast(),
&ModuleName::new_static("sub.a").unwrap(),
);
assert_eq!(sub_a_module, None);
assert_eq!(
@@ -525,7 +528,11 @@ fn directory_moved_to_workspace() -> anyhow::Result<()> {
.expect("a.py to exist");
// `import sub.a` should now resolve
assert!(resolve_module(case.db().upcast(), ModuleName::new_static("sub.a").unwrap()).is_some());
assert!(resolve_module(
case.db().upcast(),
&ModuleName::new_static("sub.a").unwrap()
)
.is_some());
assert_eq!(
case.collect_package_files(&case.workspace_path("bar.py")),
@@ -544,7 +551,11 @@ fn directory_moved_to_trash() -> anyhow::Result<()> {
])?;
let bar = case.system_file(case.workspace_path("bar.py")).unwrap();
assert!(resolve_module(case.db().upcast(), ModuleName::new_static("sub.a").unwrap()).is_some());
assert!(resolve_module(
case.db().upcast(),
&ModuleName::new_static("sub.a").unwrap()
)
.is_some());
let sub_path = case.workspace_path("sub");
let init_file = case
@@ -569,7 +580,11 @@ fn directory_moved_to_trash() -> anyhow::Result<()> {
case.apply_changes(changes);
// `import sub.a` should no longer resolve
assert!(resolve_module(case.db().upcast(), ModuleName::new_static("sub.a").unwrap()).is_none());
assert!(resolve_module(
case.db().upcast(),
&ModuleName::new_static("sub.a").unwrap()
)
.is_none());
assert!(!init_file.exists(case.db()));
assert!(!a_file.exists(case.db()));
@@ -592,10 +607,14 @@ fn directory_renamed() -> anyhow::Result<()> {
let bar = case.system_file(case.workspace_path("bar.py")).unwrap();
assert!(resolve_module(case.db().upcast(), ModuleName::new_static("sub.a").unwrap()).is_some());
assert!(resolve_module(
case.db().upcast(),
ModuleName::new_static("foo.baz").unwrap()
&ModuleName::new_static("sub.a").unwrap()
)
.is_some());
assert!(resolve_module(
case.db().upcast(),
&ModuleName::new_static("foo.baz").unwrap()
)
.is_none());
@@ -623,11 +642,15 @@ fn directory_renamed() -> anyhow::Result<()> {
case.apply_changes(changes);
// `import sub.a` should no longer resolve
assert!(resolve_module(case.db().upcast(), ModuleName::new_static("sub.a").unwrap()).is_none());
assert!(resolve_module(
case.db().upcast(),
&ModuleName::new_static("sub.a").unwrap()
)
.is_none());
// `import foo.baz` should now resolve
assert!(resolve_module(
case.db().upcast(),
ModuleName::new_static("foo.baz").unwrap()
&ModuleName::new_static("foo.baz").unwrap()
)
.is_some());
@@ -665,7 +688,11 @@ fn directory_deleted() -> anyhow::Result<()> {
let bar = case.system_file(case.workspace_path("bar.py")).unwrap();
assert!(resolve_module(case.db().upcast(), ModuleName::new_static("sub.a").unwrap()).is_some());
assert!(resolve_module(
case.db().upcast(),
&ModuleName::new_static("sub.a").unwrap()
)
.is_some());
let sub_path = case.workspace_path("sub");
@@ -688,7 +715,11 @@ fn directory_deleted() -> anyhow::Result<()> {
case.apply_changes(changes);
// `import sub.a` should no longer resolve
assert!(resolve_module(case.db().upcast(), ModuleName::new_static("sub.a").unwrap()).is_none());
assert!(resolve_module(
case.db().upcast(),
&ModuleName::new_static("sub.a").unwrap()
)
.is_none());
assert!(!init_file.exists(case.db()));
assert!(!a_file.exists(case.db()));
@@ -710,7 +741,7 @@ fn search_path() -> anyhow::Result<()> {
let site_packages = case.root_path().join("site_packages");
assert_eq!(
resolve_module(case.db(), ModuleName::new("a").unwrap()),
resolve_module(case.db(), &ModuleName::new("a").unwrap()),
None
);
@@ -720,7 +751,7 @@ fn search_path() -> anyhow::Result<()> {
case.apply_changes(changes);
assert!(resolve_module(case.db().upcast(), ModuleName::new_static("a").unwrap()).is_some());
assert!(resolve_module(case.db().upcast(), &ModuleName::new_static("a").unwrap()).is_some());
assert_eq!(
case.collect_package_files(&case.workspace_path("bar.py")),
&[case.system_file(case.workspace_path("bar.py")).unwrap()]
@@ -736,7 +767,7 @@ fn add_search_path() -> anyhow::Result<()> {
let site_packages = case.workspace_path("site_packages");
std::fs::create_dir_all(site_packages.as_std_path())?;
assert!(resolve_module(case.db().upcast(), ModuleName::new_static("a").unwrap()).is_none());
assert!(resolve_module(case.db().upcast(), &ModuleName::new_static("a").unwrap()).is_none());
// Register site-packages as a search path.
case.update_search_path_settings(SearchPathConfiguration {
@@ -751,7 +782,7 @@ fn add_search_path() -> anyhow::Result<()> {
case.apply_changes(changes);
assert!(resolve_module(case.db().upcast(), ModuleName::new_static("a").unwrap()).is_some());
assert!(resolve_module(case.db().upcast(), &ModuleName::new_static("a").unwrap()).is_some());
Ok(())
}
@@ -805,7 +836,7 @@ fn changed_versions_file() -> anyhow::Result<()> {
// Unset the custom typeshed directory.
assert_eq!(
resolve_module(case.db(), ModuleName::new("os").unwrap()),
resolve_module(case.db(), &ModuleName::new("os").unwrap()),
None
);
@@ -820,7 +851,7 @@ fn changed_versions_file() -> anyhow::Result<()> {
case.apply_changes(changes);
assert!(resolve_module(case.db(), ModuleName::new("os").unwrap()).is_some());
assert!(resolve_module(case.db(), &ModuleName::new("os").unwrap()).is_some());
Ok(())
}
@@ -1044,7 +1075,7 @@ mod unix {
let baz = resolve_module(
case.db().upcast(),
ModuleName::new_static("bar.baz").unwrap(),
&ModuleName::new_static("bar.baz").unwrap(),
)
.expect("Expected bar.baz to exist in site-packages.");
let baz_workspace = case.workspace_path("bar/baz.py");
@@ -1125,7 +1156,7 @@ mod unix {
let baz = resolve_module(
case.db().upcast(),
ModuleName::new_static("bar.baz").unwrap(),
&ModuleName::new_static("bar.baz").unwrap(),
)
.expect("Expected bar.baz to exist in site-packages.");
let bar_baz = case.workspace_path("bar/baz.py");
@@ -1229,7 +1260,7 @@ mod unix {
let baz = resolve_module(
case.db().upcast(),
ModuleName::new_static("bar.baz").unwrap(),
&ModuleName::new_static("bar.baz").unwrap(),
)
.expect("Expected bar.baz to exist in site-packages.");
let baz_site_packages_path =

View File

@@ -34,6 +34,7 @@ hashbrown = { workspace = true }
smallvec = { workspace = true }
static_assertions = { workspace = true }
test-case = { workspace = true }
memchr = { workspace = true }
[dev-dependencies]
ruff_db = { workspace = true, features = ["os", "testing"] }

View File

@@ -0,0 +1,25 @@
# Assignment with annotations
## Annotation only transparent to local inference
```py
x = 1
x: int
y = x
reveal_type(y) # revealed: Literal[1]
```
## Violates own annotation
```py
x: int = 'foo' # error: [invalid-assignment] "Object of type `Literal["foo"]` is not assignable to `int`"
```
## Violates previous annotation
```py
x: int
x = 'foo' # error: [invalid-assignment] "Object of type `Literal["foo"]` is not assignable to `int`"
```

View File

@@ -0,0 +1,9 @@
# Multi-target assignment
## Basic
```py
x = y = 1
reveal_type(x) # revealed: Literal[1]
reveal_type(y) # revealed: Literal[1]
```

View File

@@ -0,0 +1,32 @@
# Unbound
## Maybe unbound
```py
if flag:
y = 3
x = y
reveal_type(x) # revealed: Unbound | Literal[3]
```
## Unbound
```py
x = foo; foo = 1
reveal_type(x) # revealed: Unbound
```
## Unbound class variable
Class variables can reference global variables unless overridden within the class scope.
```py
x = 1
class C:
y = x
if flag:
x = 2
reveal_type(C.x) # revealed: Unbound | Literal[2]
reveal_type(C.y) # revealed: Literal[1]
```

View File

@@ -0,0 +1,17 @@
# Walrus operator
## Basic
```py
x = (y := 1) + 1
reveal_type(x) # revealed: Literal[2]
reveal_type(y) # revealed: Literal[1]
```
## Walrus self-addition
```py
x = 0
(x := x + 1)
reveal_type(x) # revealed: Literal[1]
```

View File

@@ -0,0 +1,15 @@
# Class attributes
## Union of attributes
```py
if flag:
class C:
x = 1
else:
class C:
x = 2
y = C.x
reveal_type(y) # revealed: Literal[1, 2]
```

View File

@@ -0,0 +1,36 @@
## Binary operations on integers
## Basic Arithmetic
```py
a = 2 + 1
b = a - 4
c = a * b
d = c // 3
e = c / 3
f = 5 % 3
reveal_type(a) # revealed: Literal[3]
reveal_type(b) # revealed: Literal[-1]
reveal_type(c) # revealed: Literal[-3]
reveal_type(d) # revealed: Literal[-1]
reveal_type(e) # revealed: float
reveal_type(f) # revealed: Literal[2]
```
## Division by Zero
```py
# TODO: `a` should be `int` and `e` should be `float` once we support inference.
a = 1 / 0 # error: "Cannot divide object of type `Literal[1]` by zero"
b = 2 // 0 # error: "Cannot floor divide object of type `Literal[2]` by zero"
c = 3 % 0 # error: "Cannot reduce object of type `Literal[3]` modulo zero"
d = int() / 0 # error: "Cannot divide object of type `int` by zero"
e = 1.0 / 0 # error: "Cannot divide object of type `float` by zero"
reveal_type(a) # revealed: float
reveal_type(b) # revealed: int
reveal_type(c) # revealed: int
reveal_type(d) # revealed: @Todo
reveal_type(e) # revealed: @Todo
```

View File

@@ -0,0 +1,21 @@
# Callable instance
## Dunder call
```py
class Multiplier:
def __init__(self, factor: float):
self.factor = factor
def __call__(self, number: float) -> float:
return number * self.factor
a = Multiplier(2.0)(3.0)
class Unit: ...
b = Unit()(3.0) # error: "Object of type `Unit` is not callable"
reveal_type(a) # revealed: float
reveal_type(b) # revealed: Unknown
```

View File

@@ -0,0 +1,8 @@
# Constructor
```py
class Foo: ...
x = Foo()
reveal_type(x) # revealed: Foo
```

View File

@@ -0,0 +1,51 @@
# Call expression
## Simple
```py
def get_int() -> int:
return 42
x = get_int()
reveal_type(x) # revealed: int
```
## Async
```py
async def get_int_async() -> int:
return 42
x = get_int_async()
# TODO: we don't yet support `types.CoroutineType`, should be generic `Coroutine[Any, Any, int]`
reveal_type(x) # revealed: @Todo
```
## Decorated
```py
from typing import Callable
def foo() -> int:
return 42
def decorator(func) -> Callable[[], int]:
return foo
@decorator
def bar() -> str:
return 'bar'
x = bar()
# TODO: should reveal `int`, as the decorator replaces `bar` with `foo`
reveal_type(x) # revealed: @Todo
```
## Invalid callable
```py
nonsense = 123
x = nonsense() # error: "Object of type `Literal[123]` is not callable"
```

View File

@@ -0,0 +1,74 @@
# Unions in calls
## Union of return types
```py
if flag:
def f() -> int:
return 1
else:
def f() -> str:
return 'foo'
x = f()
reveal_type(x) # revealed: int | str
```
## Calling with an unknown union
```py
from nonexistent import f # error: [unresolved-import] "Cannot resolve import `nonexistent`"
if flag:
def f() -> int:
return 1
x = f()
reveal_type(x) # revealed: Unknown | int
```
## Non-callable elements in a union
Calling a union with a non-callable element should emit a diagnostic.
```py
if flag:
f = 1
else:
def f() -> int:
return 1
x = f() # error: "Object of type `Literal[1] | Literal[f]` is not callable (due to union element `Literal[1]`)"
reveal_type(x) # revealed: Unknown | int
```
## Multiple non-callable elements in a union
Calling a union with multiple non-callable elements should mention all of them in the diagnostic.
```py
if flag:
f = 1
elif flag2:
f = 'foo'
else:
def f() -> int:
return 1
x = f() # error: "Object of type `Literal[1] | Literal["foo"] | Literal[f]` is not callable (due to union elements Literal[1], Literal["foo"])"
reveal_type(x) # revealed: Unknown | int
```
## All non-callable union elements
Calling a union with no callable elements can emit a simpler diagnostic.
```py
if flag:
f = 1
else:
f = 'foo'
x = f() # error: "Object of type `Literal[1] | Literal["foo"]` is not callable"
reveal_type(x) # revealed: Unknown
```

View File

@@ -0,0 +1,41 @@
# Comparing integers
## Integer literals
```py
a = 1 == 1 == True
b = 1 == 1 == 2 == 4
c = False < True <= 2 < 3 != 6
d = 1 < 1
e = 1 > 1
f = 1 is 1
g = 1 is not 1
h = 1 is 2
i = 1 is not 7
j = 1 <= "" and 0 < 1
reveal_type(a) # revealed: Literal[True]
reveal_type(b) # revealed: Literal[False]
reveal_type(c) # revealed: Literal[True]
reveal_type(d) # revealed: Literal[False]
reveal_type(e) # revealed: Literal[False]
reveal_type(f) # revealed: bool
reveal_type(g) # revealed: bool
reveal_type(h) # revealed: Literal[False]
reveal_type(i) # revealed: Literal[True]
reveal_type(j) # revealed: @Todo | Literal[True]
```
## Integer instance
```py
# TODO: implement lookup of `__eq__` on typeshed `int` stub.
def int_instance() -> int: ...
a = 1 == int_instance()
b = 9 < int_instance()
c = int_instance() < int_instance()
reveal_type(a) # revealed: @Todo
reveal_type(b) # revealed: bool
reveal_type(c) # revealed: bool
```

View File

@@ -0,0 +1,37 @@
# Non boolean returns
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
- `b = 0 < 1 < A() < 3`
1. `0 < 1 and 1 < A() and A() < 3` - split in N comparison
1. `True` and `bool` and `A` - evaluate outcome types
1. `True` and `bool` and `bool` - evaluate truthiness
1. `bool | A` - union of "true" types
- `c = 10 < 0 < A() < B() < C()` short-circuit to False
```py
from __future__ import annotations
class A:
def __lt__(self, other) -> A: ...
class B:
def __lt__(self, other) -> B: ...
class C:
def __lt__(self, other) -> C: ...
a = A() < B() < C()
b = 0 < 1 < A() < 3
c = 10 < 0 < A() < B() < C()
reveal_type(a) # revealed: A | B
reveal_type(b) # revealed: bool | A
reveal_type(c) # revealed: Literal[False]
```

View File

@@ -0,0 +1,29 @@
# Comparing strings
## String literals
```py
def str_instance() -> str: ...
a = "abc" == "abc"
b = "ab_cd" <= "ab_ce"
c = "abc" in "ab cd"
d = "" not in "hello"
e = "--" is "--"
f = "A" is "B"
g = "--" is not "--"
h = "A" is not "B"
i = str_instance() < "..."
# ensure we're not comparing the interned salsa symbols, which compare by order of declaration.
j = "ab" < "ab_cd"
reveal_type(a) # revealed: Literal[True]
reveal_type(b) # revealed: Literal[True]
reveal_type(c) # revealed: Literal[False]
reveal_type(d) # revealed: Literal[False]
reveal_type(e) # revealed: bool
reveal_type(f) # revealed: Literal[False]
reveal_type(g) # revealed: bool
reveal_type(h) # revealed: Literal[True]
reveal_type(i) # revealed: bool
reveal_type(j) # revealed: Literal[True]
```

View File

@@ -0,0 +1,15 @@
# Unsupported operators
```py
a = 1 in 7 # error: "Operator `in` is not supported for types `Literal[1]` and `Literal[7]`"
b = 0 not in 10 # error: "Operator `not in` is not supported for types `Literal[0]` and `Literal[10]`"
c = object() < 5 # error: "Operator `<` is not supported for types `object` and `Literal[5]`"
# TODO should error, need to check if __lt__ signature is valid for right operand
d = 5 < object()
reveal_type(a) # revealed: bool
reveal_type(b) # revealed: bool
reveal_type(c) # revealed: Unknown
# TODO: should be `Unknown`
reveal_type(d) # revealed: bool
```

View File

@@ -0,0 +1,35 @@
# If expressions
## Simple if-expression
```py
x = 1 if flag else 2
reveal_type(x) # revealed: Literal[1, 2]
```
## If-expression with walrus operator
```py
y = 0
z = 0
x = (y := 1) if flag else (z := 2)
a = y
b = z
reveal_type(x) # revealed: Literal[1, 2]
reveal_type(a) # revealed: Literal[0, 1]
reveal_type(b) # revealed: Literal[0, 2]
```
## Nested if-expression
```py
x = 1 if flag else 2 if flag2 else 3
reveal_type(x) # revealed: Literal[1, 2, 3]
```
## None
```py
x = 1 if flag else None
reveal_type(x) # revealed: Literal[1] | None
```

View File

@@ -0,0 +1,97 @@
# If statements
## Simple if
```py
y = 1
y = 2
if flag:
y = 3
x = y
reveal_type(x) # revealed: Literal[2, 3]
```
## Simple if-elif-else
```py
y = 1
y = 2
if flag:
y = 3
elif flag2:
y = 4
else:
r = y
y = 5
s = y
x = y
reveal_type(x) # revealed: Literal[3, 4, 5]
reveal_type(r) # revealed: Unbound | Literal[2]
reveal_type(s) # revealed: Unbound | Literal[5]
```
## Single symbol across if-elif-else
```py
if flag:
y = 1
elif flag2:
y = 2
else:
y = 3
reveal_type(y) # revealed: Literal[1, 2, 3]
```
## if-elif-else without else assignment
```py
y = 0
if flag:
y = 1
elif flag2:
y = 2
else:
pass
reveal_type(y) # revealed: Literal[0, 1, 2]
```
## if-elif-else with intervening assignment
```py
y = 0
if flag:
y = 1
z = 3
elif flag2:
y = 2
else:
pass
reveal_type(y) # revealed: Literal[0, 1, 2]
```
## Nested if statement
```py
y = 0
if flag:
if flag2:
y = 1
reveal_type(y) # revealed: Literal[0, 1]
```
## if-elif without else
```py
y = 1
y = 2
if flag:
y = 3
elif flag2:
y = 4
x = y
reveal_type(x) # revealed: Literal[2, 3, 4]
```

View File

@@ -0,0 +1,39 @@
# Pattern matching
## With wildcard
```py
match 0:
case 1:
y = 2
case _:
y = 3
reveal_type(y) # revealed: Literal[2, 3]
```
## Without wildcard
```py
match 0:
case 1:
y = 2
case 2:
y = 3
reveal_type(y) # revealed: Unbound | Literal[2, 3]
```
## Basic match
```py
y = 1
y = 2
match 0:
case 1:
y = 3
case 2:
y = 4
reveal_type(y) # revealed: Literal[2, 3, 4]
```

View File

@@ -0,0 +1,39 @@
# Errors while declaring
## Violates previous assignment
```py
x = 1
x: str # error: [invalid-declaration] "Cannot declare type `str` for inferred type `Literal[1]`"
```
## Incompatible declarations
```py
if flag:
x: str
else:
x: int
x = 1 # error: [conflicting-declarations] "Conflicting declared types for `x`: str, int"
```
## Partial declarations
```py
if flag:
x: int
x = 1 # error: [conflicting-declarations] "Conflicting declared types for `x`: Unknown, int"
```
## Incompatible declarations with bad assignment
```py
if flag:
x: str
else:
x: int
# error: [conflicting-declarations]
# error: [invalid-assignment]
x = b'foo'
```

View File

@@ -0,0 +1,55 @@
# Exception Handling
## Single Exception
```py
import re
try:
x
except NameError as e:
reveal_type(e) # revealed: NameError
except re.error as f:
reveal_type(f) # revealed: error
```
## Unknown type in except handler does not cause spurious diagnostic
```py
from nonexistent_module import foo # error: [unresolved-import]
try:
x
except foo as e:
reveal_type(foo) # revealed: Unknown
reveal_type(e) # revealed: Unknown
```
## Multiple Exceptions in a Tuple
```py
EXCEPTIONS = (AttributeError, TypeError)
try:
x
except (RuntimeError, OSError) as e:
reveal_type(e) # revealed: RuntimeError | OSError
except EXCEPTIONS as f:
reveal_type(f) # revealed: AttributeError | TypeError
```
## Dynamic exception types
```py
def foo(x: type[AttributeError], y: tuple[type[OSError], type[RuntimeError]], z: tuple[type[BaseException], ...]):
try:
w
except x as e:
# TODO: should be `AttributeError`
reveal_type(e) # revealed: @Todo
except y as f:
# TODO: should be `OSError | RuntimeError`
reveal_type(f) # revealed: @Todo
except z as g:
# TODO: should be `BaseException`
reveal_type(g) # revealed: @Todo
```

View File

@@ -0,0 +1,32 @@
# Except star
TODO(Alex): Once we support `sys.version_info` branches, we can set `--target-version=py311` in these tests and the inferred type will just be `BaseExceptionGroup`
## Except\* with BaseException
```py
try:
x
except* BaseException as e:
reveal_type(e) # revealed: Unknown | BaseExceptionGroup
```
## Except\* with specific exception
```py
try:
x
except* OSError as e:
# TODO(Alex): more precise would be `ExceptionGroup[OSError]`
reveal_type(e) # revealed: Unknown | BaseExceptionGroup
```
## Except\* with multiple exceptions
```py
try:
x
except* (TypeError, AttributeError) as e:
#TODO(Alex): more precise would be `ExceptionGroup[TypeError | AttributeError]`.
reveal_type(e) # revealed: Unknown | BaseExceptionGroup
```

View File

@@ -0,0 +1,151 @@
# Expressions
## OR
```py
def foo() -> str:
pass
a = True or False
b = 'x' or 'y' or 'z'
c = '' or 'y' or 'z'
d = False or 'z'
e = False or True
f = False or False
g = foo() or False
h = foo() or True
reveal_type(a) # revealed: Literal[True]
reveal_type(b) # revealed: Literal["x"]
reveal_type(c) # revealed: Literal["y"]
reveal_type(d) # revealed: Literal["z"]
reveal_type(e) # revealed: Literal[True]
reveal_type(f) # revealed: Literal[False]
reveal_type(g) # revealed: str | Literal[False]
reveal_type(h) # revealed: str | Literal[True]
```
## AND
```py
def foo() -> str:
pass
a = True and False
b = False and True
c = foo() and False
d = foo() and True
e = 'x' and 'y' and 'z'
f = 'x' and 'y' and ''
g = '' and 'y'
reveal_type(a) # revealed: Literal[False]
reveal_type(b) # revealed: Literal[False]
reveal_type(c) # revealed: str | Literal[False]
reveal_type(d) # revealed: str | Literal[True]
reveal_type(e) # revealed: Literal["z"]
reveal_type(f) # revealed: Literal[""]
reveal_type(g) # revealed: Literal[""]
```
## Simple function calls to bool
```py
def returns_bool() -> bool:
return True
if returns_bool():
x = True
else:
x = False
reveal_type(x) # revealed: bool
```
## Complex
```py
def foo() -> str:
pass
a = "x" and "y" or "z"
b = "x" or "y" and "z"
c = "" and "y" or "z"
d = "" or "y" and "z"
e = "x" and "y" or ""
f = "x" or "y" and ""
reveal_type(a) # revealed: Literal["y"]
reveal_type(b) # revealed: Literal["x"]
reveal_type(c) # revealed: Literal["z"]
reveal_type(d) # revealed: Literal["z"]
reveal_type(e) # revealed: Literal["y"]
reveal_type(f) # revealed: Literal["x"]
```
## `bool()` function
## Evaluates to builtin
```py path=a.py
redefined_builtin_bool = bool
def my_bool(x)-> bool: pass
```
```py
from a import redefined_builtin_bool, my_bool
a = redefined_builtin_bool(0)
b = my_bool(0)
reveal_type(a) # revealed: Literal[False]
reveal_type(b) # revealed: bool
```
## Truthy values
```py
a = bool(1)
b = bool((0,))
c = bool("NON EMPTY")
d = bool(True)
def foo(): pass
e = bool(foo)
reveal_type(a) # revealed: Literal[True]
reveal_type(b) # revealed: Literal[True]
reveal_type(c) # revealed: Literal[True]
reveal_type(d) # revealed: Literal[True]
reveal_type(e) # revealed: Literal[True]
```
## Falsy values
```py
a = bool(0)
b = bool(())
c = bool(None)
d = bool("")
e = bool(False)
f = bool()
reveal_type(a) # revealed: Literal[False]
reveal_type(b) # revealed: Literal[False]
reveal_type(c) # revealed: Literal[False]
reveal_type(d) # revealed: Literal[False]
reveal_type(e) # revealed: Literal[False]
reveal_type(f) # revealed: Literal[False]
```
## Ambiguous values
```py
a = bool([])
b = bool({})
c = bool(set())
reveal_type(a) # revealed: bool
reveal_type(b) # revealed: bool
reveal_type(c) # revealed: bool
```

View File

@@ -0,0 +1,23 @@
# Structures
## Class import following
```py
from b import C as D; E = D
reveal_type(E) # revealed: Literal[C]
```
```py path=b.py
class C: pass
```
## Module member resolution
```py
import b; D = b.C
reveal_type(D) # revealed: Literal[C]
```
```py path=b.py
class C: pass
```

View File

@@ -0,0 +1,6 @@
# Importing builtin module
```py
import builtins; x = builtins.copyright
reveal_type(x) # revealed: Literal[copyright]
```

View File

@@ -0,0 +1,42 @@
# Conditional imports
## Reimport
```py path=c.py
def f(): ...
```
```py path=b.py
if flag:
from c import f
else:
def f(): ...
```
```py
# TODO we should not emit this error
from b import f # error: [invalid-assignment] "Object of type `Literal[f, f]` is not assignable to `Literal[f, f]`"
# TODO: We should disambiguate in such cases, showing `Literal[b.f, c.f]`.
reveal_type(f) # revealed: Literal[f, f]
```
## Reimport with stub declaration
When we have a declared type in one path and only an inferred-from-definition type in the other, we
should still be able to unify those:
```py path=c.pyi
x: int
```
```py path=b.py
if flag:
from c import x
else:
x = 1
```
```py
from b import x
reveal_type(x) # revealed: int
```

View File

@@ -0,0 +1,47 @@
# Unresolved Imports
## Unresolved import statement
```py
import bar # error: "Cannot resolve import `bar`"
```
## Unresolved import from statement
```py
from bar import baz # error: "Cannot resolve import `bar`"
```
## Unresolved import from resolved module
```py path=a.py
```
```py
from a import thing # error: "Module `a` has no member `thing`"
```
## Resolved import of symbol from unresolved import
```py path=a.py
import foo as foo # error: "Cannot resolve import `foo`"
```
Importing the unresolved import into a second file should not trigger an additional "unresolved
import" violation:
```py
from a import foo
```
## No implicit shadowing error
```py path=b.py
x: int
```
```py
from b import x
x = 'foo' # error: "Object of type `Literal["foo"]"
```

View File

@@ -0,0 +1,133 @@
# Relative
## Non-existent
```py path=package/__init__.py
```
```py path=package/bar.py
from .foo import X # error: [unresolved-import]
reveal_type(X) # revealed: Unknown
```
## Simple
```py path=package/__init__.py
```
```py path=package/foo.py
X = 42
```
```py path=package/bar.py
from .foo import X
reveal_type(X) # revealed: Literal[42]
```
## Dotted
```py path=package/__init__.py
```
```py path=package/foo/bar/baz.py
X = 42
```
```py path=package/bar.py
from .foo.bar.baz import X
reveal_type(X) # revealed: Literal[42]
```
## Bare to package
```py path=package/__init__.py
X = 42
```
```py path=package/bar.py
from . import X
reveal_type(X) # revealed: Literal[42]
```
## Non-existent + bare to package
```py path=package/bar.py
from . import X # error: [unresolved-import]
reveal_type(X) # revealed: Unknown
```
## Dunder init
```py path=package/__init__.py
from .foo import X
reveal_type(X) # revealed: Literal[42]
```
```py path=package/foo.py
X = 42
```
## Non-existent + dunder init
```py path=package/__init__.py
from .foo import X # error: [unresolved-import]
reveal_type(X) # revealed: Unknown
```
## Long relative import
```py path=package/__init__.py
```
```py path=package/foo.py
X = 42
```
```py path=package/subpackage/subsubpackage/bar.py
from ...foo import X
reveal_type(X) # revealed: Literal[42]
```
## Unbound symbol
```py path=package/__init__.py
```
```py path=package/foo.py
x
```
```py path=package/bar.py
from .foo import x # error: [unresolved-import]
reveal_type(x) # revealed: Unknown
```
## Bare to module
```py path=package/__init__.py
```
```py path=package/foo.py
X = 42
```
```py path=package/bar.py
# TODO: support submodule imports
from . import foo # error: [unresolved-import]
y = foo.X
# TODO: should be `Literal[42]`
reveal_type(y) # revealed: Unknown
```
## Non-existent + bare to module
```py path=package/__init__.py
```
```py path=package/bar.py
# TODO: submodule imports possibly not supported right now?
from . import foo # error: [unresolved-import]
reveal_type(foo) # revealed: Unknown
```

View File

@@ -0,0 +1,25 @@
# Stubs
## Import from stub declaration
```py
from b import x
y = x
reveal_type(y) # revealed: int
```
```py path=b.pyi
x: int
```
## Import from non-stub with declaration and definition
```py
from b import x
y = x
reveal_type(y) # revealed: int
```
```py path=b.py
x: int = 1
```

View File

@@ -0,0 +1,8 @@
# Boolean literals
```py
x = True
y = False
reveal_type(x) # revealed: Literal[True]
reveal_type(y) # revealed: Literal[False]
```

View File

@@ -0,0 +1,8 @@
# Dictionaries
## Empty dictionary
```py
x = {}
reveal_type(x) # revealed: dict
```

View File

@@ -0,0 +1,8 @@
# Lists
## Empty list
```py
x = []
reveal_type(x) # revealed: list
```

View File

@@ -0,0 +1,8 @@
# Sets
## Basic set
```py
x = {1, 2}
reveal_type(x) # revealed: set
```

View File

@@ -0,0 +1,20 @@
# Tuples
## Empty tuple
```py
x = ()
reveal_type(x) # revealed: tuple[()]
```
## Heterogeneous tuple
```py
x = (1, 'a')
y = (1, (2, 3))
z = (x, 2)
reveal_type(x) # revealed: tuple[Literal[1], Literal["a"]]
reveal_type(y) # revealed: tuple[Literal[1], tuple[Literal[2], Literal[3]]]
reveal_type(z) # revealed: tuple[tuple[Literal[1], Literal["a"]], Literal[2]]
```

View File

@@ -0,0 +1,7 @@
# Complex literals
## Complex numbers
```py
reveal_type(2j) # revealed: complex
```

View File

@@ -0,0 +1,44 @@
# f-strings
## Expression
```py
x = 0
y = str()
z = False
a = f'hello'
b = f'h {x}'
c = 'one ' f'single ' f'literal'
d = 'first ' f'second({b})' f' third'
e = f'-{y}-'
f = f'-{y}-' f'--' '--'
g = f'{z} == {False} is {True}'
reveal_type(a) # revealed: Literal["hello"]
reveal_type(b) # revealed: Literal["h 0"]
reveal_type(c) # revealed: Literal["one single literal"]
reveal_type(d) # revealed: Literal["first second(h 0) third"]
reveal_type(e) # revealed: str
reveal_type(f) # revealed: str
reveal_type(g) # revealed: Literal["False == False is True"]
```
## Conversion Flags
```py
string = 'hello'
a = f'{string!r}'
# TODO: should be `Literal["'hello'"]`
reveal_type(a) # revealed: str
```
## Format Specifiers
```py
a = f'{1:02}'
# TODO: should be `Literal["01"]`
reveal_type(a) # revealed: str
```

View File

@@ -0,0 +1,7 @@
# Float literals
## Basic
```py
reveal_type(1.0) # revealed: float
```

View File

@@ -0,0 +1,56 @@
# Integer literals
## Literals
We can infer an integer literal type:
```py
reveal_type(1) # revealed: Literal[1]
```
## Variable
```py
x = 1
reveal_type(x) # revealed: Literal[1]
```
## Overflow
We only track integer literals within the range of an i64:
```py
reveal_type(9223372036854775808) # revealed: int
```
## Big int
We don't support big integer literals; we just infer `int` type instead:
```py
x = 10_000_000_000_000_000_000
reveal_type(x) # revealed: int
```
## Negated
```py
x = -1
y = -1234567890987654321
z = --987
reveal_type(x) # revealed: Literal[-1]
reveal_type(y) # revealed: Literal[-1234567890987654321]
reveal_type(z) # revealed: Literal[987]
```
## Floats
```py
reveal_type(1.0) # revealed: float
```
## Complex
```py
reveal_type(2j) # revealed: complex
```

View File

@@ -0,0 +1,26 @@
# String literals
## Simple
```py
w = "Hello"
x = 'world'
y = "Guten " + 'tag'
z = 'bon ' + "jour"
reveal_type(w) # revealed: Literal["Hello"]
reveal_type(x) # revealed: Literal["world"]
reveal_type(y) # revealed: Literal["Guten tag"]
reveal_type(z) # revealed: Literal["bon jour"]
```
## Nested Quotes
```py
x = 'I say "hello" to you'
y = "You say \"hey\" back"
z = 'No "closure here'
reveal_type(x) # revealed: Literal["I say \"hello\" to you"]
reveal_type(y) # revealed: Literal["You say \"hey\" back"]
reveal_type(z) # revealed: Literal["No \"closure here"]
```

View File

@@ -0,0 +1,41 @@
# Async
Async `for` loops do not work according to the synchronous iteration protocol.
## Invalid async for loop
```py
async def foo():
class Iterator:
def __next__(self) -> int:
return 42
class Iterable:
def __iter__(self) -> Iterator:
return Iterator()
async for x in Iterator():
pass
# TODO
reveal_type(x) # revealed: Unbound | @Todo
```
## Basic async for loop
```py
async def foo():
class IntAsyncIterator:
async def __anext__(self) -> int:
return 42
class IntAsyncIterable:
def __aiter__(self) -> IntAsyncIterator:
return IntAsyncIterator()
#TODO(Alex): async iterables/iterators!
async for x in IntAsyncIterable():
pass
reveal_type(x) # revealed: Unbound | @Todo
```

View File

@@ -0,0 +1,134 @@
# For loops
## Basic `for` loop
```py
class IntIterator:
def __next__(self) -> int:
return 42
class IntIterable:
def __iter__(self) -> IntIterator:
return IntIterator()
for x in IntIterable():
pass
reveal_type(x) # revealed: Unbound | int
```
## With previous definition
```py
class IntIterator:
def __next__(self) -> int:
return 42
class IntIterable:
def __iter__(self) -> IntIterator:
return IntIterator()
x = 'foo'
for x in IntIterable():
pass
reveal_type(x) # revealed: Literal["foo"] | int
```
## With `else` (no break)
```py
class IntIterator:
def __next__(self) -> int:
return 42
class IntIterable:
def __iter__(self) -> IntIterator:
return IntIterator()
for x in IntIterable():
pass
else:
x = 'foo'
reveal_type(x) # revealed: Literal["foo"]
```
## May `break`
```py
class IntIterator:
def __next__(self) -> int:
return 42
class IntIterable:
def __iter__(self) -> IntIterator:
return IntIterator()
for x in IntIterable():
if x > 5:
break
else:
x = 'foo'
reveal_type(x) # revealed: int | Literal["foo"]
```
## With old-style iteration protocol
```py
class OldStyleIterable:
def __getitem__(self, key: int) -> int:
return 42
for x in OldStyleIterable():
pass
reveal_type(x) # revealed: Unbound | int
```
## With heterogeneous tuple
```py
for x in (1, 'a', b'foo'):
pass
reveal_type(x) # revealed: Unbound | Literal[1] | Literal["a"] | Literal[b"foo"]
```
## With non-callable iterator
```py
class NotIterable:
if flag:
__iter__ = 1
else:
__iter__ = None
for x in NotIterable(): # error: "Object of type `NotIterable` is not iterable"
pass
reveal_type(x) # revealed: Unbound | Unknown
```
## Invalid iterable
```py
nonsense = 123
for x in nonsense: # error: "Object of type `Literal[123]` is not iterable"
pass
```
## New over old style iteration protocol
```py
class NotIterable:
def __getitem__(self, key: int) -> int:
return 42
__iter__ = None
for x in NotIterable(): # error: "Object of type `NotIterable` is not iterable"
pass
```

View File

@@ -0,0 +1,18 @@
# Iterators
## Yield must be iterable
```py
class NotIterable: pass
class Iterator:
def __next__(self) -> int:
return 42
class Iterable:
def __iter__(self) -> Iterator: ...
def generator_function():
yield from Iterable()
yield from NotIterable() # error: "Object of type `NotIterable` is not iterable"
```

View File

@@ -0,0 +1,43 @@
# While loops
## Basic While Loop
```py
x = 1
while flag:
x = 2
reveal_type(x) # revealed: Literal[1, 2]
```
## While with else (no break)
```py
x = 1
while flag:
x = 2
else:
y = x
x = 3
reveal_type(x) # revealed: Literal[3]
reveal_type(y) # revealed: Literal[1, 2]
```
## While with Else (may break)
```py
x = 1
y = 0
while flag:
x = 2
if flag2:
y = 4
break
else:
y = x
x = 3
reveal_type(x) # revealed: Literal[2, 3]
reveal_type(y) # revealed: Literal[1, 2, 4]
```

View File

@@ -0,0 +1,29 @@
# Narrowing for `is` conditionals
## `is None`
```py
x = None if flag else 1
if x is None:
# TODO the following should be simplified to 'None'
reveal_type(x) # revealed: None | Literal[1] & None
reveal_type(x) # revealed: None | Literal[1]
```
## `is` for other types
```py
class A:
...
x = A()
y = x if flag else None
if y is x:
# TODO the following should be simplified to 'A'
reveal_type(y) # revealed: A | None & A
reveal_type(y) # revealed: A | None
```

View File

@@ -0,0 +1,40 @@
# Narrowing for `is not` conditionals
## `is not None`
The type guard removes `None` from the union type:
```py
x = None if flag else 1
if x is not None:
reveal_type(x) # revealed: Literal[1]
reveal_type(x) # revealed: None | Literal[1]
```
## `is not` for other singleton types
```py
x = True if flag else False
reveal_type(x) # revealed: bool
if x is not False:
# TODO the following should be `Literal[True]`
reveal_type(x) # revealed: bool & ~Literal[False]
```
## `is not` for non-singleton types
Non-singleton types should *not* narrow the type: two instances of a
non-singleton class may occupy different addresses in memory even if
they compare equal.
```py
x = [1]
y = [1]
if x is not y:
# TODO: should include type parameter: list[int]
reveal_type(x) # revealed: list
```

View File

@@ -0,0 +1,17 @@
# Narrowing for `match` statements
## Single `match` pattern
```py
x = None if flag else 1
reveal_type(x) # revealed: None | Literal[1]
y = 0
match x:
case None:
y = x
# TODO intersection simplification: should be just Literal[0] | None
reveal_type(y) # revealed: Literal[0] | None | Literal[1] & None
```

View File

@@ -0,0 +1,9 @@
# `is not None` narrowing
```py
x = None if flag else 1
if x is not None:
reveal_type(x) # revealed: Literal[1]
reveal_type(x) # revealed: None | Literal[1]
```

View File

@@ -1,35 +0,0 @@
# Numbers
## Integers
### Literals
We can infer an integer literal type:
```py
reveal_type(1) # revealed: Literal[1]
```
### Overflow
We only track integer literals within the range of an i64:
```py
reveal_type(9223372036854775808) # revealed: int
```
## Floats
There aren't literal float types, but we infer the general float type:
```py
reveal_type(1.0) # revealed: float
```
## Complex
Same for complex:
```py
reveal_type(2j) # revealed: complex
```

View File

@@ -0,0 +1,17 @@
# Classes shadowing
## Implicit error
```py
class C: pass
C = 1 # error: "Implicit shadowing of class `C`; annotate to make it explicit if this is intentional"
```
## Explicit
No diagnostic is raised in the case of explicit shadowing:
```py
class C: pass
C: int = 1
```

View File

@@ -0,0 +1,24 @@
# Function shadowing
## Parameter
Parameter `x` of type `str` is shadowed and reassigned with a new `int` value inside the function. No diagnostics should be generated.
```py path=a.py
def f(x: str):
x: int = int(x)
```
## Implicit error
```py path=a.py
def f(): pass
f = 1 # error: "Implicit shadowing of function `f`; annotate to make it explicit if this is intentional"
```
## Explicit shadowing
```py path=a.py
def f(): pass
f: int = 1
```

View File

@@ -0,0 +1,11 @@
# Shadwing declaration
## Shadow after incompatible declarations is OK
```py
if flag:
x: str
else:
x: int
x: bytes = b'foo'
```

View File

@@ -0,0 +1,10 @@
# Class defenitions in stubs
## Cyclical class definition
In type stubs, classes can reference themselves in their base class definitions. For example, in `typeshed`, we have `class str(Sequence[str]): ...`.
```py path=a.pyi
class C(C): ...
reveal_type(C) # revealed: Literal[C]
```

View File

@@ -0,0 +1,15 @@
# Bytes subscript
## Simple
```py
w = b'red' b'knot'
x = b'hello'
y = b'world' + b'!'
z = b'\xff\x00'
reveal_type(w) # revealed: Literal[b"redknot"]
reveal_type(x) # revealed: Literal[b"hello"]
reveal_type(y) # revealed: Literal[b"world!"]
reveal_type(z) # revealed: Literal[b"\xff\x00"]
```

View File

@@ -0,0 +1,92 @@
# Class subscript
## Class getitem unbound
```py
class NotSubscriptable: pass
a = NotSubscriptable[0] # error: "Cannot subscript object of type `Literal[NotSubscriptable]` with no `__class_getitem__` method"
```
## Class getitem
```py
class Identity:
def __class_getitem__(cls, item: int) -> str:
return item
a = Identity[0]
reveal_type(a) # revealed: str
```
## Class getitem union
```py
flag = True
class Identity:
if flag:
def __class_getitem__(cls, item: int) -> str:
return item
else:
def __class_getitem__(cls, item: int) -> int:
return item
a = Identity[0]
reveal_type(a) # revealed: str | int
```
## Class getitem with class union
```py
flag = True
class Identity1:
def __class_getitem__(cls, item: int) -> str:
return item
class Identity2:
def __class_getitem__(cls, item: int) -> int:
return item
if flag:
a = Identity1
else:
a = Identity2
b = a[0]
reveal_type(a) # revealed: Literal[Identity1, Identity2]
reveal_type(b) # revealed: str | int
```
## Class getitem with unbound method union
```py
flag = True
if flag:
class Identity:
def __class_getitem__(self, x: int) -> str:
pass
else:
class Identity: pass
a = Identity[42] # error: [call-non-callable] "Method `__class_getitem__` of type `Literal[__class_getitem__] | Unbound` is not callable on object of type `Literal[Identity, Identity]`"
reveal_type(a) # revealed: str | Unknown
```
## TODO: Class getitem non-class union
```py
flag = True
if flag:
class Identity:
def __class_getitem__(self, x: int) -> str:
pass
else:
Identity = 1
a = Identity[42] # error: "Cannot subscript object of type `Literal[Identity] | Literal[1]` with no `__getitem__` method"
# TODO: should _probably_ emit `str | Unknown`
reveal_type(a) # revealed: Unknown
```

View File

@@ -0,0 +1,45 @@
# Instance subscript
## Getitem unbound
```py
class NotSubscriptable: pass
a = NotSubscriptable()[0] # error: "Cannot subscript object of type `NotSubscriptable` with no `__getitem__` method"
```
## Getitem not callable
```py
class NotSubscriptable:
__getitem__ = None
a = NotSubscriptable()[0] # error: "Method `__getitem__` of type `None` is not callable on object of type `NotSubscriptable`"
```
## Valid getitem
```py
class Identity:
def __getitem__(self, index: int) -> int:
return index
a = Identity()[0]
reveal_type(a) # revealed: int
```
## Getitem union
```py
flag = True
class Identity:
if flag:
def __getitem__(self, index: int) -> int:
return index
else:
def __getitem__(self, index: int) -> str:
return str(index)
a = Identity()[0]
reveal_type(a) # revealed: int | str
```

View File

@@ -0,0 +1,32 @@
# Subscript on strings
## Simple
```py
s = 'abcde'
a = s[0]
b = s[1]
c = s[-1]
d = s[-2]
e = s[8] # error: [index-out-of-bounds] "Index 8 is out of bounds for string `Literal["abcde"]` with length 5"
f = s[-8] # error: [index-out-of-bounds] "Index -8 is out of bounds for string `Literal["abcde"]` with length 5"
reveal_type(a) # revealed: Literal["a"]
reveal_type(b) # revealed: Literal["b"]
reveal_type(c) # revealed: Literal["e"]
reveal_type(d) # revealed: Literal["d"]
reveal_type(e) # revealed: Unknown
reveal_type(f) # revealed: Unknown
```
## Function return
```py
def add(x: int, y: int) -> int:
return x + y
a = 'abcde'[add(0, 1)]
# TODO: Support overloads... Should be `str`
reveal_type(a) # revealed: @Todo
```

View File

@@ -0,0 +1,21 @@
# Tuple subscripts
## Basic
```py
t = (1, 'a', 'b')
a = t[0]
b = t[1]
c = t[-1]
d = t[-2]
e = t[4] # error: [index-out-of-bounds]
f = t[-4] # error: [index-out-of-bounds]
reveal_type(a) # revealed: Literal[1]
reveal_type(b) # revealed: Literal["a"]
reveal_type(c) # revealed: Literal["b"]
reveal_type(d) # revealed: Literal["a"]
reveal_type(e) # revealed: Unknown
reveal_type(f) # revealed: Unknown
```

View File

@@ -0,0 +1,37 @@
# Unary Operations
## Unary Addition
```py
a = +0
b = +1
c = +True
reveal_type(a) # revealed: Literal[0]
reveal_type(b) # revealed: Literal[1]
reveal_type(c) # revealed: Literal[1]
```
## Unary Subtraction
```py
a = -0
b = -1
c = -True
reveal_type(a) # revealed: Literal[0]
reveal_type(b) # revealed: Literal[-1]
reveal_type(c) # revealed: Literal[-1]
```
## Unary Bitwise Inversion
```py
a = ~0
b = ~1
c = ~True
reveal_type(a) # revealed: Literal[-1]
reveal_type(b) # revealed: Literal[-2]
reveal_type(c) # revealed: Literal[-2]
```

View File

@@ -0,0 +1,149 @@
# Unary not
## None
```py
a = not None
b = not not None
reveal_type(a) # revealed: Literal[True]
reveal_type(b) # revealed: Literal[False]
```
## Function
```py
from typing import reveal_type
def f():
return 1
a = not f
b = not reveal_type
reveal_type(a) # revealed: Literal[False]
# TODO Unknown should not be part of the type of typing.reveal_type
# reveal_type(b) revealed: Literal[False]
```
## Module
```py
import b; import warnings
x = not b
z = not warnings
reveal_type(x) # revealed: Literal[False]
reveal_type(z) # revealed: Literal[False]
```
```py path=b.py
y = 1
```
## Union
```py
if flag:
p = 1
q = 3.3
r = "hello"
s = "world"
t = 0
else:
p = "hello"
q = 4
r = ""
s = 0
t = ""
a = not p
b = not q
c = not r
d = not s
e = not t
reveal_type(a) # revealed: Literal[False]
reveal_type(b) # revealed: bool
reveal_type(c) # revealed: bool
reveal_type(d) # revealed: bool
reveal_type(e) # revealed: Literal[True]
```
## Integer literal
```py
a = not 1
b = not 1234567890987654321
e = not 0
x = not -1
y = not -1234567890987654321
z = not --987
reveal_type(a) # revealed: Literal[False]
reveal_type(b) # revealed: Literal[False]
reveal_type(e) # revealed: Literal[True]
reveal_type(x) # revealed: Literal[False]
reveal_type(y) # revealed: Literal[False]
reveal_type(z) # revealed: Literal[False]
```
## Boolean literal
```py
w = True
x = False
y = not w
z = not x
reveal_type(w) # revealed: Literal[True]
reveal_type(x) # revealed: Literal[False]
reveal_type(y) # revealed: Literal[False]
reveal_type(z) # revealed: Literal[True]
```
## String literal
```py
a = not "hello"
b = not ""
c = not "0"
d = not "hello" + "world"
reveal_type(a) # revealed: Literal[False]
reveal_type(b) # revealed: Literal[True]
reveal_type(c) # revealed: Literal[False]
reveal_type(d) # revealed: Literal[False]
```
## Bytes literal
```py
a = not b"hello"
b = not b""
c = not b"0"
d = not b"hello" + b"world"
reveal_type(a) # revealed: Literal[False]
reveal_type(b) # revealed: Literal[True]
reveal_type(c) # revealed: Literal[False]
reveal_type(d) # revealed: Literal[False]
```
## Tuple
```py
a = not (1,)
b = not (1, 2)
c = not (1, 2, 3)
d = not ()
e = not ("hello",)
f = not (1, "hello")
reveal_type(a) # revealed: Literal[False]
reveal_type(b) # revealed: Literal[False]
reveal_type(c) # revealed: Literal[False]
reveal_type(d) # revealed: Literal[True]
reveal_type(e) # revealed: Literal[False]
reveal_type(f) # revealed: Literal[False]
```

View File

@@ -0,0 +1,273 @@
# Unpacking
## Tuple
### Simple tuple
```py
(a, b, c) = (1, 2, 3)
reveal_type(a) # revealed: Literal[1]
reveal_type(b) # revealed: Literal[2]
reveal_type(c) # revealed: Literal[3]
```
### Simple list
```py
[a, b, c] = (1, 2, 3)
reveal_type(a) # revealed: Literal[1]
reveal_type(b) # revealed: Literal[2]
reveal_type(c) # revealed: Literal[3]
```
### Simple mixed
```py
[a, (b, c), d] = (1, (2, 3), 4)
reveal_type(a) # revealed: Literal[1]
reveal_type(b) # revealed: Literal[2]
reveal_type(c) # revealed: Literal[3]
reveal_type(d) # revealed: Literal[4]
```
### Multiple assignment
```py
a, b = c = 1, 2
reveal_type(a) # revealed: Literal[1]
reveal_type(b) # revealed: Literal[2]
reveal_type(c) # revealed: tuple[Literal[1], Literal[2]]
```
### Nested tuple with unpacking
```py
(a, (b, c), d) = (1, (2, 3), 4)
reveal_type(a) # revealed: Literal[1]
reveal_type(b) # revealed: Literal[2]
reveal_type(c) # revealed: Literal[3]
reveal_type(d) # revealed: Literal[4]
```
### Nested tuple without unpacking
```py
(a, b, c) = (1, (2, 3), 4)
reveal_type(a) # revealed: Literal[1]
reveal_type(b) # revealed: tuple[Literal[2], Literal[3]]
reveal_type(c) # revealed: Literal[4]
```
### Uneven unpacking (1)
```py
# TODO: Add diagnostic (there aren't enough values to unpack)
(a, b, c) = (1, 2)
reveal_type(a) # revealed: Literal[1]
reveal_type(b) # revealed: Literal[2]
reveal_type(c) # revealed: Unknown
```
### Uneven unpacking (2)
```py
# TODO: Add diagnostic (too many values to unpack)
(a, b) = (1, 2, 3)
reveal_type(a) # revealed: Literal[1]
reveal_type(b) # revealed: Literal[2]
```
### Starred expression (1)
```py
# TODO: Add diagnostic (need more values to unpack)
# TODO: Remove 'not-iterable' diagnostic
[a, *b, c, d] = (1, 2) # error: "Object of type `None` is not iterable"
reveal_type(a) # revealed: Literal[1]
# TODO: Should be list[Any] once support for assigning to starred expression is added
reveal_type(b) # revealed: @Todo
reveal_type(c) # revealed: Literal[2]
reveal_type(d) # revealed: Unknown
```
### Starred expression (2)
```py
[a, *b, c] = (1, 2) # error: "Object of type `None` is not iterable"
reveal_type(a) # revealed: Literal[1]
# TODO: Should be list[Any] once support for assigning to starred expression is added
reveal_type(b) # revealed: @Todo
reveal_type(c) # revealed: Literal[2]
```
### Starred expression (3)
```py
# TODO: Remove 'not-iterable' diagnostic
[a, *b, c] = (1, 2, 3) # error: "Object of type `None` is not iterable"
reveal_type(a) # revealed: Literal[1]
# TODO: Should be list[int] once support for assigning to starred expression is added
reveal_type(b) # revealed: @Todo
reveal_type(c) # revealed: Literal[3]
```
### Starred expression (4)
```py
# TODO: Remove 'not-iterable' diagnostic
[a, *b, c, d] = (1, 2, 3, 4, 5, 6) # error: "Object of type `None` is not iterable"
reveal_type(a) # revealed: Literal[1]
# TODO: Should be list[int] once support for assigning to starred expression is added
reveal_type(b) # revealed: @Todo
reveal_type(c) # revealed: Literal[5]
reveal_type(d) # revealed: Literal[6]
```
### Starred expression (5)
```py
# TODO: Remove 'not-iterable' diagnostic
[a, b, *c] = (1, 2, 3, 4) # error: "Object of type `None` is not iterable"
reveal_type(a) # revealed: Literal[1]
reveal_type(b) # revealed: Literal[2]
# TODO: Should be list[int] once support for assigning to starred expression is added
reveal_type(c) # revealed: @Todo
```
### Non-iterable unpacking
TODO: Remove duplicate diagnostics. This is happening because for a sequence-like
assignment target, multiple definitions are created and the inference engine runs
on each of them which results in duplicate diagnostics.
```py
# error: "Object of type `Literal[1]` is not iterable"
# error: "Object of type `Literal[1]` is not iterable"
a, b = 1
reveal_type(a) # revealed: Unknown
reveal_type(b) # revealed: Unknown
```
### Custom iterator unpacking
```py
class Iterator:
def __next__(self) -> int:
return 42
class Iterable:
def __iter__(self) -> Iterator:
return Iterator()
(a, b) = Iterable()
reveal_type(a) # revealed: int
reveal_type(b) # revealed: int
```
### Custom iterator unpacking nested
```py
class Iterator:
def __next__(self) -> int:
return 42
class Iterable:
def __iter__(self) -> Iterator:
return Iterator()
(a, (b, c), d) = (1, Iterable(), 2)
reveal_type(a) # revealed: Literal[1]
reveal_type(b) # revealed: int
reveal_type(c) # revealed: int
reveal_type(d) # revealed: Literal[2]
```
## String
### Simple unpacking
```py
a, b = 'ab'
reveal_type(a) # revealed: LiteralString
reveal_type(b) # revealed: LiteralString
```
### Uneven unpacking (1)
```py
# TODO: Add diagnostic (there aren't enough values to unpack)
a, b, c = 'ab'
reveal_type(a) # revealed: LiteralString
reveal_type(b) # revealed: LiteralString
reveal_type(c) # revealed: Unknown
```
### Uneven unpacking (2)
```py
# TODO: Add diagnostic (too many values to unpack)
a, b = 'abc'
reveal_type(a) # revealed: LiteralString
reveal_type(b) # revealed: LiteralString
```
### Starred expression (1)
```py
# TODO: Add diagnostic (need more values to unpack)
# TODO: Remove 'not-iterable' diagnostic
(a, *b, c, d) = "ab" # error: "Object of type `None` is not iterable"
reveal_type(a) # revealed: LiteralString
# TODO: Should be list[LiteralString] once support for assigning to starred expression is added
reveal_type(b) # revealed: @Todo
reveal_type(c) # revealed: LiteralString
reveal_type(d) # revealed: Unknown
```
### Starred expression (2)
```py
(a, *b, c) = "ab" # error: "Object of type `None` is not iterable"
reveal_type(a) # revealed: LiteralString
# TODO: Should be list[Any] once support for assigning to starred expression is added
reveal_type(b) # revealed: @Todo
reveal_type(c) # revealed: LiteralString
```
### Starred expression (3)
```py
# TODO: Remove 'not-iterable' diagnostic
(a, *b, c) = "abc" # error: "Object of type `None` is not iterable"
reveal_type(a) # revealed: LiteralString
# TODO: Should be list[LiteralString] once support for assigning to starred expression is added
reveal_type(b) # revealed: @Todo
reveal_type(c) # revealed: LiteralString
```
### Starred expression (4)
```py
# TODO: Remove 'not-iterable' diagnostic
(a, *b, c, d) = "abcdef" # error: "Object of type `None` is not iterable"
reveal_type(a) # revealed: LiteralString
# TODO: Should be list[LiteralString] once support for assigning to starred expression is added
reveal_type(b) # revealed: @Todo
reveal_type(c) # revealed: LiteralString
reveal_type(d) # revealed: LiteralString
```
### Starred expression (5)
```py
# TODO: Remove 'not-iterable' diagnostic
(a, b, *c) = "abcd" # error: "Object of type `None` is not iterable"
reveal_type(a) # revealed: LiteralString
reveal_type(b) # revealed: LiteralString
# TODO: Should be list[int] once support for assigning to starred expression is added
reveal_type(c) # revealed: @Todo
```

View File

@@ -17,7 +17,7 @@ use super::module::{Module, ModuleKind};
use super::path::{ModulePath, SearchPath, SearchPathValidationError};
/// Resolves a module name to a module.
pub fn resolve_module(db: &dyn Db, module_name: ModuleName) -> Option<Module> {
pub fn resolve_module(db: &dyn Db, module_name: &ModuleName) -> Option<Module> {
let interned_name = ModuleNameIngredient::new(db, module_name);
resolve_module_query(db, interned_name)
@@ -103,7 +103,7 @@ pub(crate) fn file_to_module(db: &dyn Db, file: File) -> Option<Module> {
// If it doesn't, then that means that multiple modules have the same name in different
// root paths, but that the module corresponding to `path` is in a lower priority search path,
// in which case we ignore it.
let module = resolve_module(db, module_name)?;
let module = resolve_module(db, &module_name)?;
if file == module.file() {
Some(module)
@@ -728,11 +728,11 @@ mod tests {
.build();
let foo_module_name = ModuleName::new_static("foo").unwrap();
let foo_module = resolve_module(&db, foo_module_name.clone()).unwrap();
let foo_module = resolve_module(&db, &foo_module_name).unwrap();
assert_eq!(
Some(&foo_module),
resolve_module(&db, foo_module_name.clone()).as_ref()
resolve_module(&db, &foo_module_name).as_ref()
);
assert_eq!("foo", foo_module.name());
@@ -755,7 +755,7 @@ mod tests {
.build();
let builtins_module_name = ModuleName::new_static("builtins").unwrap();
let builtins = resolve_module(&db, builtins_module_name).expect("builtins to resolve");
let builtins = resolve_module(&db, &builtins_module_name).expect("builtins to resolve");
assert_eq!(builtins.file().path(&db), &stdlib.join("builtins.pyi"));
}
@@ -776,7 +776,7 @@ mod tests {
.build();
let builtins_module_name = ModuleName::new_static("builtins").unwrap();
let builtins = resolve_module(&db, builtins_module_name).expect("builtins to resolve");
let builtins = resolve_module(&db, &builtins_module_name).expect("builtins to resolve");
assert_eq!(builtins.file().path(&db), &stdlib.join("builtins.pyi"));
}
@@ -794,11 +794,11 @@ mod tests {
.build();
let functools_module_name = ModuleName::new_static("functools").unwrap();
let functools_module = resolve_module(&db, functools_module_name.clone()).unwrap();
let functools_module = resolve_module(&db, &functools_module_name).unwrap();
assert_eq!(
Some(&functools_module),
resolve_module(&db, functools_module_name).as_ref()
resolve_module(&db, &functools_module_name).as_ref()
);
assert_eq!(&stdlib, functools_module.search_path());
@@ -848,7 +848,7 @@ mod tests {
let existing_modules = create_module_names(&["asyncio", "functools", "xml.etree"]);
for module_name in existing_modules {
let resolved_module = resolve_module(&db, module_name.clone()).unwrap_or_else(|| {
let resolved_module = resolve_module(&db, &module_name).unwrap_or_else(|| {
panic!("Expected module {module_name} to exist in the mock stdlib")
});
let search_path = resolved_module.search_path();
@@ -901,7 +901,7 @@ mod tests {
for module_name in nonexisting_modules {
assert!(
resolve_module(&db, module_name.clone()).is_none(),
resolve_module(&db, &module_name).is_none(),
"Unexpectedly resolved a module for {module_name}"
);
}
@@ -944,7 +944,7 @@ mod tests {
]);
for module_name in existing_modules {
let resolved_module = resolve_module(&db, module_name.clone()).unwrap_or_else(|| {
let resolved_module = resolve_module(&db, &module_name).unwrap_or_else(|| {
panic!("Expected module {module_name} to exist in the mock stdlib")
});
let search_path = resolved_module.search_path();
@@ -980,7 +980,7 @@ mod tests {
let nonexisting_modules = create_module_names(&["importlib", "xml", "xml.etree"]);
for module_name in nonexisting_modules {
assert!(
resolve_module(&db, module_name.clone()).is_none(),
resolve_module(&db, &module_name).is_none(),
"Unexpectedly resolved a module for {module_name}"
);
}
@@ -1002,11 +1002,11 @@ mod tests {
.build();
let functools_module_name = ModuleName::new_static("functools").unwrap();
let functools_module = resolve_module(&db, functools_module_name.clone()).unwrap();
let functools_module = resolve_module(&db, &functools_module_name).unwrap();
assert_eq!(
Some(&functools_module),
resolve_module(&db, functools_module_name).as_ref()
resolve_module(&db, &functools_module_name).as_ref()
);
assert_eq!(&src, functools_module.search_path());
assert_eq!(ModuleKind::Module, functools_module.kind());
@@ -1026,7 +1026,7 @@ mod tests {
.build();
let pydoc_data_topics_name = ModuleName::new_static("pydoc_data.topics").unwrap();
let pydoc_data_topics = resolve_module(&db, pydoc_data_topics_name).unwrap();
let pydoc_data_topics = resolve_module(&db, &pydoc_data_topics_name).unwrap();
assert_eq!("pydoc_data.topics", pydoc_data_topics.name());
assert_eq!(pydoc_data_topics.search_path(), &stdlib);
@@ -1043,7 +1043,7 @@ mod tests {
.build();
let foo_path = src.join("foo/__init__.py");
let foo_module = resolve_module(&db, ModuleName::new_static("foo").unwrap()).unwrap();
let foo_module = resolve_module(&db, &ModuleName::new_static("foo").unwrap()).unwrap();
assert_eq!("foo", foo_module.name());
assert_eq!(&src, foo_module.search_path());
@@ -1070,7 +1070,7 @@ mod tests {
let TestCase { db, src, .. } = TestCaseBuilder::new().with_src_files(SRC).build();
let foo_module = resolve_module(&db, ModuleName::new_static("foo").unwrap()).unwrap();
let foo_module = resolve_module(&db, &ModuleName::new_static("foo").unwrap()).unwrap();
let foo_init_path = src.join("foo/__init__.py");
assert_eq!(&src, foo_module.search_path());
@@ -1098,11 +1098,11 @@ mod tests {
let foo_bar_module_name = ModuleName::new_static("foo.bar").unwrap();
// `foo.py` takes priority over the `foo` namespace package
let foo_module = resolve_module(&db, foo_module_name.clone()).unwrap();
let foo_module = resolve_module(&db, &foo_module_name).unwrap();
assert_eq!(foo_module.file().path(&db), &src.join("foo.py"));
// `foo.bar` isn't recognised as a module
let foo_bar_module = resolve_module(&db, foo_bar_module_name.clone());
let foo_bar_module = resolve_module(&db, &foo_bar_module_name);
assert_eq!(foo_bar_module, None);
}
@@ -1112,7 +1112,7 @@ mod tests {
let TestCase { db, src, .. } = TestCaseBuilder::new().with_src_files(SRC).build();
let foo = resolve_module(&db, ModuleName::new_static("foo").unwrap()).unwrap();
let foo = resolve_module(&db, &ModuleName::new_static("foo").unwrap()).unwrap();
let foo_stub = src.join("foo.pyi");
assert_eq!(&src, foo.search_path());
@@ -1136,7 +1136,7 @@ mod tests {
let TestCase { db, src, .. } = TestCaseBuilder::new().with_src_files(SRC).build();
let baz_module =
resolve_module(&db, ModuleName::new_static("foo.bar.baz").unwrap()).unwrap();
resolve_module(&db, &ModuleName::new_static("foo.bar.baz").unwrap()).unwrap();
let baz_path = src.join("foo/bar/baz.py");
assert_eq!(&src, baz_module.search_path());
@@ -1175,14 +1175,14 @@ mod tests {
let one_module_name = ModuleName::new_static("parent.child.one").unwrap();
let one_module_path = FilePath::System(src.join("parent/child/one.py"));
assert_eq!(
resolve_module(&db, one_module_name),
resolve_module(&db, &one_module_name),
path_to_module(&db, &one_module_path)
);
let two_module_name = ModuleName::new_static("parent.child.two").unwrap();
let two_module_path = FilePath::System(site_packages.join("parent/child/two.py"));
assert_eq!(
resolve_module(&db, two_module_name),
resolve_module(&db, &two_module_name),
path_to_module(&db, &two_module_path)
);
}
@@ -1215,12 +1215,12 @@ mod tests {
let one_module_path = FilePath::System(src.join("parent/child/one.py"));
let one_module_name =
resolve_module(&db, ModuleName::new_static("parent.child.one").unwrap());
resolve_module(&db, &ModuleName::new_static("parent.child.one").unwrap());
assert_eq!(one_module_name, path_to_module(&db, &one_module_path));
assert_eq!(
None,
resolve_module(&db, ModuleName::new_static("parent.child.two").unwrap())
resolve_module(&db, &ModuleName::new_static("parent.child.two").unwrap())
);
}
@@ -1236,7 +1236,7 @@ mod tests {
.with_site_packages_files(&[("foo.py", "")])
.build();
let foo_module = resolve_module(&db, ModuleName::new_static("foo").unwrap()).unwrap();
let foo_module = resolve_module(&db, &ModuleName::new_static("foo").unwrap()).unwrap();
let foo_src_path = src.join("foo.py");
assert_eq!(&src, foo_module.search_path());
@@ -1301,8 +1301,8 @@ mod tests {
)
.context("Invalid program settings")?;
let foo_module = resolve_module(&db, ModuleName::new_static("foo").unwrap()).unwrap();
let bar_module = resolve_module(&db, ModuleName::new_static("bar").unwrap()).unwrap();
let foo_module = resolve_module(&db, &ModuleName::new_static("foo").unwrap()).unwrap();
let bar_module = resolve_module(&db, &ModuleName::new_static("bar").unwrap()).unwrap();
assert_ne!(foo_module, bar_module);
@@ -1337,7 +1337,7 @@ mod tests {
.build();
let foo_module_name = ModuleName::new_static("foo").unwrap();
let foo_module = resolve_module(&db, foo_module_name.clone()).unwrap();
let foo_module = resolve_module(&db, &foo_module_name).unwrap();
let bar_path = src.join("bar.py");
let bar = system_path_to_file(&db, &bar_path).expect("bar.py to exist");
@@ -1351,7 +1351,7 @@ mod tests {
// Re-query the foo module. The foo module should still be cached because `bar.py` isn't relevant
// for resolving `foo`.
let foo_module2 = resolve_module(&db, foo_module_name);
let foo_module2 = resolve_module(&db, &foo_module_name);
assert!(!db
.take_salsa_events()
@@ -1368,14 +1368,14 @@ mod tests {
let foo_path = src.join("foo.py");
let foo_module_name = ModuleName::new_static("foo").unwrap();
assert_eq!(resolve_module(&db, foo_module_name.clone()), None);
assert_eq!(resolve_module(&db, &foo_module_name), None);
// Now write the foo file
db.write_file(&foo_path, "x = 1")?;
let foo_file = system_path_to_file(&db, &foo_path).expect("foo.py to exist");
let foo_module = resolve_module(&db, foo_module_name).expect("Foo module to resolve");
let foo_module = resolve_module(&db, &foo_module_name).expect("Foo module to resolve");
assert_eq!(foo_file, foo_module.file());
Ok(())
@@ -1389,7 +1389,7 @@ mod tests {
let TestCase { mut db, src, .. } = TestCaseBuilder::new().with_src_files(SRC).build();
let foo_module_name = ModuleName::new_static("foo").unwrap();
let foo_module = resolve_module(&db, foo_module_name.clone()).expect("foo module to exist");
let foo_module = resolve_module(&db, &foo_module_name).expect("foo module to exist");
let foo_init_path = src.join("foo/__init__.py");
assert_eq!(&foo_init_path, foo_module.file().path(&db));
@@ -1401,7 +1401,7 @@ mod tests {
File::sync_path(&mut db, &foo_init_path);
File::sync_path(&mut db, foo_init_path.parent().unwrap());
let foo_module = resolve_module(&db, foo_module_name).expect("Foo module to resolve");
let foo_module = resolve_module(&db, &foo_module_name).expect("Foo module to resolve");
assert_eq!(&src.join("foo.py"), foo_module.file().path(&db));
Ok(())
@@ -1427,7 +1427,7 @@ mod tests {
let functools_module_name = ModuleName::new_static("functools").unwrap();
let stdlib_functools_path = stdlib.join("functools.pyi");
let functools_module = resolve_module(&db, functools_module_name.clone()).unwrap();
let functools_module = resolve_module(&db, &functools_module_name).unwrap();
assert_eq!(functools_module.search_path(), &stdlib);
assert_eq!(
Ok(functools_module.file()),
@@ -1440,7 +1440,7 @@ mod tests {
let site_packages_functools_path = site_packages.join("functools.py");
db.write_file(&site_packages_functools_path, "f: int")
.unwrap();
let functools_module = resolve_module(&db, functools_module_name.clone()).unwrap();
let functools_module = resolve_module(&db, &functools_module_name).unwrap();
let events = db.take_salsa_events();
assert_function_query_was_not_run(
&db,
@@ -1473,7 +1473,7 @@ mod tests {
.build();
let functools_module_name = ModuleName::new_static("functools").unwrap();
let functools_module = resolve_module(&db, functools_module_name.clone()).unwrap();
let functools_module = resolve_module(&db, &functools_module_name).unwrap();
assert_eq!(functools_module.search_path(), &stdlib);
assert_eq!(
Ok(functools_module.file()),
@@ -1484,7 +1484,7 @@ mod tests {
// since first-party files take higher priority in module resolution:
let src_functools_path = src.join("functools.py");
db.write_file(&src_functools_path, "FOO: int").unwrap();
let functools_module = resolve_module(&db, functools_module_name.clone()).unwrap();
let functools_module = resolve_module(&db, &functools_module_name).unwrap();
assert_eq!(functools_module.search_path(), &src);
assert_eq!(
Ok(functools_module.file()),
@@ -1515,7 +1515,7 @@ mod tests {
let functools_module_name = ModuleName::new_static("functools").unwrap();
let src_functools_path = src.join("functools.py");
let functools_module = resolve_module(&db, functools_module_name.clone()).unwrap();
let functools_module = resolve_module(&db, &functools_module_name).unwrap();
assert_eq!(functools_module.search_path(), &src);
assert_eq!(
Ok(functools_module.file()),
@@ -1528,7 +1528,7 @@ mod tests {
.remove_file(&src_functools_path)
.unwrap();
File::sync_path(&mut db, &src_functools_path);
let functools_module = resolve_module(&db, functools_module_name.clone()).unwrap();
let functools_module = resolve_module(&db, &functools_module_name).unwrap();
assert_eq!(functools_module.search_path(), &stdlib);
assert_eq!(
Ok(functools_module.file()),
@@ -1550,8 +1550,8 @@ mod tests {
let foo_module_name = ModuleName::new_static("foo").unwrap();
let foo_bar_module_name = ModuleName::new_static("foo.bar").unwrap();
let foo_module = resolve_module(&db, foo_module_name.clone()).unwrap();
let foo_bar_module = resolve_module(&db, foo_bar_module_name.clone()).unwrap();
let foo_module = resolve_module(&db, &foo_module_name).unwrap();
let foo_bar_module = resolve_module(&db, &foo_bar_module_name).unwrap();
assert_eq!(
foo_module.file().path(&db),
@@ -1579,11 +1579,11 @@ mod tests {
// Lines with leading whitespace in `.pth` files do not parse:
let foo_module_name = ModuleName::new_static("foo").unwrap();
assert_eq!(resolve_module(&db, foo_module_name), None);
assert_eq!(resolve_module(&db, &foo_module_name), None);
// Lines with trailing whitespace in `.pth` files do:
let bar_module_name = ModuleName::new_static("bar").unwrap();
let bar_module = resolve_module(&db, bar_module_name.clone()).unwrap();
let bar_module = resolve_module(&db, &bar_module_name).unwrap();
assert_eq!(
bar_module.file().path(&db),
&FilePath::system("/y/src/bar.py")
@@ -1602,7 +1602,7 @@ mod tests {
.build();
let foo_module_name = ModuleName::new_static("foo").unwrap();
let foo_module = resolve_module(&db, foo_module_name.clone()).unwrap();
let foo_module = resolve_module(&db, &foo_module_name).unwrap();
assert_eq!(
foo_module.file().path(&db),
@@ -1650,10 +1650,10 @@ not_a_directory
let b_module_name = ModuleName::new_static("b").unwrap();
let spam_module_name = ModuleName::new_static("spam").unwrap();
let foo_module = resolve_module(&db, foo_module_name.clone()).unwrap();
let a_module = resolve_module(&db, a_module_name.clone()).unwrap();
let b_module = resolve_module(&db, b_module_name.clone()).unwrap();
let spam_module = resolve_module(&db, spam_module_name.clone()).unwrap();
let foo_module = resolve_module(&db, &foo_module_name).unwrap();
let a_module = resolve_module(&db, &a_module_name).unwrap();
let b_module = resolve_module(&db, &b_module_name).unwrap();
let spam_module = resolve_module(&db, &spam_module_name).unwrap();
assert_eq!(
foo_module.file().path(&db),
@@ -1681,14 +1681,14 @@ not_a_directory
let foo_module_name = ModuleName::new_static("foo").unwrap();
let bar_module_name = ModuleName::new_static("bar").unwrap();
let foo_module = resolve_module(&db, foo_module_name).unwrap();
let foo_module = resolve_module(&db, &foo_module_name).unwrap();
assert_eq!(
foo_module.file().path(&db),
&FilePath::system("/x/src/foo.py")
);
db.clear_salsa_events();
let bar_module = resolve_module(&db, bar_module_name).unwrap();
let bar_module = resolve_module(&db, &bar_module_name).unwrap();
assert_eq!(
bar_module.file().path(&db),
&FilePath::system("/y/src/bar.py")
@@ -1713,7 +1713,7 @@ not_a_directory
db.write_files(x_directory).unwrap();
let foo_module_name = ModuleName::new_static("foo").unwrap();
let foo_module = resolve_module(&db, foo_module_name.clone()).unwrap();
let foo_module = resolve_module(&db, &foo_module_name).unwrap();
assert_eq!(
foo_module.file().path(&db),
&FilePath::system("/x/src/foo.py")
@@ -1725,7 +1725,7 @@ not_a_directory
File::sync_path(&mut db, &site_packages.join("_foo.pth"));
assert_eq!(resolve_module(&db, foo_module_name.clone()), None);
assert_eq!(resolve_module(&db, &foo_module_name), None);
}
#[test]
@@ -1740,7 +1740,7 @@ not_a_directory
db.write_files(x_directory).unwrap();
let foo_module_name = ModuleName::new_static("foo").unwrap();
let foo_module = resolve_module(&db, foo_module_name.clone()).unwrap();
let foo_module = resolve_module(&db, &foo_module_name).unwrap();
let src_path = SystemPathBuf::from("/x/src");
assert_eq!(
foo_module.file().path(&db),
@@ -1753,7 +1753,7 @@ not_a_directory
db.memory_file_system().remove_directory(&src_path).unwrap();
File::sync_path(&mut db, &src_path.join("foo.py"));
File::sync_path(&mut db, &src_path);
assert_eq!(resolve_module(&db, foo_module_name.clone()), None);
assert_eq!(resolve_module(&db, &foo_module_name), None);
}
#[test]
@@ -1812,7 +1812,7 @@ not_a_directory
// The editable installs discovered from the `.pth` file in the first `site-packages` directory
// take precedence over the second `site-packages` directory...
let a_module_name = ModuleName::new_static("a").unwrap();
let a_module = resolve_module(&db, a_module_name.clone()).unwrap();
let a_module = resolve_module(&db, &a_module_name).unwrap();
assert_eq!(a_module.file().path(&db), &editable_install_location);
db.memory_file_system()
@@ -1823,7 +1823,7 @@ not_a_directory
// ...But now that the `.pth` file in the first `site-packages` directory has been deleted,
// the editable install no longer exists, so the module now resolves to the file in the
// second `site-packages` directory
let a_module = resolve_module(&db, a_module_name).unwrap();
let a_module = resolve_module(&db, &a_module_name).unwrap();
assert_eq!(a_module.file().path(&db), &system_site_packages_location);
}
}

View File

@@ -994,7 +994,7 @@ class C[T]:
let ast::Expr::NumberLiteral(ast::ExprNumberLiteral {
value: ast::Number::Int(num),
..
}) = &*assignment.assignment().value
}) = assignment.value()
else {
panic!("should be a number literal")
};

View File

@@ -28,8 +28,8 @@ use crate::Db;
use super::constraint::{Constraint, PatternConstraint};
use super::definition::{
DefinitionCategory, ExceptHandlerDefinitionNodeRef, MatchPatternDefinitionNodeRef,
WithItemDefinitionNodeRef,
AssignmentKind, DefinitionCategory, ExceptHandlerDefinitionNodeRef,
MatchPatternDefinitionNodeRef, WithItemDefinitionNodeRef,
};
pub(super) struct SemanticIndexBuilder<'db> {
@@ -566,11 +566,22 @@ where
debug_assert!(self.current_assignment.is_none());
self.visit_expr(&node.value);
self.add_standalone_expression(&node.value);
self.current_assignment = Some(node.into());
for target in &node.targets {
for (target_index, target) in node.targets.iter().enumerate() {
let kind = match target {
ast::Expr::List(_) | ast::Expr::Tuple(_) => Some(AssignmentKind::Sequence),
ast::Expr::Name(_) => Some(AssignmentKind::Name),
_ => None,
};
if let Some(kind) = kind {
self.current_assignment = Some(CurrentAssignment::Assign {
assignment: node,
target_index,
kind,
});
}
self.visit_expr(target);
self.current_assignment = None;
}
self.current_assignment = None;
}
ast::Stmt::AnnAssign(node) => {
debug_assert!(self.current_assignment.is_none());
@@ -815,12 +826,18 @@ where
let symbol = self.add_symbol(id.clone());
if is_definition {
match self.current_assignment {
Some(CurrentAssignment::Assign(assignment)) => {
Some(CurrentAssignment::Assign {
assignment,
target_index,
kind,
}) => {
self.add_definition(
symbol,
AssignmentDefinitionNodeRef {
assignment,
target: name_node,
target_index,
name: name_node,
kind,
},
);
}
@@ -1045,7 +1062,11 @@ where
#[derive(Copy, Clone, Debug)]
enum CurrentAssignment<'a> {
Assign(&'a ast::StmtAssign),
Assign {
assignment: &'a ast::StmtAssign,
target_index: usize,
kind: AssignmentKind,
},
AnnAssign(&'a ast::StmtAnnAssign),
AugAssign(&'a ast::StmtAugAssign),
For(&'a ast::StmtFor),
@@ -1057,12 +1078,6 @@ enum CurrentAssignment<'a> {
WithItem(&'a ast::WithItem),
}
impl<'a> From<&'a ast::StmtAssign> for CurrentAssignment<'a> {
fn from(value: &'a ast::StmtAssign) -> Self {
Self::Assign(value)
}
}
impl<'a> From<&'a ast::StmtAnnAssign> for CurrentAssignment<'a> {
fn from(value: &'a ast::StmtAnnAssign) -> Self {
Self::AnnAssign(value)

View File

@@ -161,7 +161,9 @@ pub(crate) struct ImportFromDefinitionNodeRef<'a> {
#[derive(Copy, Clone, Debug)]
pub(crate) struct AssignmentDefinitionNodeRef<'a> {
pub(crate) assignment: &'a ast::StmtAssign,
pub(crate) target: &'a ast::ExprName,
pub(crate) target_index: usize,
pub(crate) name: &'a ast::ExprName,
pub(crate) kind: AssignmentKind,
}
#[derive(Copy, Clone, Debug)]
@@ -224,12 +226,17 @@ impl DefinitionNodeRef<'_> {
DefinitionNodeRef::NamedExpression(named) => {
DefinitionKind::NamedExpression(AstNodeRef::new(parsed, named))
}
DefinitionNodeRef::Assignment(AssignmentDefinitionNodeRef { assignment, target }) => {
DefinitionKind::Assignment(AssignmentDefinitionKind {
assignment: AstNodeRef::new(parsed.clone(), assignment),
target: AstNodeRef::new(parsed, target),
})
}
DefinitionNodeRef::Assignment(AssignmentDefinitionNodeRef {
assignment,
target_index,
name,
kind,
}) => DefinitionKind::Assignment(AssignmentDefinitionKind {
assignment: AstNodeRef::new(parsed.clone(), assignment),
target_index,
name: AstNodeRef::new(parsed, name),
kind,
}),
DefinitionNodeRef::AnnotatedAssignment(assign) => {
DefinitionKind::AnnotatedAssignment(AstNodeRef::new(parsed, assign))
}
@@ -300,8 +307,10 @@ impl DefinitionNodeRef<'_> {
Self::NamedExpression(node) => node.into(),
Self::Assignment(AssignmentDefinitionNodeRef {
assignment: _,
target,
}) => target.into(),
target_index: _,
name,
kind: _,
}) => name.into(),
Self::AnnotatedAssignment(node) => node.into(),
Self::AugmentedAssignment(node) => node.into(),
Self::For(ForStmtDefinitionNodeRef {
@@ -485,17 +494,34 @@ impl ImportFromDefinitionKind {
#[derive(Clone, Debug)]
pub struct AssignmentDefinitionKind {
assignment: AstNodeRef<ast::StmtAssign>,
target: AstNodeRef<ast::ExprName>,
target_index: usize,
name: AstNodeRef<ast::ExprName>,
kind: AssignmentKind,
}
impl AssignmentDefinitionKind {
pub(crate) fn assignment(&self) -> &ast::StmtAssign {
self.assignment.node()
pub(crate) fn value(&self) -> &ast::Expr {
&self.assignment.node().value
}
pub(crate) fn target(&self) -> &ast::ExprName {
self.target.node()
pub(crate) fn target(&self) -> &ast::Expr {
&self.assignment.node().targets[self.target_index]
}
pub(crate) fn name(&self) -> &ast::ExprName {
self.name.node()
}
pub(crate) fn kind(&self) -> AssignmentKind {
self.kind
}
}
/// The kind of assignment target expression.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum AssignmentKind {
Sequence,
Name,
}
#[derive(Clone, Debug)]

View File

@@ -35,7 +35,7 @@ impl<'db> SemanticModel<'db> {
line_index(self.db.upcast(), self.file)
}
pub fn resolve_module(&self, module_name: ModuleName) -> Option<Module> {
pub fn resolve_module(&self, module_name: &ModuleName) -> Option<Module> {
resolve_module(self.db, module_name)
}

View File

@@ -35,7 +35,7 @@ fn core_module_symbol_ty<'db>(
core_module: CoreStdlibModule,
symbol: &str,
) -> Type<'db> {
resolve_module(db, core_module.name())
resolve_module(db, &core_module.name())
.map(|module| global_symbol_ty(db, module.file(), symbol))
.unwrap_or(Type::Unbound)
}
@@ -76,7 +76,7 @@ pub(crate) fn typing_extensions_symbol_ty<'db>(db: &'db dyn Db, symbol: &str) ->
///
/// Can return `None` if a custom typeshed is used that is missing the core module in question.
fn core_module_scope(db: &dyn Db, core_module: CoreStdlibModule) -> Option<ScopeId<'_>> {
resolve_module(db, core_module.name()).map(|module| global_scope(db, module.file()))
resolve_module(db, &core_module.name()).map(|module| global_scope(db, module.file()))
}
/// Get the `builtins` module scope.

View File

@@ -463,6 +463,57 @@ impl<'db> Type<'db> {
self == other
}
/// Return true if there is just a single inhabitant for this type.
///
/// Note: This function aims to have no false positives, but might return `false`
/// for more complicated types that are actually singletons.
pub(crate) fn is_singleton(self, db: &'db dyn Db) -> bool {
match self {
Type::Any
| Type::Never
| Type::Unknown
| Type::Todo
| Type::Unbound
| Type::Instance(..) // TODO some instance types can be singleton types (EllipsisType, NotImplementedType)
| Type::IntLiteral(..)
| Type::StringLiteral(..)
| Type::BytesLiteral(..)
| Type::LiteralString => {
// Note: The literal types included in this pattern are not true singletons.
// There can be multiple Python objects (at different memory locations) that
// are both of type Literal[345], for example.
false
}
Type::None | Type::BooleanLiteral(_) | Type::Function(..) | Type::Class(..) | Type::Module(..) => true,
Type::Tuple(tuple) => {
// We deliberately deviate from the language specification [1] here and claim
// that the empty tuple type is a singleton type. The reasoning is that `()`
// is often used as a sentinel value in user code. Declaring the empty tuple to
// be of singleton type allows us to narrow types in `is not ()` conditionals.
//
// [1] https://docs.python.org/3/reference/expressions.html#parenthesized-forms
tuple.elements(db).is_empty()
}
Type::Union(..) => {
// A single-element union, where the sole element was a singleton, would itself
// be a singleton type. However, unions with length < 2 should never appear in
// our model due to [`UnionBuilder::build`].
false
}
Type::Intersection(..) => {
// Intersection types are hard to analyze. The following types are technically
// all singleton types, but it is not straightforward to compute this. Again,
// we simply return false.
//
// bool & ~Literal[False]`
// None & (None | int)
// (A | B) & (B | C) with A, B, C disjunct and B a singleton
//
false
}
}
}
/// Resolve a member access of a type.
///
/// For example, if `foo` is `Type::Instance(<Bar>)`,
@@ -791,14 +842,10 @@ impl<'db> Type<'db> {
Type::IntLiteral(number) => Type::StringLiteral(StringLiteralType::new(db, {
number.to_string().into_boxed_str()
})),
Type::BooleanLiteral(true) => {
Type::StringLiteral(StringLiteralType::new(db, "True".into()))
}
Type::BooleanLiteral(false) => {
Type::StringLiteral(StringLiteralType::new(db, "False".into()))
}
Type::BooleanLiteral(true) => Type::StringLiteral(StringLiteralType::new(db, "True")),
Type::BooleanLiteral(false) => Type::StringLiteral(StringLiteralType::new(db, "False")),
Type::StringLiteral(literal) => Type::StringLiteral(StringLiteralType::new(db, {
format!("'{}'", literal.value(db).escape_default()).into()
format!("'{}'", literal.value(db).escape_default()).into_boxed_str()
})),
Type::LiteralString => Type::LiteralString,
// TODO: handle more complex types
@@ -1463,6 +1510,12 @@ pub struct StringLiteralType<'db> {
value: Box<str>,
}
impl<'db> StringLiteralType<'db> {
pub fn len(&self, db: &'db dyn Db) -> usize {
self.value(db).len()
}
}
#[salsa::interned]
pub struct BytesLiteralType<'db> {
#[return_ref]
@@ -1475,6 +1528,16 @@ pub struct TupleType<'db> {
elements: Box<[Type<'db>]>,
}
impl<'db> TupleType<'db> {
pub fn get(&self, db: &'db dyn Db, index: usize) -> Option<Type<'db>> {
self.elements(db).get(index).copied()
}
pub fn len(&self, db: &'db dyn Db) -> usize {
self.elements(db).len()
}
}
#[cfg(test)]
mod tests {
use super::{
@@ -1514,6 +1577,7 @@ mod tests {
enum Ty {
Never,
Unknown,
None,
Any,
IntLiteral(i64),
BoolLiteral(bool),
@@ -1530,22 +1594,19 @@ mod tests {
match self {
Ty::Never => Type::Never,
Ty::Unknown => Type::Unknown,
Ty::None => Type::None,
Ty::Any => Type::Any,
Ty::IntLiteral(n) => Type::IntLiteral(n),
Ty::StringLiteral(s) => {
Type::StringLiteral(StringLiteralType::new(db, (*s).into()))
}
Ty::StringLiteral(s) => Type::StringLiteral(StringLiteralType::new(db, s)),
Ty::BoolLiteral(b) => Type::BooleanLiteral(b),
Ty::LiteralString => Type::LiteralString,
Ty::BytesLiteral(s) => {
Type::BytesLiteral(BytesLiteralType::new(db, s.as_bytes().into()))
}
Ty::BytesLiteral(s) => Type::BytesLiteral(BytesLiteralType::new(db, s.as_bytes())),
Ty::BuiltinInstance(s) => builtins_symbol_ty(db, s).to_instance(db),
Ty::Union(tys) => {
UnionType::from_elements(db, tys.into_iter().map(|ty| ty.into_type(db)))
}
Ty::Tuple(tys) => {
let elements = tys.into_iter().map(|ty| ty.into_type(db)).collect();
let elements: Box<_> = tys.into_iter().map(|ty| ty.into_type(db)).collect();
Type::Tuple(TupleType::new(db, elements))
}
}
@@ -1618,6 +1679,28 @@ mod tests {
assert!(from.into_type(&db).is_equivalent_to(&db, to.into_type(&db)));
}
#[test_case(Ty::None)]
#[test_case(Ty::BoolLiteral(true))]
#[test_case(Ty::BoolLiteral(false))]
#[test_case(Ty::Tuple(vec![]))]
fn is_singleton(from: Ty) {
let db = setup_db();
assert!(from.into_type(&db).is_singleton(&db));
}
#[test_case(Ty::Never)]
#[test_case(Ty::IntLiteral(345))]
#[test_case(Ty::BuiltinInstance("str"))]
#[test_case(Ty::Union(vec![Ty::IntLiteral(1), Ty::IntLiteral(2)]))]
#[test_case(Ty::Tuple(vec![Ty::None]))]
#[test_case(Ty::Tuple(vec![Ty::None, Ty::BoolLiteral(true)]))]
fn is_not_singleton(from: Ty) {
let db = setup_db();
assert!(!from.into_type(&db).is_singleton(&db));
}
#[test_case(Ty::IntLiteral(1); "is_int_literal_truthy")]
#[test_case(Ty::IntLiteral(-1))]
#[test_case(Ty::StringLiteral("foo"))]

View File

@@ -111,7 +111,7 @@ impl<'db> UnionBuilder<'db> {
match self.elements.len() {
0 => Type::Never,
1 => self.elements[0],
_ => Type::Union(UnionType::new(self.db, self.elements.into())),
_ => Type::Union(UnionType::new(self.db, self.elements.into_boxed_slice())),
}
}
}

View File

@@ -341,12 +341,12 @@ mod tests {
Type::Unknown,
Type::IntLiteral(-1),
global_symbol_ty(&db, mod_file, "A"),
Type::StringLiteral(StringLiteralType::new(&db, Box::from("A"))),
Type::BytesLiteral(BytesLiteralType::new(&db, Box::from([0]))),
Type::BytesLiteral(BytesLiteralType::new(&db, Box::from([7]))),
Type::StringLiteral(StringLiteralType::new(&db, "A")),
Type::BytesLiteral(BytesLiteralType::new(&db, [0u8].as_slice())),
Type::BytesLiteral(BytesLiteralType::new(&db, [7u8].as_slice())),
Type::IntLiteral(0),
Type::IntLiteral(1),
Type::StringLiteral(StringLiteralType::new(&db, Box::from("B"))),
Type::StringLiteral(StringLiteralType::new(&db, "B")),
global_symbol_ty(&db, mod_file, "foo"),
global_symbol_ty(&db, mod_file, "bar"),
global_symbol_ty(&db, mod_file, "B"),

File diff suppressed because it is too large Load Diff

View File

@@ -155,13 +155,24 @@ impl<'db> NarrowingConstraintsBuilder<'db> {
let inference = infer_expression_types(self.db, expression);
for (op, comparator) in std::iter::zip(&**ops, &**comparators) {
let comp_ty = inference.expression_ty(comparator.scoped_ast_id(self.db, scope));
if matches!(op, ast::CmpOp::IsNot) {
let ty = IntersectionBuilder::new(self.db)
.add_negative(comp_ty)
.build();
self.constraints.insert(symbol, ty);
};
// TODO other comparison types
match op {
ast::CmpOp::IsNot => {
if comp_ty.is_singleton(self.db) {
let ty = IntersectionBuilder::new(self.db)
.add_negative(comp_ty)
.build();
self.constraints.insert(symbol, ty);
} else {
// Non-singletons cannot be safely narrowed using `is not`
}
}
ast::CmpOp::Is => {
self.constraints.insert(symbol, comp_ty);
}
_ => {
// TODO other comparison types
}
}
}
}
}

View File

@@ -141,7 +141,7 @@ static HEADER_RE: Lazy<Regex> =
/// Matches a code block fenced by triple backticks, possibly with language and `key=val`
/// configuration items following the opening backticks (in the "tag string" of the code block).
static CODE_RE: Lazy<Regex> = Lazy::new(|| {
Regex::new(r"^```(?<lang>\w+)(?<config>( +\S+)*)\s*\n(?<code>(.|\n)*?)\n```\s*\n").unwrap()
Regex::new(r"^```(?<lang>\w+)(?<config>( +\S+)*)\s*\n(?<code>(.|\n)*?)\n?```\s*\n").unwrap()
});
#[derive(Debug)]

View File

@@ -21,7 +21,7 @@ the project the stubs are for, but instead report them here to typeshed.**
Further documentation on stub files, typeshed, and Python's typing system in
general, can also be found at https://typing.readthedocs.io/en/latest/.
Typeshed supports Python versions 3.8 and up.
Typeshed supports Python versions 3.8 to 3.13.
## Using

View File

@@ -1 +1 @@
91a58b07cdd807b1d965e04ba85af2adab8bf924
a871efd90ca2734b3341dde98cffab66f3e08cee

View File

@@ -20,6 +20,7 @@
__future__: 3.0-
__main__: 3.0-
_ast: 3.0-
_asyncio: 3.0-
_bisect: 3.0-
_bootlocale: 3.4-3.9
_codecs: 3.0-
@@ -37,6 +38,7 @@ _imp: 3.0-
_interpchannels: 3.13-
_interpqueues: 3.13-
_interpreters: 3.13-
_io: 3.0-
_json: 3.0-
_locale: 3.0-
_lsprof: 3.0-
@@ -50,6 +52,8 @@ _pydecimal: 3.5-
_random: 3.0-
_sitebuiltins: 3.4-
_socket: 3.0- # present in 3.0 at runtime, but not in typeshed
_sqlite3: 3.0-
_ssl: 3.0-
_stat: 3.4-
_thread: 3.0-
_threading_local: 3.0-

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,120 @@
import sys
from asyncio.events import AbstractEventLoop
from collections.abc import Awaitable, Callable, Coroutine, Generator, Iterable
from contextvars import Context
from types import FrameType
from typing import Any, Literal, TextIO, TypeVar
from typing_extensions import Self, TypeAlias
if sys.version_info >= (3, 9):
from types import GenericAlias
_T = TypeVar("_T")
_T_co = TypeVar("_T_co", covariant=True)
_TaskYieldType: TypeAlias = Future[object] | None
class Future(Awaitable[_T], Iterable[_T]):
_state: str
@property
def _exception(self) -> BaseException | None: ...
_blocking: bool
@property
def _log_traceback(self) -> bool: ...
@_log_traceback.setter
def _log_traceback(self, val: Literal[False]) -> None: ...
_asyncio_future_blocking: bool # is a part of duck-typing contract for `Future`
def __init__(self, *, loop: AbstractEventLoop | None = ...) -> None: ...
def __del__(self) -> None: ...
def get_loop(self) -> AbstractEventLoop: ...
@property
def _callbacks(self) -> list[tuple[Callable[[Self], Any], Context]]: ...
def add_done_callback(self, fn: Callable[[Self], object], /, *, context: Context | None = None) -> None: ...
if sys.version_info >= (3, 9):
def cancel(self, msg: Any | None = None) -> bool: ...
else:
def cancel(self) -> bool: ...
def cancelled(self) -> bool: ...
def done(self) -> bool: ...
def result(self) -> _T: ...
def exception(self) -> BaseException | None: ...
def remove_done_callback(self, fn: Callable[[Self], object], /) -> int: ...
def set_result(self, result: _T, /) -> None: ...
def set_exception(self, exception: type | BaseException, /) -> None: ...
def __iter__(self) -> Generator[Any, None, _T]: ...
def __await__(self) -> Generator[Any, None, _T]: ...
@property
def _loop(self) -> AbstractEventLoop: ...
if sys.version_info >= (3, 9):
def __class_getitem__(cls, item: Any, /) -> GenericAlias: ...
if sys.version_info >= (3, 12):
_TaskCompatibleCoro: TypeAlias = Coroutine[Any, Any, _T_co]
elif sys.version_info >= (3, 9):
_TaskCompatibleCoro: TypeAlias = Generator[_TaskYieldType, None, _T_co] | Coroutine[Any, Any, _T_co]
else:
_TaskCompatibleCoro: TypeAlias = Generator[_TaskYieldType, None, _T_co] | Awaitable[_T_co]
# mypy and pyright complain that a subclass of an invariant class shouldn't be covariant.
# While this is true in general, here it's sort-of okay to have a covariant subclass,
# since the only reason why `asyncio.Future` is invariant is the `set_result()` method,
# and `asyncio.Task.set_result()` always raises.
class Task(Future[_T_co]): # type: ignore[type-var] # pyright: ignore[reportInvalidTypeArguments]
if sys.version_info >= (3, 12):
def __init__(
self,
coro: _TaskCompatibleCoro[_T_co],
*,
loop: AbstractEventLoop = ...,
name: str | None = ...,
context: Context | None = None,
eager_start: bool = False,
) -> None: ...
elif sys.version_info >= (3, 11):
def __init__(
self,
coro: _TaskCompatibleCoro[_T_co],
*,
loop: AbstractEventLoop = ...,
name: str | None = ...,
context: Context | None = None,
) -> None: ...
else:
def __init__(
self, coro: _TaskCompatibleCoro[_T_co], *, loop: AbstractEventLoop = ..., name: str | None = ...
) -> None: ...
if sys.version_info >= (3, 12):
def get_coro(self) -> _TaskCompatibleCoro[_T_co] | None: ...
else:
def get_coro(self) -> _TaskCompatibleCoro[_T_co]: ...
def get_name(self) -> str: ...
def set_name(self, value: object, /) -> None: ...
if sys.version_info >= (3, 12):
def get_context(self) -> Context: ...
def get_stack(self, *, limit: int | None = None) -> list[FrameType]: ...
def print_stack(self, *, limit: int | None = None, file: TextIO | None = None) -> None: ...
if sys.version_info >= (3, 11):
def cancelling(self) -> int: ...
def uncancel(self) -> int: ...
if sys.version_info < (3, 9):
@classmethod
def current_task(cls, loop: AbstractEventLoop | None = None) -> Task[Any] | None: ...
@classmethod
def all_tasks(cls, loop: AbstractEventLoop | None = None) -> set[Task[Any]]: ...
if sys.version_info >= (3, 9):
def __class_getitem__(cls, item: Any, /) -> GenericAlias: ...
def get_event_loop() -> AbstractEventLoop: ...
def get_running_loop() -> AbstractEventLoop: ...
def _set_running_loop(loop: AbstractEventLoop | None, /) -> None: ...
def _get_running_loop() -> AbstractEventLoop: ...
def _register_task(task: Task[Any]) -> None: ...
def _unregister_task(task: Task[Any]) -> None: ...
def _enter_task(loop: AbstractEventLoop, task: Task[Any]) -> None: ...
def _leave_task(loop: AbstractEventLoop, task: Task[Any]) -> None: ...
if sys.version_info >= (3, 12):
def current_task(loop: AbstractEventLoop | None = None) -> Task[Any] | None: ...

View File

@@ -20,6 +20,8 @@ _QuotingType: TypeAlias = int
class Error(Exception): ...
_DialectLike: TypeAlias = str | Dialect | type[Dialect]
class Dialect:
delimiter: str
quotechar: str | None
@@ -29,9 +31,18 @@ class Dialect:
lineterminator: str
quoting: _QuotingType
strict: bool
def __init__(self) -> None: ...
_DialectLike: TypeAlias = str | Dialect | type[Dialect]
def __init__(
self,
dialect: _DialectLike | None = ...,
delimiter: str = ",",
doublequote: bool = True,
escapechar: str | None = None,
lineterminator: str = "\r\n",
quotechar: str | None = '"',
quoting: _QuotingType = 0,
skipinitialspace: bool = False,
strict: bool = False,
) -> None: ...
class _reader(Iterator[list[str]]):
@property

View File

@@ -2,7 +2,7 @@ import sys
from _typeshed import ReadableBuffer, WriteableBuffer
from abc import abstractmethod
from collections.abc import Callable, Iterable, Iterator, Mapping, Sequence
from ctypes import CDLL, ArgumentError as ArgumentError
from ctypes import CDLL, ArgumentError as ArgumentError, c_void_p
from typing import Any, ClassVar, Generic, TypeVar, overload
from typing_extensions import Self, TypeAlias
@@ -99,6 +99,9 @@ class _Pointer(_PointerLike, _CData, Generic[_CT]):
def __getitem__(self, key: slice, /) -> list[Any]: ...
def __setitem__(self, key: int, value: Any, /) -> None: ...
@overload
def POINTER(type: None, /) -> type[c_void_p]: ...
@overload
def POINTER(type: type[_CT], /) -> type[_Pointer[_CT]]: ...
def pointer(obj: _CT, /) -> _Pointer[_CT]: ...

View File

@@ -298,7 +298,7 @@ if sys.version_info >= (3, 9):
def getmouse() -> tuple[int, int, int, int, int]: ...
def getsyx() -> tuple[int, int]: ...
def getwin(file: SupportsRead[bytes], /) -> _CursesWindow: ...
def getwin(file: SupportsRead[bytes], /) -> window: ...
def halfdelay(tenths: int, /) -> None: ...
def has_colors() -> bool: ...
@@ -310,7 +310,7 @@ def has_il() -> bool: ...
def has_key(key: int, /) -> bool: ...
def init_color(color_number: int, r: int, g: int, b: int, /) -> None: ...
def init_pair(pair_number: int, fg: int, bg: int, /) -> None: ...
def initscr() -> _CursesWindow: ...
def initscr() -> window: ...
def intrflush(flag: bool, /) -> None: ...
def is_term_resized(nlines: int, ncols: int, /) -> bool: ...
def isendwin() -> bool: ...
@@ -321,8 +321,8 @@ def meta(yes: bool, /) -> None: ...
def mouseinterval(interval: int, /) -> None: ...
def mousemask(newmask: int, /) -> tuple[int, int]: ...
def napms(ms: int, /) -> int: ...
def newpad(nlines: int, ncols: int, /) -> _CursesWindow: ...
def newwin(nlines: int, ncols: int, begin_y: int = ..., begin_x: int = ..., /) -> _CursesWindow: ...
def newpad(nlines: int, ncols: int, /) -> window: ...
def newwin(nlines: int, ncols: int, begin_y: int = ..., begin_x: int = ..., /) -> window: ...
def nl(flag: bool = True, /) -> None: ...
def nocbreak() -> None: ...
def noecho() -> None: ...
@@ -378,7 +378,7 @@ def use_env(flag: bool, /) -> None: ...
class error(Exception): ...
@final
class _CursesWindow:
class window: # undocumented
encoding: str
@overload
def addch(self, ch: _ChType, attr: int = ...) -> None: ...
@@ -431,9 +431,9 @@ class _CursesWindow:
def delch(self, y: int, x: int) -> None: ...
def deleteln(self) -> None: ...
@overload
def derwin(self, begin_y: int, begin_x: int) -> _CursesWindow: ...
def derwin(self, begin_y: int, begin_x: int) -> window: ...
@overload
def derwin(self, nlines: int, ncols: int, begin_y: int, begin_x: int) -> _CursesWindow: ...
def derwin(self, nlines: int, ncols: int, begin_y: int, begin_x: int) -> window: ...
def echochar(self, ch: _ChType, attr: int = ..., /) -> None: ...
def enclose(self, y: int, x: int, /) -> bool: ...
def erase(self) -> None: ...
@@ -505,16 +505,16 @@ class _CursesWindow:
@overload
def noutrefresh(self, pminrow: int, pmincol: int, sminrow: int, smincol: int, smaxrow: int, smaxcol: int) -> None: ...
@overload
def overlay(self, destwin: _CursesWindow) -> None: ...
def overlay(self, destwin: window) -> None: ...
@overload
def overlay(
self, destwin: _CursesWindow, sminrow: int, smincol: int, dminrow: int, dmincol: int, dmaxrow: int, dmaxcol: int
self, destwin: window, sminrow: int, smincol: int, dminrow: int, dmincol: int, dmaxrow: int, dmaxcol: int
) -> None: ...
@overload
def overwrite(self, destwin: _CursesWindow) -> None: ...
def overwrite(self, destwin: window) -> None: ...
@overload
def overwrite(
self, destwin: _CursesWindow, sminrow: int, smincol: int, dminrow: int, dmincol: int, dmaxrow: int, dmaxcol: int
self, destwin: window, sminrow: int, smincol: int, dminrow: int, dmincol: int, dmaxrow: int, dmaxcol: int
) -> None: ...
def putwin(self, file: IO[Any], /) -> None: ...
def redrawln(self, beg: int, num: int, /) -> None: ...
@@ -530,13 +530,13 @@ class _CursesWindow:
def standend(self) -> None: ...
def standout(self) -> None: ...
@overload
def subpad(self, begin_y: int, begin_x: int) -> _CursesWindow: ...
def subpad(self, begin_y: int, begin_x: int) -> window: ...
@overload
def subpad(self, nlines: int, ncols: int, begin_y: int, begin_x: int) -> _CursesWindow: ...
def subpad(self, nlines: int, ncols: int, begin_y: int, begin_x: int) -> window: ...
@overload
def subwin(self, begin_y: int, begin_x: int) -> _CursesWindow: ...
def subwin(self, begin_y: int, begin_x: int) -> window: ...
@overload
def subwin(self, nlines: int, ncols: int, begin_y: int, begin_x: int) -> _CursesWindow: ...
def subwin(self, nlines: int, ncols: int, begin_y: int, begin_x: int) -> window: ...
def syncdown(self) -> None: ...
def syncok(self, flag: bool) -> None: ...
def syncup(self) -> None: ...
@@ -555,4 +555,3 @@ class _ncurses_version(NamedTuple):
patch: int
ncurses_version: _ncurses_version
window = _CursesWindow # undocumented

View File

@@ -1,22 +1,39 @@
import numbers
import sys
from collections.abc import Container, Sequence
from decimal import (
Clamped as Clamped,
Context as Context,
ConversionSyntax as ConversionSyntax,
Decimal as Decimal,
DecimalException as DecimalException,
DecimalTuple as DecimalTuple,
DivisionByZero as DivisionByZero,
DivisionImpossible as DivisionImpossible,
DivisionUndefined as DivisionUndefined,
FloatOperation as FloatOperation,
Inexact as Inexact,
InvalidContext as InvalidContext,
InvalidOperation as InvalidOperation,
Overflow as Overflow,
Rounded as Rounded,
Subnormal as Subnormal,
Underflow as Underflow,
)
from types import TracebackType
from typing import Any, ClassVar, Final, Literal, NamedTuple, overload
from typing_extensions import Self, TypeAlias
from typing import Final
from typing_extensions import TypeAlias
_Decimal: TypeAlias = Decimal | int
_DecimalNew: TypeAlias = Decimal | float | str | tuple[int, Sequence[int], int]
_ComparableNum: TypeAlias = Decimal | float | numbers.Rational
_TrapType: TypeAlias = type[DecimalException]
class _ContextManager:
new_context: Context
saved_context: Context
def __init__(self, new_context: Context) -> None: ...
def __enter__(self) -> Context: ...
def __exit__(self, t: type[BaseException] | None, v: BaseException | None, tb: TracebackType | None) -> None: ...
__version__: Final[str]
__libmpdec_version__: Final[str]
class DecimalTuple(NamedTuple):
sign: int
digits: tuple[int, ...]
exponent: int | Literal["n", "N", "F"]
ROUND_DOWN: Final[str]
ROUND_HALF_UP: Final[str]
ROUND_HALF_EVEN: Final[str]
@@ -32,21 +49,6 @@ MAX_PREC: Final[int]
MIN_EMIN: Final[int]
MIN_ETINY: Final[int]
class DecimalException(ArithmeticError): ...
class Clamped(DecimalException): ...
class InvalidOperation(DecimalException): ...
class ConversionSyntax(InvalidOperation): ...
class DivisionByZero(DecimalException, ZeroDivisionError): ...
class DivisionImpossible(InvalidOperation): ...
class DivisionUndefined(InvalidOperation, ZeroDivisionError): ...
class Inexact(DecimalException): ...
class InvalidContext(InvalidOperation): ...
class Rounded(DecimalException): ...
class Subnormal(DecimalException): ...
class Overflow(Inexact, Rounded): ...
class Underflow(Inexact, Rounded, Subnormal): ...
class FloatOperation(DecimalException, TypeError): ...
def setcontext(context: Context, /) -> None: ...
def getcontext() -> Context: ...
@@ -67,215 +69,6 @@ if sys.version_info >= (3, 11):
else:
def localcontext(ctx: Context | None = None) -> _ContextManager: ...
class Decimal:
def __new__(cls, value: _DecimalNew = ..., context: Context | None = ...) -> Self: ...
@classmethod
def from_float(cls, f: float, /) -> Self: ...
def __bool__(self) -> bool: ...
def compare(self, other: _Decimal, context: Context | None = None) -> Decimal: ...
def __hash__(self) -> int: ...
def as_tuple(self) -> DecimalTuple: ...
def as_integer_ratio(self) -> tuple[int, int]: ...
def to_eng_string(self, context: Context | None = None) -> str: ...
def __abs__(self) -> Decimal: ...
def __add__(self, value: _Decimal, /) -> Decimal: ...
def __divmod__(self, value: _Decimal, /) -> tuple[Decimal, Decimal]: ...
def __eq__(self, value: object, /) -> bool: ...
def __floordiv__(self, value: _Decimal, /) -> Decimal: ...
def __ge__(self, value: _ComparableNum, /) -> bool: ...
def __gt__(self, value: _ComparableNum, /) -> bool: ...
def __le__(self, value: _ComparableNum, /) -> bool: ...
def __lt__(self, value: _ComparableNum, /) -> bool: ...
def __mod__(self, value: _Decimal, /) -> Decimal: ...
def __mul__(self, value: _Decimal, /) -> Decimal: ...
def __neg__(self) -> Decimal: ...
def __pos__(self) -> Decimal: ...
def __pow__(self, value: _Decimal, mod: _Decimal | None = None, /) -> Decimal: ...
def __radd__(self, value: _Decimal, /) -> Decimal: ...
def __rdivmod__(self, value: _Decimal, /) -> tuple[Decimal, Decimal]: ...
def __rfloordiv__(self, value: _Decimal, /) -> Decimal: ...
def __rmod__(self, value: _Decimal, /) -> Decimal: ...
def __rmul__(self, value: _Decimal, /) -> Decimal: ...
def __rsub__(self, value: _Decimal, /) -> Decimal: ...
def __rtruediv__(self, value: _Decimal, /) -> Decimal: ...
def __sub__(self, value: _Decimal, /) -> Decimal: ...
def __truediv__(self, value: _Decimal, /) -> Decimal: ...
def remainder_near(self, other: _Decimal, context: Context | None = None) -> Decimal: ...
def __float__(self) -> float: ...
def __int__(self) -> int: ...
def __trunc__(self) -> int: ...
@property
def real(self) -> Decimal: ...
@property
def imag(self) -> Decimal: ...
def conjugate(self) -> Decimal: ...
def __complex__(self) -> complex: ...
@overload
def __round__(self) -> int: ...
@overload
def __round__(self, ndigits: int, /) -> Decimal: ...
def __floor__(self) -> int: ...
def __ceil__(self) -> int: ...
def fma(self, other: _Decimal, third: _Decimal, context: Context | None = None) -> Decimal: ...
def __rpow__(self, value: _Decimal, mod: Context | None = None, /) -> Decimal: ...
def normalize(self, context: Context | None = None) -> Decimal: ...
def quantize(self, exp: _Decimal, rounding: str | None = None, context: Context | None = None) -> Decimal: ...
def same_quantum(self, other: _Decimal, context: Context | None = None) -> bool: ...
def to_integral_exact(self, rounding: str | None = None, context: Context | None = None) -> Decimal: ...
def to_integral_value(self, rounding: str | None = None, context: Context | None = None) -> Decimal: ...
def to_integral(self, rounding: str | None = None, context: Context | None = None) -> Decimal: ...
def sqrt(self, context: Context | None = None) -> Decimal: ...
def max(self, other: _Decimal, context: Context | None = None) -> Decimal: ...
def min(self, other: _Decimal, context: Context | None = None) -> Decimal: ...
def adjusted(self) -> int: ...
def canonical(self) -> Decimal: ...
def compare_signal(self, other: _Decimal, context: Context | None = None) -> Decimal: ...
def compare_total(self, other: _Decimal, context: Context | None = None) -> Decimal: ...
def compare_total_mag(self, other: _Decimal, context: Context | None = None) -> Decimal: ...
def copy_abs(self) -> Decimal: ...
def copy_negate(self) -> Decimal: ...
def copy_sign(self, other: _Decimal, context: Context | None = None) -> Decimal: ...
def exp(self, context: Context | None = None) -> Decimal: ...
def is_canonical(self) -> bool: ...
def is_finite(self) -> bool: ...
def is_infinite(self) -> bool: ...
def is_nan(self) -> bool: ...
def is_normal(self, context: Context | None = None) -> bool: ...
def is_qnan(self) -> bool: ...
def is_signed(self) -> bool: ...
def is_snan(self) -> bool: ...
def is_subnormal(self, context: Context | None = None) -> bool: ...
def is_zero(self) -> bool: ...
def ln(self, context: Context | None = None) -> Decimal: ...
def log10(self, context: Context | None = None) -> Decimal: ...
def logb(self, context: Context | None = None) -> Decimal: ...
def logical_and(self, other: _Decimal, context: Context | None = None) -> Decimal: ...
def logical_invert(self, context: Context | None = None) -> Decimal: ...
def logical_or(self, other: _Decimal, context: Context | None = None) -> Decimal: ...
def logical_xor(self, other: _Decimal, context: Context | None = None) -> Decimal: ...
def max_mag(self, other: _Decimal, context: Context | None = None) -> Decimal: ...
def min_mag(self, other: _Decimal, context: Context | None = None) -> Decimal: ...
def next_minus(self, context: Context | None = None) -> Decimal: ...
def next_plus(self, context: Context | None = None) -> Decimal: ...
def next_toward(self, other: _Decimal, context: Context | None = None) -> Decimal: ...
def number_class(self, context: Context | None = None) -> str: ...
def radix(self) -> Decimal: ...
def rotate(self, other: _Decimal, context: Context | None = None) -> Decimal: ...
def scaleb(self, other: _Decimal, context: Context | None = None) -> Decimal: ...
def shift(self, other: _Decimal, context: Context | None = None) -> Decimal: ...
def __reduce__(self) -> tuple[type[Self], tuple[str]]: ...
def __copy__(self) -> Self: ...
def __deepcopy__(self, memo: Any, /) -> Self: ...
def __format__(self, specifier: str, context: Context | None = ..., /) -> str: ...
class _ContextManager:
new_context: Context
saved_context: Context
def __init__(self, new_context: Context) -> None: ...
def __enter__(self) -> Context: ...
def __exit__(self, t: type[BaseException] | None, v: BaseException | None, tb: TracebackType | None) -> None: ...
_TrapType: TypeAlias = type[DecimalException]
class Context:
# TODO: Context doesn't allow you to delete *any* attributes from instances of the class at runtime,
# even settable attributes like `prec` and `rounding`,
# but that's inexpressable in the stub.
# Type checkers either ignore it or misinterpret it
# if you add a `def __delattr__(self, name: str, /) -> NoReturn` method to the stub
prec: int
rounding: str
Emin: int
Emax: int
capitals: int
clamp: int
traps: dict[_TrapType, bool]
flags: dict[_TrapType, bool]
def __init__(
self,
prec: int | None = ...,
rounding: str | None = ...,
Emin: int | None = ...,
Emax: int | None = ...,
capitals: int | None = ...,
clamp: int | None = ...,
flags: None | dict[_TrapType, bool] | Container[_TrapType] = ...,
traps: None | dict[_TrapType, bool] | Container[_TrapType] = ...,
_ignored_flags: list[_TrapType] | None = ...,
) -> None: ...
def __reduce__(self) -> tuple[type[Self], tuple[Any, ...]]: ...
def clear_flags(self) -> None: ...
def clear_traps(self) -> None: ...
def copy(self) -> Context: ...
def __copy__(self) -> Context: ...
# see https://github.com/python/cpython/issues/94107
__hash__: ClassVar[None] # type: ignore[assignment]
def Etiny(self) -> int: ...
def Etop(self) -> int: ...
def create_decimal(self, num: _DecimalNew = "0", /) -> Decimal: ...
def create_decimal_from_float(self, f: float, /) -> Decimal: ...
def abs(self, x: _Decimal, /) -> Decimal: ...
def add(self, x: _Decimal, y: _Decimal, /) -> Decimal: ...
def canonical(self, x: Decimal, /) -> Decimal: ...
def compare(self, x: _Decimal, y: _Decimal, /) -> Decimal: ...
def compare_signal(self, x: _Decimal, y: _Decimal, /) -> Decimal: ...
def compare_total(self, x: _Decimal, y: _Decimal, /) -> Decimal: ...
def compare_total_mag(self, x: _Decimal, y: _Decimal, /) -> Decimal: ...
def copy_abs(self, x: _Decimal, /) -> Decimal: ...
def copy_decimal(self, x: _Decimal, /) -> Decimal: ...
def copy_negate(self, x: _Decimal, /) -> Decimal: ...
def copy_sign(self, x: _Decimal, y: _Decimal, /) -> Decimal: ...
def divide(self, x: _Decimal, y: _Decimal, /) -> Decimal: ...
def divide_int(self, x: _Decimal, y: _Decimal, /) -> Decimal: ...
def divmod(self, x: _Decimal, y: _Decimal, /) -> tuple[Decimal, Decimal]: ...
def exp(self, x: _Decimal, /) -> Decimal: ...
def fma(self, x: _Decimal, y: _Decimal, z: _Decimal, /) -> Decimal: ...
def is_canonical(self, x: _Decimal, /) -> bool: ...
def is_finite(self, x: _Decimal, /) -> bool: ...
def is_infinite(self, x: _Decimal, /) -> bool: ...
def is_nan(self, x: _Decimal, /) -> bool: ...
def is_normal(self, x: _Decimal, /) -> bool: ...
def is_qnan(self, x: _Decimal, /) -> bool: ...
def is_signed(self, x: _Decimal, /) -> bool: ...
def is_snan(self, x: _Decimal, /) -> bool: ...
def is_subnormal(self, x: _Decimal, /) -> bool: ...
def is_zero(self, x: _Decimal, /) -> bool: ...
def ln(self, x: _Decimal, /) -> Decimal: ...
def log10(self, x: _Decimal, /) -> Decimal: ...
def logb(self, x: _Decimal, /) -> Decimal: ...
def logical_and(self, x: _Decimal, y: _Decimal, /) -> Decimal: ...
def logical_invert(self, x: _Decimal, /) -> Decimal: ...
def logical_or(self, x: _Decimal, y: _Decimal, /) -> Decimal: ...
def logical_xor(self, x: _Decimal, y: _Decimal, /) -> Decimal: ...
def max(self, x: _Decimal, y: _Decimal, /) -> Decimal: ...
def max_mag(self, x: _Decimal, y: _Decimal, /) -> Decimal: ...
def min(self, x: _Decimal, y: _Decimal, /) -> Decimal: ...
def min_mag(self, x: _Decimal, y: _Decimal, /) -> Decimal: ...
def minus(self, x: _Decimal, /) -> Decimal: ...
def multiply(self, x: _Decimal, y: _Decimal, /) -> Decimal: ...
def next_minus(self, x: _Decimal, /) -> Decimal: ...
def next_plus(self, x: _Decimal, /) -> Decimal: ...
def next_toward(self, x: _Decimal, y: _Decimal, /) -> Decimal: ...
def normalize(self, x: _Decimal, /) -> Decimal: ...
def number_class(self, x: _Decimal, /) -> str: ...
def plus(self, x: _Decimal, /) -> Decimal: ...
def power(self, a: _Decimal, b: _Decimal, modulo: _Decimal | None = None) -> Decimal: ...
def quantize(self, x: _Decimal, y: _Decimal, /) -> Decimal: ...
def radix(self) -> Decimal: ...
def remainder(self, x: _Decimal, y: _Decimal, /) -> Decimal: ...
def remainder_near(self, x: _Decimal, y: _Decimal, /) -> Decimal: ...
def rotate(self, x: _Decimal, y: _Decimal, /) -> Decimal: ...
def same_quantum(self, x: _Decimal, y: _Decimal, /) -> bool: ...
def scaleb(self, x: _Decimal, y: _Decimal, /) -> Decimal: ...
def shift(self, x: _Decimal, y: _Decimal, /) -> Decimal: ...
def sqrt(self, x: _Decimal, /) -> Decimal: ...
def subtract(self, x: _Decimal, y: _Decimal, /) -> Decimal: ...
def to_eng_string(self, x: _Decimal, /) -> str: ...
def to_sci_string(self, x: _Decimal, /) -> str: ...
def to_integral_exact(self, x: _Decimal, /) -> Decimal: ...
def to_integral_value(self, x: _Decimal, /) -> Decimal: ...
def to_integral(self, x: _Decimal, /) -> Decimal: ...
DefaultContext: Context
BasicContext: Context
ExtendedContext: Context

View File

@@ -0,0 +1,195 @@
import builtins
import codecs
import sys
from _typeshed import FileDescriptorOrPath, MaybeNone, ReadableBuffer, WriteableBuffer
from collections.abc import Callable, Iterable, Iterator
from io import BufferedIOBase, RawIOBase, TextIOBase, UnsupportedOperation as UnsupportedOperation
from os import _Opener
from types import TracebackType
from typing import IO, Any, BinaryIO, Final, Generic, Literal, Protocol, TextIO, TypeVar, overload, type_check_only
from typing_extensions import Self
_T = TypeVar("_T")
DEFAULT_BUFFER_SIZE: Final = 8192
open = builtins.open
def open_code(path: str) -> IO[bytes]: ...
BlockingIOError = builtins.BlockingIOError
class _IOBase:
def __iter__(self) -> Iterator[bytes]: ...
def __next__(self) -> bytes: ...
def __enter__(self) -> Self: ...
def __exit__(
self, exc_type: type[BaseException] | None, exc_val: BaseException | None, exc_tb: TracebackType | None
) -> None: ...
def close(self) -> None: ...
def fileno(self) -> int: ...
def flush(self) -> None: ...
def isatty(self) -> bool: ...
def readable(self) -> bool: ...
read: Callable[..., Any]
def readlines(self, hint: int = -1, /) -> list[bytes]: ...
def seek(self, offset: int, whence: int = ..., /) -> int: ...
def seekable(self) -> bool: ...
def tell(self) -> int: ...
def truncate(self, size: int | None = ..., /) -> int: ...
def writable(self) -> bool: ...
write: Callable[..., Any]
def writelines(self, lines: Iterable[ReadableBuffer], /) -> None: ...
def readline(self, size: int | None = -1, /) -> bytes: ...
def __del__(self) -> None: ...
@property
def closed(self) -> bool: ...
def _checkClosed(self) -> None: ... # undocumented
class _RawIOBase(_IOBase):
def readall(self) -> bytes: ...
# The following methods can return None if the file is in non-blocking mode
# and no data is available.
def readinto(self, buffer: WriteableBuffer, /) -> int | MaybeNone: ...
def write(self, b: ReadableBuffer, /) -> int | MaybeNone: ...
def read(self, size: int = -1, /) -> bytes | MaybeNone: ...
class _BufferedIOBase(_IOBase):
def detach(self) -> RawIOBase: ...
def readinto(self, buffer: WriteableBuffer, /) -> int: ...
def write(self, buffer: ReadableBuffer, /) -> int: ...
def readinto1(self, buffer: WriteableBuffer, /) -> int: ...
def read(self, size: int | None = ..., /) -> bytes: ...
def read1(self, size: int = ..., /) -> bytes: ...
class FileIO(RawIOBase, _RawIOBase, BinaryIO): # type: ignore[misc] # incompatible definitions of writelines in the base classes
mode: str
# The type of "name" equals the argument passed in to the constructor,
# but that can make FileIO incompatible with other I/O types that assume
# "name" is a str. In the future, making FileIO generic might help.
name: Any
def __init__(
self, file: FileDescriptorOrPath, mode: str = ..., closefd: bool = ..., opener: _Opener | None = ...
) -> None: ...
@property
def closefd(self) -> bool: ...
class BytesIO(BufferedIOBase, _BufferedIOBase, BinaryIO): # type: ignore[misc] # incompatible definitions of methods in the base classes
def __init__(self, initial_bytes: ReadableBuffer = ...) -> None: ...
# BytesIO does not contain a "name" field. This workaround is necessary
# to allow BytesIO sub-classes to add this field, as it is defined
# as a read-only property on IO[].
name: Any
def getvalue(self) -> bytes: ...
def getbuffer(self) -> memoryview: ...
def read1(self, size: int | None = -1, /) -> bytes: ...
class BufferedReader(BufferedIOBase, _BufferedIOBase, BinaryIO): # type: ignore[misc] # incompatible definitions of methods in the base classes
raw: RawIOBase
def __init__(self, raw: RawIOBase, buffer_size: int = ...) -> None: ...
def peek(self, size: int = 0, /) -> bytes: ...
class BufferedWriter(BufferedIOBase, _BufferedIOBase, BinaryIO): # type: ignore[misc] # incompatible definitions of writelines in the base classes
raw: RawIOBase
def __init__(self, raw: RawIOBase, buffer_size: int = ...) -> None: ...
def write(self, buffer: ReadableBuffer, /) -> int: ...
class BufferedRandom(BufferedReader, BufferedWriter, BufferedIOBase, _BufferedIOBase): # type: ignore[misc] # incompatible definitions of methods in the base classes
def seek(self, target: int, whence: int = 0, /) -> int: ... # stubtest needs this
class BufferedRWPair(BufferedIOBase, _BufferedIOBase):
def __init__(self, reader: RawIOBase, writer: RawIOBase, buffer_size: int = ...) -> None: ...
def peek(self, size: int = ..., /) -> bytes: ...
class _TextIOBase(_IOBase):
encoding: str
errors: str | None
newlines: str | tuple[str, ...] | None
def __iter__(self) -> Iterator[str]: ... # type: ignore[override]
def __next__(self) -> str: ... # type: ignore[override]
def detach(self) -> BinaryIO: ...
def write(self, s: str, /) -> int: ...
def writelines(self, lines: Iterable[str], /) -> None: ... # type: ignore[override]
def readline(self, size: int = ..., /) -> str: ... # type: ignore[override]
def readlines(self, hint: int = -1, /) -> list[str]: ... # type: ignore[override]
def read(self, size: int | None = ..., /) -> str: ...
@type_check_only
class _WrappedBuffer(Protocol):
# "name" is wrapped by TextIOWrapper. Its type is inconsistent between
# the various I/O types, see the comments on TextIOWrapper.name and
# TextIO.name.
@property
def name(self) -> Any: ...
@property
def closed(self) -> bool: ...
def read(self, size: int = ..., /) -> ReadableBuffer: ...
# Optional: def read1(self, size: int, /) -> ReadableBuffer: ...
def write(self, b: bytes, /) -> object: ...
def flush(self) -> object: ...
def close(self) -> object: ...
def seekable(self) -> bool: ...
def readable(self) -> bool: ...
def writable(self) -> bool: ...
def truncate(self, size: int, /) -> int: ...
def fileno(self) -> int: ...
def isatty(self) -> bool: ...
# Optional: Only needs to be present if seekable() returns True.
# def seek(self, offset: Literal[0], whence: Literal[2]) -> int: ...
# def tell(self) -> int: ...
_BufferT_co = TypeVar("_BufferT_co", bound=_WrappedBuffer, default=_WrappedBuffer, covariant=True)
class TextIOWrapper(TextIOBase, _TextIOBase, TextIO, Generic[_BufferT_co]): # type: ignore[misc] # incompatible definitions of write in the base classes
def __init__(
self,
buffer: _BufferT_co,
encoding: str | None = None,
errors: str | None = None,
newline: str | None = None,
line_buffering: bool = False,
write_through: bool = False,
) -> None: ...
# Equals the "buffer" argument passed in to the constructor.
@property
def buffer(self) -> _BufferT_co: ... # type: ignore[override]
@property
def line_buffering(self) -> bool: ...
@property
def write_through(self) -> bool: ...
def reconfigure(
self,
*,
encoding: str | None = None,
errors: str | None = None,
newline: str | None = None,
line_buffering: bool | None = None,
write_through: bool | None = None,
) -> None: ...
def readline(self, size: int = -1, /) -> str: ... # type: ignore[override]
# Equals the "buffer" argument passed in to the constructor.
def detach(self) -> _BufferT_co: ... # type: ignore[override]
# TextIOWrapper's version of seek only supports a limited subset of
# operations.
def seek(self, cookie: int, whence: int = 0, /) -> int: ...
class StringIO(TextIOWrapper, TextIOBase, _TextIOBase): # type: ignore[misc] # incompatible definitions of write in the base classes
def __init__(self, initial_value: str | None = ..., newline: str | None = ...) -> None: ...
# StringIO does not contain a "name" field. This workaround is necessary
# to allow StringIO sub-classes to add this field, as it is defined
# as a read-only property on IO[].
name: Any
def getvalue(self) -> str: ...
class IncrementalNewlineDecoder(codecs.IncrementalDecoder):
def __init__(self, decoder: codecs.IncrementalDecoder | None, translate: bool, errors: str = ...) -> None: ...
def decode(self, input: ReadableBuffer | str, final: bool = False) -> str: ...
@property
def newlines(self) -> str | tuple[str, ...] | None: ...
def setstate(self, state: tuple[bytes, int], /) -> None: ...
if sys.version_info >= (3, 10):
@overload
def text_encoding(encoding: None, stacklevel: int = 2, /) -> Literal["locale", "utf-8"]: ...
@overload
def text_encoding(encoding: _T, stacklevel: int = 2, /) -> _T: ...

View File

@@ -1,18 +1,16 @@
import sys
from _typeshed import SupportsGetItem
from collections.abc import Callable, Container, Iterable, MutableMapping, MutableSequence, Sequence
from typing import Any, AnyStr, Generic, Protocol, SupportsAbs, SupportsIndex, TypeVar, final, overload
from typing_extensions import ParamSpec, TypeAlias, TypeIs, TypeVarTuple, Unpack
from operator import attrgetter as attrgetter, itemgetter as itemgetter, methodcaller as methodcaller
from typing import Any, AnyStr, Protocol, SupportsAbs, SupportsIndex, TypeVar, overload
from typing_extensions import ParamSpec, TypeAlias, TypeIs
_R = TypeVar("_R")
_T = TypeVar("_T")
_T_co = TypeVar("_T_co", covariant=True)
_T1 = TypeVar("_T1")
_T2 = TypeVar("_T2")
_K = TypeVar("_K")
_V = TypeVar("_V")
_P = ParamSpec("_P")
_Ts = TypeVarTuple("_Ts")
# The following protocols return "Any" instead of bool, since the comparison
# operators can be overloaded to return an arbitrary object. For example,
@@ -92,40 +90,6 @@ def setitem(a: MutableSequence[_T], b: slice, c: Sequence[_T], /) -> None: ...
@overload
def setitem(a: MutableMapping[_K, _V], b: _K, c: _V, /) -> None: ...
def length_hint(obj: object, default: int = 0, /) -> int: ...
@final
class attrgetter(Generic[_T_co]):
@overload
def __new__(cls, attr: str, /) -> attrgetter[Any]: ...
@overload
def __new__(cls, attr: str, attr2: str, /) -> attrgetter[tuple[Any, Any]]: ...
@overload
def __new__(cls, attr: str, attr2: str, attr3: str, /) -> attrgetter[tuple[Any, Any, Any]]: ...
@overload
def __new__(cls, attr: str, attr2: str, attr3: str, attr4: str, /) -> attrgetter[tuple[Any, Any, Any, Any]]: ...
@overload
def __new__(cls, attr: str, /, *attrs: str) -> attrgetter[tuple[Any, ...]]: ...
def __call__(self, obj: Any, /) -> _T_co: ...
@final
class itemgetter(Generic[_T_co]):
@overload
def __new__(cls, item: _T, /) -> itemgetter[_T]: ...
@overload
def __new__(cls, item1: _T1, item2: _T2, /, *items: Unpack[_Ts]) -> itemgetter[tuple[_T1, _T2, Unpack[_Ts]]]: ...
# __key: _KT_contra in SupportsGetItem seems to be causing variance issues, ie:
# TypeVar "_KT_contra@SupportsGetItem" is contravariant
# "tuple[int, int]" is incompatible with protocol "SupportsIndex"
# preventing [_T_co, ...] instead of [Any, ...]
#
# A suspected mypy issue prevents using [..., _T] instead of [..., Any] here.
# https://github.com/python/mypy/issues/14032
def __call__(self, obj: SupportsGetItem[Any, Any]) -> Any: ...
@final
class methodcaller:
def __init__(self, name: str, /, *args: Any, **kwargs: Any) -> None: ...
def __call__(self, obj: Any) -> Any: ...
def iadd(a: Any, b: Any, /) -> Any: ...
def iand(a: Any, b: Any, /) -> Any: ...
def iconcat(a: Any, b: Any, /) -> Any: ...

View File

@@ -1,6 +1,7 @@
import sys
from _typeshed import ReadableBuffer, WriteableBuffer
from collections.abc import Iterable
from socket import error as error, gaierror as gaierror, herror as herror, timeout as timeout
from typing import Any, SupportsIndex, overload
from typing_extensions import TypeAlias
@@ -666,18 +667,6 @@ if sys.platform != "win32":
if sys.platform != "win32" and sys.platform != "darwin":
IPX_TYPE: int
# ===== Exceptions =====
error = OSError
class herror(error): ...
class gaierror(error): ...
if sys.version_info >= (3, 10):
timeout = TimeoutError
else:
class timeout(error): ...
# ===== Classes =====
class socket:
@@ -687,8 +676,9 @@ class socket:
def type(self) -> int: ...
@property
def proto(self) -> int: ...
# F811: "Redefinition of unused `timeout`"
@property
def timeout(self) -> float | None: ...
def timeout(self) -> float | None: ... # noqa: F811
if sys.platform == "win32":
def __init__(
self, family: int = ..., type: int = ..., proto: int = ..., fileno: SupportsIndex | bytes | None = ...
@@ -788,7 +778,9 @@ def inet_ntoa(packed_ip: ReadableBuffer, /) -> str: ...
def inet_pton(address_family: int, ip_string: str, /) -> bytes: ...
def inet_ntop(address_family: int, packed_ip: ReadableBuffer, /) -> str: ...
def getdefaulttimeout() -> float | None: ...
def setdefaulttimeout(timeout: float | None, /) -> None: ...
# F811: "Redefinition of unused `timeout`"
def setdefaulttimeout(timeout: float | None, /) -> None: ... # noqa: F811
if sys.platform != "win32":
def sethostname(name: str, /) -> None: ...

View File

@@ -0,0 +1,312 @@
import sys
from _typeshed import ReadableBuffer, StrOrBytesPath
from collections.abc import Callable
from sqlite3 import (
Connection as Connection,
Cursor as Cursor,
DatabaseError as DatabaseError,
DataError as DataError,
Error as Error,
IntegrityError as IntegrityError,
InterfaceError as InterfaceError,
InternalError as InternalError,
NotSupportedError as NotSupportedError,
OperationalError as OperationalError,
PrepareProtocol as PrepareProtocol,
ProgrammingError as ProgrammingError,
Row as Row,
Warning as Warning,
)
from typing import Any, Final, Literal, TypeVar, overload
from typing_extensions import TypeAlias
if sys.version_info >= (3, 11):
from sqlite3 import Blob as Blob
_T = TypeVar("_T")
_ConnectionT = TypeVar("_ConnectionT", bound=Connection)
_SqliteData: TypeAlias = str | ReadableBuffer | int | float | None
_Adapter: TypeAlias = Callable[[_T], _SqliteData]
_Converter: TypeAlias = Callable[[bytes], Any]
PARSE_COLNAMES: Final[int]
PARSE_DECLTYPES: Final[int]
SQLITE_ALTER_TABLE: Final[int]
SQLITE_ANALYZE: Final[int]
SQLITE_ATTACH: Final[int]
SQLITE_CREATE_INDEX: Final[int]
SQLITE_CREATE_TABLE: Final[int]
SQLITE_CREATE_TEMP_INDEX: Final[int]
SQLITE_CREATE_TEMP_TABLE: Final[int]
SQLITE_CREATE_TEMP_TRIGGER: Final[int]
SQLITE_CREATE_TEMP_VIEW: Final[int]
SQLITE_CREATE_TRIGGER: Final[int]
SQLITE_CREATE_VIEW: Final[int]
SQLITE_CREATE_VTABLE: Final[int]
SQLITE_DELETE: Final[int]
SQLITE_DENY: Final[int]
SQLITE_DETACH: Final[int]
SQLITE_DONE: Final[int]
SQLITE_DROP_INDEX: Final[int]
SQLITE_DROP_TABLE: Final[int]
SQLITE_DROP_TEMP_INDEX: Final[int]
SQLITE_DROP_TEMP_TABLE: Final[int]
SQLITE_DROP_TEMP_TRIGGER: Final[int]
SQLITE_DROP_TEMP_VIEW: Final[int]
SQLITE_DROP_TRIGGER: Final[int]
SQLITE_DROP_VIEW: Final[int]
SQLITE_DROP_VTABLE: Final[int]
SQLITE_FUNCTION: Final[int]
SQLITE_IGNORE: Final[int]
SQLITE_INSERT: Final[int]
SQLITE_OK: Final[int]
SQLITE_PRAGMA: Final[int]
SQLITE_READ: Final[int]
SQLITE_RECURSIVE: Final[int]
SQLITE_REINDEX: Final[int]
SQLITE_SAVEPOINT: Final[int]
SQLITE_SELECT: Final[int]
SQLITE_TRANSACTION: Final[int]
SQLITE_UPDATE: Final[int]
adapters: dict[tuple[type[Any], type[Any]], _Adapter[Any]]
converters: dict[str, _Converter]
sqlite_version: str
if sys.version_info < (3, 12):
version: str
if sys.version_info >= (3, 12):
LEGACY_TRANSACTION_CONTROL: Final[int]
SQLITE_DBCONFIG_DEFENSIVE: Final[int]
SQLITE_DBCONFIG_DQS_DDL: Final[int]
SQLITE_DBCONFIG_DQS_DML: Final[int]
SQLITE_DBCONFIG_ENABLE_FKEY: Final[int]
SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER: Final[int]
SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION: Final[int]
SQLITE_DBCONFIG_ENABLE_QPSG: Final[int]
SQLITE_DBCONFIG_ENABLE_TRIGGER: Final[int]
SQLITE_DBCONFIG_ENABLE_VIEW: Final[int]
SQLITE_DBCONFIG_LEGACY_ALTER_TABLE: Final[int]
SQLITE_DBCONFIG_LEGACY_FILE_FORMAT: Final[int]
SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE: Final[int]
SQLITE_DBCONFIG_RESET_DATABASE: Final[int]
SQLITE_DBCONFIG_TRIGGER_EQP: Final[int]
SQLITE_DBCONFIG_TRUSTED_SCHEMA: Final[int]
SQLITE_DBCONFIG_WRITABLE_SCHEMA: Final[int]
if sys.version_info >= (3, 11):
SQLITE_ABORT: Final[int]
SQLITE_ABORT_ROLLBACK: Final[int]
SQLITE_AUTH: Final[int]
SQLITE_AUTH_USER: Final[int]
SQLITE_BUSY: Final[int]
SQLITE_BUSY_RECOVERY: Final[int]
SQLITE_BUSY_SNAPSHOT: Final[int]
SQLITE_BUSY_TIMEOUT: Final[int]
SQLITE_CANTOPEN: Final[int]
SQLITE_CANTOPEN_CONVPATH: Final[int]
SQLITE_CANTOPEN_DIRTYWAL: Final[int]
SQLITE_CANTOPEN_FULLPATH: Final[int]
SQLITE_CANTOPEN_ISDIR: Final[int]
SQLITE_CANTOPEN_NOTEMPDIR: Final[int]
SQLITE_CANTOPEN_SYMLINK: Final[int]
SQLITE_CONSTRAINT: Final[int]
SQLITE_CONSTRAINT_CHECK: Final[int]
SQLITE_CONSTRAINT_COMMITHOOK: Final[int]
SQLITE_CONSTRAINT_FOREIGNKEY: Final[int]
SQLITE_CONSTRAINT_FUNCTION: Final[int]
SQLITE_CONSTRAINT_NOTNULL: Final[int]
SQLITE_CONSTRAINT_PINNED: Final[int]
SQLITE_CONSTRAINT_PRIMARYKEY: Final[int]
SQLITE_CONSTRAINT_ROWID: Final[int]
SQLITE_CONSTRAINT_TRIGGER: Final[int]
SQLITE_CONSTRAINT_UNIQUE: Final[int]
SQLITE_CONSTRAINT_VTAB: Final[int]
SQLITE_CORRUPT: Final[int]
SQLITE_CORRUPT_INDEX: Final[int]
SQLITE_CORRUPT_SEQUENCE: Final[int]
SQLITE_CORRUPT_VTAB: Final[int]
SQLITE_EMPTY: Final[int]
SQLITE_ERROR: Final[int]
SQLITE_ERROR_MISSING_COLLSEQ: Final[int]
SQLITE_ERROR_RETRY: Final[int]
SQLITE_ERROR_SNAPSHOT: Final[int]
SQLITE_FORMAT: Final[int]
SQLITE_FULL: Final[int]
SQLITE_INTERNAL: Final[int]
SQLITE_INTERRUPT: Final[int]
SQLITE_IOERR: Final[int]
SQLITE_IOERR_ACCESS: Final[int]
SQLITE_IOERR_AUTH: Final[int]
SQLITE_IOERR_BEGIN_ATOMIC: Final[int]
SQLITE_IOERR_BLOCKED: Final[int]
SQLITE_IOERR_CHECKRESERVEDLOCK: Final[int]
SQLITE_IOERR_CLOSE: Final[int]
SQLITE_IOERR_COMMIT_ATOMIC: Final[int]
SQLITE_IOERR_CONVPATH: Final[int]
SQLITE_IOERR_CORRUPTFS: Final[int]
SQLITE_IOERR_DATA: Final[int]
SQLITE_IOERR_DELETE: Final[int]
SQLITE_IOERR_DELETE_NOENT: Final[int]
SQLITE_IOERR_DIR_CLOSE: Final[int]
SQLITE_IOERR_DIR_FSYNC: Final[int]
SQLITE_IOERR_FSTAT: Final[int]
SQLITE_IOERR_FSYNC: Final[int]
SQLITE_IOERR_GETTEMPPATH: Final[int]
SQLITE_IOERR_LOCK: Final[int]
SQLITE_IOERR_MMAP: Final[int]
SQLITE_IOERR_NOMEM: Final[int]
SQLITE_IOERR_RDLOCK: Final[int]
SQLITE_IOERR_READ: Final[int]
SQLITE_IOERR_ROLLBACK_ATOMIC: Final[int]
SQLITE_IOERR_SEEK: Final[int]
SQLITE_IOERR_SHMLOCK: Final[int]
SQLITE_IOERR_SHMMAP: Final[int]
SQLITE_IOERR_SHMOPEN: Final[int]
SQLITE_IOERR_SHMSIZE: Final[int]
SQLITE_IOERR_SHORT_READ: Final[int]
SQLITE_IOERR_TRUNCATE: Final[int]
SQLITE_IOERR_UNLOCK: Final[int]
SQLITE_IOERR_VNODE: Final[int]
SQLITE_IOERR_WRITE: Final[int]
SQLITE_LIMIT_ATTACHED: Final[int]
SQLITE_LIMIT_COLUMN: Final[int]
SQLITE_LIMIT_COMPOUND_SELECT: Final[int]
SQLITE_LIMIT_EXPR_DEPTH: Final[int]
SQLITE_LIMIT_FUNCTION_ARG: Final[int]
SQLITE_LIMIT_LENGTH: Final[int]
SQLITE_LIMIT_LIKE_PATTERN_LENGTH: Final[int]
SQLITE_LIMIT_SQL_LENGTH: Final[int]
SQLITE_LIMIT_TRIGGER_DEPTH: Final[int]
SQLITE_LIMIT_VARIABLE_NUMBER: Final[int]
SQLITE_LIMIT_VDBE_OP: Final[int]
SQLITE_LIMIT_WORKER_THREADS: Final[int]
SQLITE_LOCKED: Final[int]
SQLITE_LOCKED_SHAREDCACHE: Final[int]
SQLITE_LOCKED_VTAB: Final[int]
SQLITE_MISMATCH: Final[int]
SQLITE_MISUSE: Final[int]
SQLITE_NOLFS: Final[int]
SQLITE_NOMEM: Final[int]
SQLITE_NOTADB: Final[int]
SQLITE_NOTFOUND: Final[int]
SQLITE_NOTICE: Final[int]
SQLITE_NOTICE_RECOVER_ROLLBACK: Final[int]
SQLITE_NOTICE_RECOVER_WAL: Final[int]
SQLITE_OK_LOAD_PERMANENTLY: Final[int]
SQLITE_OK_SYMLINK: Final[int]
SQLITE_PERM: Final[int]
SQLITE_PROTOCOL: Final[int]
SQLITE_RANGE: Final[int]
SQLITE_READONLY: Final[int]
SQLITE_READONLY_CANTINIT: Final[int]
SQLITE_READONLY_CANTLOCK: Final[int]
SQLITE_READONLY_DBMOVED: Final[int]
SQLITE_READONLY_DIRECTORY: Final[int]
SQLITE_READONLY_RECOVERY: Final[int]
SQLITE_READONLY_ROLLBACK: Final[int]
SQLITE_ROW: Final[int]
SQLITE_SCHEMA: Final[int]
SQLITE_TOOBIG: Final[int]
SQLITE_WARNING: Final[int]
SQLITE_WARNING_AUTOINDEX: Final[int]
threadsafety: Final[int]
# Can take or return anything depending on what's in the registry.
@overload
def adapt(obj: Any, proto: Any, /) -> Any: ...
@overload
def adapt(obj: Any, proto: Any, alt: _T, /) -> Any | _T: ...
def complete_statement(statement: str) -> bool: ...
if sys.version_info >= (3, 12):
@overload
def connect(
database: StrOrBytesPath,
timeout: float = 5.0,
detect_types: int = 0,
isolation_level: Literal["DEFERRED", "EXCLUSIVE", "IMMEDIATE"] | None = "DEFERRED",
check_same_thread: bool = True,
cached_statements: int = 128,
uri: bool = False,
*,
autocommit: bool = ...,
) -> Connection: ...
@overload
def connect(
database: StrOrBytesPath,
timeout: float,
detect_types: int,
isolation_level: Literal["DEFERRED", "EXCLUSIVE", "IMMEDIATE"] | None,
check_same_thread: bool,
factory: type[_ConnectionT],
cached_statements: int = 128,
uri: bool = False,
*,
autocommit: bool = ...,
) -> _ConnectionT: ...
@overload
def connect(
database: StrOrBytesPath,
timeout: float = 5.0,
detect_types: int = 0,
isolation_level: Literal["DEFERRED", "EXCLUSIVE", "IMMEDIATE"] | None = "DEFERRED",
check_same_thread: bool = True,
*,
factory: type[_ConnectionT],
cached_statements: int = 128,
uri: bool = False,
autocommit: bool = ...,
) -> _ConnectionT: ...
else:
@overload
def connect(
database: StrOrBytesPath,
timeout: float = 5.0,
detect_types: int = 0,
isolation_level: Literal["DEFERRED", "EXCLUSIVE", "IMMEDIATE"] | None = "DEFERRED",
check_same_thread: bool = True,
cached_statements: int = 128,
uri: bool = False,
) -> Connection: ...
@overload
def connect(
database: StrOrBytesPath,
timeout: float,
detect_types: int,
isolation_level: Literal["DEFERRED", "EXCLUSIVE", "IMMEDIATE"] | None,
check_same_thread: bool,
factory: type[_ConnectionT],
cached_statements: int = 128,
uri: bool = False,
) -> _ConnectionT: ...
@overload
def connect(
database: StrOrBytesPath,
timeout: float = 5.0,
detect_types: int = 0,
isolation_level: Literal["DEFERRED", "EXCLUSIVE", "IMMEDIATE"] | None = "DEFERRED",
check_same_thread: bool = True,
*,
factory: type[_ConnectionT],
cached_statements: int = 128,
uri: bool = False,
) -> _ConnectionT: ...
def enable_callback_tracebacks(enable: bool, /) -> None: ...
if sys.version_info < (3, 12):
# takes a pos-or-keyword argument because there is a C wrapper
def enable_shared_cache(do_enable: int) -> None: ...
if sys.version_info >= (3, 10):
def register_adapter(type: type[_T], adapter: _Adapter[_T], /) -> None: ...
def register_converter(typename: str, converter: _Converter, /) -> None: ...
else:
def register_adapter(type: type[_T], caster: _Adapter[_T], /) -> None: ...
def register_converter(name: str, converter: _Converter, /) -> None: ...
if sys.version_info < (3, 10):
OptimizedUnicode = str

View File

@@ -0,0 +1,292 @@
import sys
from _typeshed import ReadableBuffer, StrOrBytesPath
from collections.abc import Callable
from ssl import (
SSLCertVerificationError as SSLCertVerificationError,
SSLContext,
SSLEOFError as SSLEOFError,
SSLError as SSLError,
SSLObject,
SSLSyscallError as SSLSyscallError,
SSLWantReadError as SSLWantReadError,
SSLWantWriteError as SSLWantWriteError,
SSLZeroReturnError as SSLZeroReturnError,
)
from typing import Any, Literal, TypedDict, final, overload
from typing_extensions import NotRequired, Self, TypeAlias
_PasswordType: TypeAlias = Callable[[], str | bytes | bytearray] | str | bytes | bytearray
_PCTRTT: TypeAlias = tuple[tuple[str, str], ...]
_PCTRTTT: TypeAlias = tuple[_PCTRTT, ...]
_PeerCertRetDictType: TypeAlias = dict[str, str | _PCTRTTT | _PCTRTT]
class _Cipher(TypedDict):
aead: bool
alg_bits: int
auth: str
description: str
digest: str | None
id: int
kea: str
name: str
protocol: str
strength_bits: int
symmetric: str
class _CertInfo(TypedDict):
subject: tuple[tuple[tuple[str, str], ...], ...]
issuer: tuple[tuple[tuple[str, str], ...], ...]
version: int
serialNumber: str
notBefore: str
notAfter: str
subjectAltName: NotRequired[tuple[tuple[str, str], ...] | None]
OCSP: NotRequired[tuple[str, ...] | None]
caIssuers: NotRequired[tuple[str, ...] | None]
crlDistributionPoints: NotRequired[tuple[str, ...] | None]
def RAND_add(string: str | ReadableBuffer, entropy: float, /) -> None: ...
def RAND_bytes(n: int, /) -> bytes: ...
if sys.version_info < (3, 12):
def RAND_pseudo_bytes(n: int, /) -> tuple[bytes, bool]: ...
if sys.version_info < (3, 10):
def RAND_egd(path: str) -> None: ...
def RAND_status() -> bool: ...
def get_default_verify_paths() -> tuple[str, str, str, str]: ...
if sys.platform == "win32":
_EnumRetType: TypeAlias = list[tuple[bytes, str, set[str] | bool]]
def enum_certificates(store_name: str) -> _EnumRetType: ...
def enum_crls(store_name: str) -> _EnumRetType: ...
def txt2obj(txt: str, name: bool = False) -> tuple[int, str, str, str]: ...
def nid2obj(nid: int, /) -> tuple[int, str, str, str]: ...
class _SSLContext:
check_hostname: bool
keylog_filename: str | None
maximum_version: int
minimum_version: int
num_tickets: int
options: int
post_handshake_auth: bool
protocol: int
if sys.version_info >= (3, 10):
security_level: int
sni_callback: Callable[[SSLObject, str, SSLContext], None | int] | None
verify_flags: int
verify_mode: int
def __new__(cls, protocol: int, /) -> Self: ...
def cert_store_stats(self) -> dict[str, int]: ...
@overload
def get_ca_certs(self, binary_form: Literal[False] = False) -> list[_PeerCertRetDictType]: ...
@overload
def get_ca_certs(self, binary_form: Literal[True]) -> list[bytes]: ...
@overload
def get_ca_certs(self, binary_form: bool = False) -> Any: ...
def get_ciphers(self) -> list[_Cipher]: ...
def load_cert_chain(
self, certfile: StrOrBytesPath, keyfile: StrOrBytesPath | None = None, password: _PasswordType | None = None
) -> None: ...
def load_dh_params(self, path: str, /) -> None: ...
def load_verify_locations(
self,
cafile: StrOrBytesPath | None = None,
capath: StrOrBytesPath | None = None,
cadata: str | ReadableBuffer | None = None,
) -> None: ...
def session_stats(self) -> dict[str, int]: ...
def set_ciphers(self, cipherlist: str, /) -> None: ...
def set_default_verify_paths(self) -> None: ...
def set_ecdh_curve(self, name: str, /) -> None: ...
if sys.version_info >= (3, 13):
def set_psk_client_callback(self, callback: Callable[[str | None], tuple[str | None, bytes]] | None) -> None: ...
def set_psk_server_callback(
self, callback: Callable[[str | None], tuple[str | None, bytes]] | None, identity_hint: str | None = None
) -> None: ...
@final
class MemoryBIO:
eof: bool
pending: int
def __new__(self) -> Self: ...
def read(self, size: int = -1, /) -> bytes: ...
def write(self, b: ReadableBuffer, /) -> int: ...
def write_eof(self) -> None: ...
@final
class SSLSession:
@property
def has_ticket(self) -> bool: ...
@property
def id(self) -> bytes: ...
@property
def ticket_lifetime_hint(self) -> int: ...
@property
def time(self) -> int: ...
@property
def timeout(self) -> int: ...
# _ssl.Certificate is weird: it can't be instantiated or subclassed.
# Instances can only be created via methods of the private _ssl._SSLSocket class,
# for which the relevant method signatures are:
#
# class _SSLSocket:
# def get_unverified_chain(self) -> list[Certificate] | None: ...
# def get_verified_chain(self) -> list[Certificate] | None: ...
#
# You can find a _ssl._SSLSocket object as the _sslobj attribute of a ssl.SSLSocket object
if sys.version_info >= (3, 10):
@final
class Certificate:
def get_info(self) -> _CertInfo: ...
@overload
def public_bytes(self) -> str: ...
@overload
def public_bytes(self, format: Literal[1] = 1, /) -> str: ... # ENCODING_PEM
@overload
def public_bytes(self, format: Literal[2], /) -> bytes: ... # ENCODING_DER
@overload
def public_bytes(self, format: int, /) -> str | bytes: ...
if sys.version_info < (3, 12):
err_codes_to_names: dict[tuple[int, int], str]
err_names_to_codes: dict[str, tuple[int, int]]
lib_codes_to_names: dict[int, str]
_DEFAULT_CIPHERS: str
# SSL error numbers
SSL_ERROR_ZERO_RETURN: int
SSL_ERROR_WANT_READ: int
SSL_ERROR_WANT_WRITE: int
SSL_ERROR_WANT_X509_LOOKUP: int
SSL_ERROR_SYSCALL: int
SSL_ERROR_SSL: int
SSL_ERROR_WANT_CONNECT: int
SSL_ERROR_EOF: int
SSL_ERROR_INVALID_ERROR_CODE: int
# verify modes
CERT_NONE: int
CERT_OPTIONAL: int
CERT_REQUIRED: int
# verify flags
VERIFY_DEFAULT: int
VERIFY_CRL_CHECK_LEAF: int
VERIFY_CRL_CHECK_CHAIN: int
VERIFY_X509_STRICT: int
VERIFY_X509_TRUSTED_FIRST: int
if sys.version_info >= (3, 10):
VERIFY_ALLOW_PROXY_CERTS: int
VERIFY_X509_PARTIAL_CHAIN: int
# alert descriptions
ALERT_DESCRIPTION_CLOSE_NOTIFY: int
ALERT_DESCRIPTION_UNEXPECTED_MESSAGE: int
ALERT_DESCRIPTION_BAD_RECORD_MAC: int
ALERT_DESCRIPTION_RECORD_OVERFLOW: int
ALERT_DESCRIPTION_DECOMPRESSION_FAILURE: int
ALERT_DESCRIPTION_HANDSHAKE_FAILURE: int
ALERT_DESCRIPTION_BAD_CERTIFICATE: int
ALERT_DESCRIPTION_UNSUPPORTED_CERTIFICATE: int
ALERT_DESCRIPTION_CERTIFICATE_REVOKED: int
ALERT_DESCRIPTION_CERTIFICATE_EXPIRED: int
ALERT_DESCRIPTION_CERTIFICATE_UNKNOWN: int
ALERT_DESCRIPTION_ILLEGAL_PARAMETER: int
ALERT_DESCRIPTION_UNKNOWN_CA: int
ALERT_DESCRIPTION_ACCESS_DENIED: int
ALERT_DESCRIPTION_DECODE_ERROR: int
ALERT_DESCRIPTION_DECRYPT_ERROR: int
ALERT_DESCRIPTION_PROTOCOL_VERSION: int
ALERT_DESCRIPTION_INSUFFICIENT_SECURITY: int
ALERT_DESCRIPTION_INTERNAL_ERROR: int
ALERT_DESCRIPTION_USER_CANCELLED: int
ALERT_DESCRIPTION_NO_RENEGOTIATION: int
ALERT_DESCRIPTION_UNSUPPORTED_EXTENSION: int
ALERT_DESCRIPTION_CERTIFICATE_UNOBTAINABLE: int
ALERT_DESCRIPTION_UNRECOGNIZED_NAME: int
ALERT_DESCRIPTION_BAD_CERTIFICATE_STATUS_RESPONSE: int
ALERT_DESCRIPTION_BAD_CERTIFICATE_HASH_VALUE: int
ALERT_DESCRIPTION_UNKNOWN_PSK_IDENTITY: int
# protocol versions
PROTOCOL_SSLv23: int
PROTOCOL_TLS: int
PROTOCOL_TLS_CLIENT: int
PROTOCOL_TLS_SERVER: int
PROTOCOL_TLSv1: int
PROTOCOL_TLSv1_1: int
PROTOCOL_TLSv1_2: int
# protocol options
OP_ALL: int
OP_NO_SSLv2: int
OP_NO_SSLv3: int
OP_NO_TLSv1: int
OP_NO_TLSv1_1: int
OP_NO_TLSv1_2: int
OP_NO_TLSv1_3: int
OP_CIPHER_SERVER_PREFERENCE: int
OP_SINGLE_DH_USE: int
OP_NO_TICKET: int
OP_SINGLE_ECDH_USE: int
OP_NO_COMPRESSION: int
OP_ENABLE_MIDDLEBOX_COMPAT: int
OP_NO_RENEGOTIATION: int
if sys.version_info >= (3, 11):
OP_IGNORE_UNEXPECTED_EOF: int
elif sys.version_info >= (3, 8) and sys.platform == "linux":
OP_IGNORE_UNEXPECTED_EOF: int
if sys.version_info >= (3, 12):
OP_LEGACY_SERVER_CONNECT: int
OP_ENABLE_KTLS: int
# host flags
HOSTFLAG_ALWAYS_CHECK_SUBJECT: int
HOSTFLAG_NEVER_CHECK_SUBJECT: int
HOSTFLAG_NO_WILDCARDS: int
HOSTFLAG_NO_PARTIAL_WILDCARDS: int
HOSTFLAG_MULTI_LABEL_WILDCARDS: int
HOSTFLAG_SINGLE_LABEL_SUBDOMAINS: int
if sys.version_info >= (3, 10):
# certificate file types
# Typed as Literal so the overload on Certificate.public_bytes can work properly.
ENCODING_PEM: Literal[1]
ENCODING_DER: Literal[2]
# protocol versions
PROTO_MINIMUM_SUPPORTED: int
PROTO_MAXIMUM_SUPPORTED: int
PROTO_SSLv3: int
PROTO_TLSv1: int
PROTO_TLSv1_1: int
PROTO_TLSv1_2: int
PROTO_TLSv1_3: int
# feature support
HAS_SNI: bool
HAS_TLS_UNIQUE: bool
HAS_ECDH: bool
HAS_NPN: bool
if sys.version_info >= (3, 13):
HAS_PSK: bool
HAS_ALPN: bool
HAS_SSLv2: bool
HAS_SSLv3: bool
HAS_TLSv1: bool
HAS_TLSv1_1: bool
HAS_TLSv1_2: bool
HAS_TLSv1_3: bool
# version info
OPENSSL_VERSION_NUMBER: int
OPENSSL_VERSION_INFO: tuple[int, int, int, int, int]
OPENSSL_VERSION: str
_OPENSSL_API_VERSION: tuple[int, int, int, int, int]

View File

@@ -1,37 +1,10 @@
import sys
from collections.abc import Callable
from typing import Any, Generic, TypeVar, final, overload
from typing_extensions import Self
if sys.version_info >= (3, 9):
from types import GenericAlias
from typing import Any, TypeVar, overload
from weakref import CallableProxyType as CallableProxyType, ProxyType as ProxyType, ReferenceType as ReferenceType, ref as ref
_C = TypeVar("_C", bound=Callable[..., Any])
_T = TypeVar("_T")
@final
class CallableProxyType(Generic[_C]): # "weakcallableproxy"
def __eq__(self, value: object, /) -> bool: ...
def __getattr__(self, attr: str) -> Any: ...
__call__: _C
@final
class ProxyType(Generic[_T]): # "weakproxy"
def __eq__(self, value: object, /) -> bool: ...
def __getattr__(self, attr: str) -> Any: ...
class ReferenceType(Generic[_T]):
__callback__: Callable[[Self], Any]
def __new__(cls, o: _T, callback: Callable[[Self], Any] | None = ..., /) -> Self: ...
def __init__(self, o: _T, callback: Callable[[Self], Any] | None = ..., /) -> None: ...
def __call__(self) -> _T | None: ...
def __eq__(self, value: object, /) -> bool: ...
def __hash__(self) -> int: ...
if sys.version_info >= (3, 9):
def __class_getitem__(cls, item: Any, /) -> GenericAlias: ...
ref = ReferenceType
def getweakrefcount(object: Any, /) -> int: ...
def getweakrefs(object: Any, /) -> list[Any]: ...

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,11 @@
import ssl
import sys
from _asyncio import (
_get_running_loop as _get_running_loop,
_set_running_loop as _set_running_loop,
get_event_loop as get_event_loop,
get_running_loop as get_running_loop,
)
from _typeshed import FileDescriptorLike, ReadableBuffer, StrPath, Unused, WriteableBuffer
from abc import ABCMeta, abstractmethod
from collections.abc import Callable, Sequence
@@ -632,7 +638,6 @@ class BaseDefaultEventLoopPolicy(AbstractEventLoopPolicy, metaclass=ABCMeta):
def get_event_loop_policy() -> AbstractEventLoopPolicy: ...
def set_event_loop_policy(policy: AbstractEventLoopPolicy | None) -> None: ...
def get_event_loop() -> AbstractEventLoop: ...
def set_event_loop(loop: AbstractEventLoop | None) -> None: ...
def new_event_loop() -> AbstractEventLoop: ...
@@ -646,7 +651,3 @@ if sys.version_info < (3, 14):
else:
def get_child_watcher() -> AbstractChildWatcher: ...
def set_child_watcher(watcher: AbstractChildWatcher) -> None: ...
def _set_running_loop(loop: AbstractEventLoop | None, /) -> None: ...
def _get_running_loop() -> AbstractEventLoop: ...
def get_running_loop() -> AbstractEventLoop: ...

View File

@@ -1,15 +1,10 @@
import sys
from collections.abc import Awaitable, Callable, Generator, Iterable
from _asyncio import Future as Future
from concurrent.futures._base import Future as _ConcurrentFuture
from contextvars import Context
from typing import Any, Literal, TypeVar
from typing_extensions import Self, TypeIs
from typing import Any, TypeVar
from typing_extensions import TypeIs
from .events import AbstractEventLoop
if sys.version_info >= (3, 9):
from types import GenericAlias
__all__ = ("Future", "wrap_future", "isfuture")
_T = TypeVar("_T")
@@ -18,40 +13,4 @@ _T = TypeVar("_T")
# but it leads to circular import error in pytype tool.
# That's why the import order is reversed.
def isfuture(obj: object) -> TypeIs[Future[Any]]: ...
class Future(Awaitable[_T], Iterable[_T]):
_state: str
@property
def _exception(self) -> BaseException | None: ...
_blocking: bool
@property
def _log_traceback(self) -> bool: ...
@_log_traceback.setter
def _log_traceback(self, val: Literal[False]) -> None: ...
_asyncio_future_blocking: bool # is a part of duck-typing contract for `Future`
def __init__(self, *, loop: AbstractEventLoop | None = ...) -> None: ...
def __del__(self) -> None: ...
def get_loop(self) -> AbstractEventLoop: ...
@property
def _callbacks(self) -> list[tuple[Callable[[Self], Any], Context]]: ...
def add_done_callback(self, fn: Callable[[Self], object], /, *, context: Context | None = None) -> None: ...
if sys.version_info >= (3, 9):
def cancel(self, msg: Any | None = None) -> bool: ...
else:
def cancel(self) -> bool: ...
def cancelled(self) -> bool: ...
def done(self) -> bool: ...
def result(self) -> _T: ...
def exception(self) -> BaseException | None: ...
def remove_done_callback(self, fn: Callable[[Self], object], /) -> int: ...
def set_result(self, result: _T, /) -> None: ...
def set_exception(self, exception: type | BaseException, /) -> None: ...
def __iter__(self) -> Generator[Any, None, _T]: ...
def __await__(self) -> Generator[Any, None, _T]: ...
@property
def _loop(self) -> AbstractEventLoop: ...
if sys.version_info >= (3, 9):
def __class_getitem__(cls, item: Any, /) -> GenericAlias: ...
def wrap_future(future: _ConcurrentFuture[_T] | Future[_T], *, loop: AbstractEventLoop | None = None) -> Future[_T]: ...

View File

@@ -1,16 +1,20 @@
import concurrent.futures
import sys
from _asyncio import (
Task as Task,
_enter_task as _enter_task,
_leave_task as _leave_task,
_register_task as _register_task,
_unregister_task as _unregister_task,
)
from collections.abc import Awaitable, Coroutine, Generator, Iterable, Iterator
from types import FrameType
from typing import Any, Literal, Protocol, TextIO, TypeVar, overload
from typing import Any, Literal, Protocol, TypeVar, overload
from typing_extensions import TypeAlias
from . import _CoroutineLike
from .events import AbstractEventLoop
from .futures import Future
if sys.version_info >= (3, 9):
from types import GenericAlias
if sys.version_info >= (3, 11):
from contextvars import Context
@@ -400,58 +404,6 @@ elif sys.version_info >= (3, 9):
else:
_TaskCompatibleCoro: TypeAlias = Generator[_TaskYieldType, None, _T_co] | Awaitable[_T_co]
# mypy and pyright complain that a subclass of an invariant class shouldn't be covariant.
# While this is true in general, here it's sort-of okay to have a covariant subclass,
# since the only reason why `asyncio.Future` is invariant is the `set_result()` method,
# and `asyncio.Task.set_result()` always raises.
class Task(Future[_T_co]): # type: ignore[type-var] # pyright: ignore[reportInvalidTypeArguments]
if sys.version_info >= (3, 12):
def __init__(
self,
coro: _TaskCompatibleCoro[_T_co],
*,
loop: AbstractEventLoop = ...,
name: str | None = ...,
context: Context | None = None,
eager_start: bool = False,
) -> None: ...
elif sys.version_info >= (3, 11):
def __init__(
self,
coro: _TaskCompatibleCoro[_T_co],
*,
loop: AbstractEventLoop = ...,
name: str | None = ...,
context: Context | None = None,
) -> None: ...
else:
def __init__(
self, coro: _TaskCompatibleCoro[_T_co], *, loop: AbstractEventLoop = ..., name: str | None = ...
) -> None: ...
if sys.version_info >= (3, 12):
def get_coro(self) -> _TaskCompatibleCoro[_T_co] | None: ...
else:
def get_coro(self) -> _TaskCompatibleCoro[_T_co]: ...
def get_name(self) -> str: ...
def set_name(self, value: object, /) -> None: ...
if sys.version_info >= (3, 12):
def get_context(self) -> Context: ...
def get_stack(self, *, limit: int | None = None) -> list[FrameType]: ...
def print_stack(self, *, limit: int | None = None, file: TextIO | None = None) -> None: ...
if sys.version_info >= (3, 11):
def cancelling(self) -> int: ...
def uncancel(self) -> int: ...
if sys.version_info < (3, 9):
@classmethod
def current_task(cls, loop: AbstractEventLoop | None = None) -> Task[Any] | None: ...
@classmethod
def all_tasks(cls, loop: AbstractEventLoop | None = None) -> set[Task[Any]]: ...
if sys.version_info >= (3, 9):
def __class_getitem__(cls, item: Any, /) -> GenericAlias: ...
def all_tasks(loop: AbstractEventLoop | None = None) -> set[Task[Any]]: ...
if sys.version_info >= (3, 11):
@@ -460,9 +412,10 @@ if sys.version_info >= (3, 11):
else:
def create_task(coro: _CoroutineLike[_T], *, name: str | None = None) -> Task[_T]: ...
def current_task(loop: AbstractEventLoop | None = None) -> Task[Any] | None: ...
def _enter_task(loop: AbstractEventLoop, task: Task[Any]) -> None: ...
def _leave_task(loop: AbstractEventLoop, task: Task[Any]) -> None: ...
if sys.version_info >= (3, 12):
from _asyncio import current_task as current_task
else:
def current_task(loop: AbstractEventLoop | None = None) -> Task[Any] | None: ...
if sys.version_info >= (3, 12):
_TaskT_co = TypeVar("_TaskT_co", bound=Task[Any], covariant=True)
@@ -499,6 +452,3 @@ if sys.version_info >= (3, 12):
name: str | None = None,
context: Context | None = None,
) -> Task[_T_co]: ...
def _register_task(task: Task[Any]) -> None: ...
def _unregister_task(task: Task[Any]) -> None: ...

View File

@@ -589,7 +589,10 @@ class str(Sequence[str]):
def __contains__(self, key: str, /) -> bool: ... # type: ignore[override]
def __eq__(self, value: object, /) -> bool: ...
def __ge__(self, value: str, /) -> bool: ...
def __getitem__(self, key: SupportsIndex | slice, /) -> str: ...
@overload
def __getitem__(self: LiteralString, key: SupportsIndex | slice, /) -> LiteralString: ...
@overload
def __getitem__(self, key: SupportsIndex | slice, /) -> str: ... # type: ignore[misc]
def __gt__(self, value: str, /) -> bool: ...
def __hash__(self) -> int: ...
@overload
@@ -831,7 +834,7 @@ _IntegerFormats: TypeAlias = Literal[
]
@final
class memoryview(Sequence[_I]):
class memoryview(Generic[_I]):
@property
def format(self) -> str: ...
@property
@@ -1205,7 +1208,7 @@ class frozenset(AbstractSet[_T_co]):
def __class_getitem__(cls, item: Any, /) -> GenericAlias: ...
class enumerate(Iterator[tuple[int, _T]]):
def __new__(cls, iterable: Iterable[_T], start: int = ...) -> Self: ...
def __new__(cls, iterable: Iterable[_T], start: int = 0) -> Self: ...
def __iter__(self) -> Self: ...
def __next__(self) -> tuple[int, _T]: ...
if sys.version_info >= (3, 9):

View File

@@ -131,7 +131,7 @@ class BZ2File(BaseStream, IO[bytes]):
@final
class BZ2Compressor:
def __init__(self, compresslevel: int = ...) -> None: ...
def __init__(self, compresslevel: int = 9) -> None: ...
def compress(self, data: ReadableBuffer, /) -> bytes: ...
def flush(self) -> bytes: ...

View File

@@ -12,7 +12,11 @@ class InteractiveInterpreter:
def __init__(self, locals: Mapping[str, Any] | None = None) -> None: ...
def runsource(self, source: str, filename: str = "<input>", symbol: str = "single") -> bool: ...
def runcode(self, code: CodeType) -> None: ...
def showsyntaxerror(self, filename: str | None = None) -> None: ...
if sys.version_info >= (3, 13):
def showsyntaxerror(self, filename: str | None = None, *, source: str = "") -> None: ...
else:
def showsyntaxerror(self, filename: str | None = None) -> None: ...
def showtraceback(self) -> None: ...
def write(self, data: str) -> None: ...

View File

@@ -17,7 +17,6 @@ if sys.version_info >= (3, 10):
Mapping,
MutableMapping,
MutableSequence,
Reversible,
Sequence,
ValuesView,
)
@@ -331,13 +330,13 @@ class Counter(dict[_T, int], Generic[_T]):
# The pure-Python implementations of the "views" classes
# These are exposed at runtime in `collections/__init__.py`
class _OrderedDictKeysView(KeysView[_KT_co], Reversible[_KT_co]):
class _OrderedDictKeysView(KeysView[_KT_co]):
def __reversed__(self) -> Iterator[_KT_co]: ...
class _OrderedDictItemsView(ItemsView[_KT_co, _VT_co], Reversible[tuple[_KT_co, _VT_co]]):
class _OrderedDictItemsView(ItemsView[_KT_co, _VT_co]):
def __reversed__(self) -> Iterator[tuple[_KT_co, _VT_co]]: ...
class _OrderedDictValuesView(ValuesView[_VT_co], Reversible[_VT_co]):
class _OrderedDictValuesView(ValuesView[_VT_co]):
def __reversed__(self) -> Iterator[_VT_co]: ...
# The C implementations of the "views" classes
@@ -345,18 +344,18 @@ class _OrderedDictValuesView(ValuesView[_VT_co], Reversible[_VT_co]):
# but they are not exposed anywhere)
# pyright doesn't have a specific error code for subclassing error!
@final
class _odict_keys(dict_keys[_KT_co, _VT_co], Reversible[_KT_co]): # type: ignore[misc] # pyright: ignore[reportGeneralTypeIssues]
class _odict_keys(dict_keys[_KT_co, _VT_co]): # type: ignore[misc] # pyright: ignore[reportGeneralTypeIssues]
def __reversed__(self) -> Iterator[_KT_co]: ...
@final
class _odict_items(dict_items[_KT_co, _VT_co], Reversible[tuple[_KT_co, _VT_co]]): # type: ignore[misc] # pyright: ignore[reportGeneralTypeIssues]
class _odict_items(dict_items[_KT_co, _VT_co]): # type: ignore[misc] # pyright: ignore[reportGeneralTypeIssues]
def __reversed__(self) -> Iterator[tuple[_KT_co, _VT_co]]: ...
@final
class _odict_values(dict_values[_KT_co, _VT_co], Reversible[_VT_co], Generic[_KT_co, _VT_co]): # type: ignore[misc] # pyright: ignore[reportGeneralTypeIssues]
class _odict_values(dict_values[_KT_co, _VT_co]): # type: ignore[misc] # pyright: ignore[reportGeneralTypeIssues]
def __reversed__(self) -> Iterator[_VT_co]: ...
class OrderedDict(dict[_KT, _VT], Reversible[_KT], Generic[_KT, _VT]):
class OrderedDict(dict[_KT, _VT]):
def popitem(self, last: bool = True) -> tuple[_KT, _VT]: ...
def move_to_end(self, key: _KT, last: bool = True) -> None: ...
def copy(self) -> Self: ...

View File

@@ -19,8 +19,9 @@ _global_shutdown: bool
class _ThreadWakeup:
_closed: bool
_reader: Connection
_writer: Connection
# Any: Unused send and recv methods
_reader: Connection[Any, Any]
_writer: Connection[Any, Any]
def close(self) -> None: ...
def wakeup(self) -> None: ...
def clear(self) -> None: ...

View File

@@ -143,13 +143,15 @@ class _RedirectStream(AbstractContextManager[_T_io, None]):
class redirect_stdout(_RedirectStream[_T_io]): ...
class redirect_stderr(_RedirectStream[_T_io]): ...
# In reality this is a subclass of `AbstractContextManager`;
# see #7961 for why we don't do that in the stub
class ExitStack(Generic[_ExitT_co], metaclass=abc.ABCMeta):
class _BaseExitStack(Generic[_ExitT_co]):
def enter_context(self, cm: AbstractContextManager[_T, _ExitT_co]) -> _T: ...
def push(self, exit: _CM_EF) -> _CM_EF: ...
def callback(self, callback: Callable[_P, _T], /, *args: _P.args, **kwds: _P.kwargs) -> Callable[_P, _T]: ...
def pop_all(self) -> Self: ...
# In reality this is a subclass of `AbstractContextManager`;
# see #7961 for why we don't do that in the stub
class ExitStack(_BaseExitStack[_ExitT_co], metaclass=abc.ABCMeta):
def close(self) -> None: ...
def __enter__(self) -> Self: ...
def __exit__(
@@ -163,16 +165,12 @@ _ACM_EF = TypeVar("_ACM_EF", bound=AbstractAsyncContextManager[Any, Any] | _Exit
# In reality this is a subclass of `AbstractAsyncContextManager`;
# see #7961 for why we don't do that in the stub
class AsyncExitStack(Generic[_ExitT_co], metaclass=abc.ABCMeta):
def enter_context(self, cm: AbstractContextManager[_T, _ExitT_co]) -> _T: ...
class AsyncExitStack(_BaseExitStack[_ExitT_co], metaclass=abc.ABCMeta):
async def enter_async_context(self, cm: AbstractAsyncContextManager[_T, _ExitT_co]) -> _T: ...
def push(self, exit: _CM_EF) -> _CM_EF: ...
def push_async_exit(self, exit: _ACM_EF) -> _ACM_EF: ...
def callback(self, callback: Callable[_P, _T], /, *args: _P.args, **kwds: _P.kwargs) -> Callable[_P, _T]: ...
def push_async_callback(
self, callback: Callable[_P, Awaitable[_T]], /, *args: _P.args, **kwds: _P.kwargs
) -> Callable[_P, Awaitable[_T]]: ...
def pop_all(self) -> Self: ...
async def aclose(self) -> None: ...
async def __aenter__(self) -> Self: ...
async def __aexit__(

View File

@@ -1,12 +1,10 @@
import sys
# actually csv.Dialect is a different class to _csv.Dialect at runtime, but for typing purposes, they're identical
from _csv import (
QUOTE_ALL as QUOTE_ALL,
QUOTE_MINIMAL as QUOTE_MINIMAL,
QUOTE_NONE as QUOTE_NONE,
QUOTE_NONNUMERIC as QUOTE_NONNUMERIC,
Dialect as Dialect,
Dialect as _Dialect,
Error as Error,
__version__ as __version__,
_DialectLike,
@@ -61,6 +59,9 @@ if sys.version_info < (3, 13):
_T = TypeVar("_T")
class Dialect(_Dialect):
def __init__(self) -> None: ...
class excel(Dialect): ...
class excel_tab(excel): ...
class unix_dialect(Dialect): ...

Some files were not shown because too many files have changed in this diff Show More