Skip to content

Commit abaa715

Browse files
committed
Merge branch 'main' of https://github.com/microsoft/pyright into perf/benchmark-suite
2 parents a7fde2c + d8dd0a2 commit abaa715

12 files changed

Lines changed: 2687 additions & 1666 deletions

File tree

package-lock.json

Lines changed: 1800 additions & 1259 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/pyright-internal/package-lock.json

Lines changed: 594 additions & 146 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/pyright-internal/src/analyzer/sentinel.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -78,10 +78,7 @@ export function createSentinelType(
7878

7979
let instanceType = ClassType.cloneAsInstance(classType);
8080

81-
// Is TypeForm supported?
82-
if (fileInfo.diagnosticRuleSet.enableExperimentalFeatures) {
83-
instanceType = TypeBase.cloneWithTypeForm(instanceType, instanceType);
84-
}
81+
instanceType = TypeBase.cloneWithTypeForm(instanceType, instanceType);
8582

8683
return instanceType;
8784
}

packages/pyright-internal/src/analyzer/typeEvaluator.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10591,11 +10591,13 @@ export function createTypeEvaluator(
1059110591
return { returnType: createNewType(errorNode, argList) };
1059210592
}
1059310593

10594-
// Handle the Sentinel call specially.
10595-
if (className === 'Sentinel') {
10596-
if (AnalyzerNodeInfo.getFileInfo(errorNode).diagnosticRuleSet.enableExperimentalFeatures) {
10597-
return { returnType: createSentinelType(evaluatorInterface, errorNode, argList) };
10598-
}
10594+
// Handle sentinel calls specially.
10595+
if (
10596+
expandedCallType.shared.fullName === 'builtins.sentinel' ||
10597+
expandedCallType.shared.fullName === 'typing_extensions.sentinel' ||
10598+
expandedCallType.shared.fullName === 'typing_extensions.Sentinel'
10599+
) {
10600+
return { returnType: createSentinelType(evaluatorInterface, errorNode, argList) };
1059910601
}
1060010602

1060110603
if (ClassType.isSpecialFormClass(expandedCallType)) {

packages/pyright-internal/src/common/pythonVersion.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,5 +215,6 @@ export const pythonVersion3_11 = PythonVersion.create(3, 11);
215215
export const pythonVersion3_12 = PythonVersion.create(3, 12);
216216
export const pythonVersion3_13 = PythonVersion.create(3, 13);
217217
export const pythonVersion3_14 = PythonVersion.create(3, 14);
218+
export const pythonVersion3_15 = PythonVersion.create(3, 15);
218219

219220
export const latestStablePythonVersion = pythonVersion3_14;

packages/pyright-internal/src/tests/samples/sentinel1.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# This sample tests the handling of Sentinel as described in PEP 661.
22

33
from typing import Literal, TypeAlias
4-
from typing_extensions import Sentinel, TypeForm # pyright: ignore[reportMissingModuleSource]
4+
from typing_extensions import Sentinel, TypeForm, sentinel # pyright: ignore[reportMissingModuleSource]
55

66
# This should generate an error because the names don't match.
77
BAD_NAME1 = Sentinel("OTHER")
@@ -15,15 +15,23 @@
1515
# This should generate an error because the arg type is wrong.
1616
BAD_CALL3 = Sentinel(1)
1717

18+
# This should generate an error because the arg count is wrong.
19+
BAD_CALL4 = sentinel()
20+
21+
# This should generate an error because the arg type is wrong.
22+
BAD_CALL5 = sentinel(1)
1823

1924
MISSING = Sentinel("MISSING")
25+
NOT_GIVEN = sentinel("NOT_GIVEN")
2026

2127
type TA1 = int | MISSING
2228

2329
TA2: TypeAlias = int | MISSING
2430

2531
TA3 = int | MISSING
2632

33+
TA4: TypeAlias = int | NOT_GIVEN
34+
2735
# This should generate an error because Literal isn't appropriate here.
2836
x: Literal[MISSING]
2937

@@ -57,3 +65,10 @@ def func3(x: Literal[0, 3, "hi"] | MISSING) -> None:
5765

5866
t1 = type(MISSING)
5967
reveal_type(t1, expected_text="type[MISSING]")
68+
69+
70+
def func4(value: str | NOT_GIVEN) -> None:
71+
if value is NOT_GIVEN:
72+
reveal_type(value, expected_text="NOT_GIVEN")
73+
else:
74+
reveal_type(value, expected_text="str")
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# This sample tests the handling of the sentinel builtin added in Python 3.15.
2+
3+
from typing import Literal, TypeAlias
4+
5+
# This should generate an error because the names don't match.
6+
BAD_NAME1 = sentinel("OTHER")
7+
8+
# This should generate an error because the arg count is wrong.
9+
BAD_CALL1 = sentinel()
10+
11+
# This should generate an error because the arg count is wrong.
12+
BAD_CALL2 = sentinel("BAD_CALL2", 1)
13+
14+
# This should generate an error because the arg type is wrong.
15+
BAD_CALL3 = sentinel(1)
16+
17+
18+
MISSING = sentinel("MISSING")
19+
20+
type TA1 = int | MISSING
21+
22+
TA2: TypeAlias = int | MISSING
23+
24+
# This should generate an error because Literal isn't appropriate here.
25+
x: Literal[MISSING]
26+
27+
28+
def func1(value: int | MISSING) -> None:
29+
if value is MISSING:
30+
reveal_type(value, expected_text="MISSING")
31+
else:
32+
reveal_type(value, expected_text="int")

packages/pyright-internal/src/tests/typeEvaluator2.test.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
*/
1010

1111
import { ConfigOptions } from '../common/configOptions';
12-
import { pythonVersion3_10, pythonVersion3_13, pythonVersion3_9 } from '../common/pythonVersion';
12+
import { pythonVersion3_10, pythonVersion3_13, pythonVersion3_15, pythonVersion3_9 } from '../common/pythonVersion';
1313
import { Uri } from '../common/uri/uri';
1414
import * as TestUtils from './testUtils';
1515

@@ -995,9 +995,13 @@ test('SolverUnknown1', () => {
995995
});
996996

997997
test('Sentinel1', () => {
998-
const configOptions = new ConfigOptions(Uri.empty());
998+
const analysisResults = TestUtils.typeAnalyzeSampleFiles(['sentinel1.py']);
999+
TestUtils.validateResults(analysisResults, 7);
1000+
});
9991001

1000-
configOptions.diagnosticRuleSet.enableExperimentalFeatures = true;
1001-
const analysisResults = TestUtils.typeAnalyzeSampleFiles(['sentinel1.py'], configOptions);
1002+
test('Sentinel2', () => {
1003+
const configOptions = new ConfigOptions(Uri.empty());
1004+
configOptions.defaultPythonVersion = pythonVersion3_15;
1005+
const analysisResults = TestUtils.typeAnalyzeSampleFiles(['sentinel2.py'], configOptions);
10021006
TestUtils.validateResults(analysisResults, 5);
10031007
});

packages/pyright-internal/typeshed-fallback/stdlib/builtins.pyi

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1556,6 +1556,15 @@ def iter(object: Callable[[], _T | None], sentinel: None, /) -> Iterator[_T]: ..
15561556
@overload
15571557
def iter(object: Callable[[], _T], sentinel: object, /) -> Iterator[_T]: ...
15581558

1559+
if sys.version_info >= (3, 15):
1560+
@final
1561+
class sentinel:
1562+
__name__: str
1563+
__module__: str
1564+
def __init__(self, name: str, /) -> None: ...
1565+
def __or__(self, other: Any) -> types.UnionType: ...
1566+
def __ror__(self, other: Any) -> types.UnionType: ...
1567+
15591568
if sys.version_info >= (3, 10):
15601569
_ClassInfo: TypeAlias = type | types.UnionType | tuple[_ClassInfo, ...]
15611570
else:

packages/pyright-internal/typeshed-fallback/stdlib/typing_extensions.pyi

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@ __all__ = [
141141
"override",
142142
"Protocol",
143143
"Sentinel",
144+
"sentinel",
144145
"reveal_type",
145146
"runtime",
146147
"runtime_checkable",
@@ -700,8 +701,23 @@ else:
700701
def type_repr(value: object) -> str: ...
701702

702703
# PEP 661
704+
@final
705+
class sentinel:
706+
__name__: str
707+
__module__: str
708+
def __init__(self, name: str, /) -> None: ...
709+
if sys.version_info >= (3, 14):
710+
def __or__(self, other: Any) -> UnionType: ... # other can be any type form legal for unions
711+
def __ror__(self, other: Any) -> UnionType: ... # other can be any type form legal for unions
712+
elif sys.version_info >= (3, 10):
713+
def __or__(self, other: Any) -> _SpecialForm: ... # other can be any type form legal for unions
714+
def __ror__(self, other: Any) -> _SpecialForm: ... # other can be any type form legal for unions
715+
716+
@final
703717
class Sentinel:
704-
def __init__(self, name: str, repr: str | None = None) -> None: ...
718+
__name__: str
719+
__module__: str
720+
def __init__(self, name: str, /) -> None: ...
705721
if sys.version_info >= (3, 14):
706722
def __or__(self, other: Any) -> UnionType: ... # other can be any type form legal for unions
707723
def __ror__(self, other: Any) -> UnionType: ... # other can be any type form legal for unions

0 commit comments

Comments
 (0)