Skip to content

Commit c20819a

Browse files
committed
Added support for PEP 675 (arbitrary literal strings)
1 parent 1dcb640 commit c20819a

File tree

6 files changed

+53
-1
lines changed

6 files changed

+53
-1
lines changed

README.md

+2
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,9 @@ Pyright supports [configuration files](/docs/configuration.md) that provide gran
2929
* [PEP 647](https://www.python.org/dev/peps/pep-0647/) user-defined type guards
3030
* [PEP 655](https://www.python.org/dev/peps/pep-0655/) required typed dictionary items
3131
* [PEP 673](https://www.python.org/dev/peps/pep-0673/) Self type
32+
* [PEP 675](https://www.python.org/dev/peps/pep-0675/) arbitrary literal strings
3233
* [PEP 677](https://www.python.org/dev/peps/pep-0677/) callable type syntax
34+
* [PEP 681](https://www.python.org/dev/peps/pep-0681/) dataclass transform
3335
* Type inference for function return values, instance variables, class variables, and globals
3436
* Type guards that understand conditional code flow constructs like if/else statements
3537

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

+1
Original file line numberDiff line numberDiff line change
@@ -3842,6 +3842,7 @@ export class Binder extends ParseTreeWalker {
38423842
['Self', true],
38433843
['NoReturn', true],
38443844
['Never', true],
3845+
['LiteralString', true],
38453846
]);
38463847

38473848
const assignedName = assignedNameNode.value;

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

+11
Original file line numberDiff line numberDiff line change
@@ -13610,6 +13610,7 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions
1361013610
['Self', { alias: '', module: 'builtins' }],
1361113611
['NoReturn', { alias: '', module: 'builtins' }],
1361213612
['Never', { alias: '', module: 'builtins' }],
13613+
['LiteralString', { alias: '', module: 'builtins' }],
1361313614
]);
1361413615

1361513616
const aliasMapEntry = specialTypes.get(assignedName);
@@ -16956,6 +16957,10 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions
1695616957
case 'Self': {
1695716958
return createSelfType(classType, errorNode, typeArgs);
1695816959
}
16960+
16961+
case 'LiteralString': {
16962+
return createSpecialType(classType, typeArgs, 0);
16963+
}
1695916964
}
1696016965
}
1696116966

@@ -20750,6 +20755,12 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions
2075020755
}
2075120756
}
2075220757

20758+
if (ClassType.isBuiltIn(destType, 'LiteralString') && ClassType.isBuiltIn(concreteSrcType, 'str')) {
20759+
if (concreteSrcType.literalValue !== undefined) {
20760+
return true;
20761+
}
20762+
}
20763+
2075320764
if (
2075420765
!canAssignClass(
2075520766
ClassType.cloneAsInstantiable(destType),
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# This sample tests the evaluation of LiteralString as described
2+
# in PEP 675.
3+
4+
from typing_extensions import LiteralString
5+
6+
7+
def func1(a: str, b: bytes):
8+
# This should generate an error.
9+
v1: LiteralString = a
10+
11+
# This should generate an error.
12+
v2: LiteralString = b
13+
14+
# This should generate an error.
15+
v3: LiteralString = b""
16+
17+
v4: LiteralString = "Hello!"
18+
19+
v5: LiteralString = "Hello " + "Bob"
20+
21+
# This should generate an error.
22+
v6: LiteralString = f"{a}"
23+
24+
# This should generate an error.
25+
v7: LiteralString[int]

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

+6
Original file line numberDiff line numberDiff line change
@@ -1246,3 +1246,9 @@ test('PseudoGeneric1', () => {
12461246

12471247
TestUtils.validateResults(analysisResults, 0);
12481248
});
1249+
1250+
test('LiteralString1', () => {
1251+
const analysisResults = TestUtils.typeAnalyzeSampleFiles(['literalString1.py']);
1252+
1253+
TestUtils.validateResults(analysisResults, 5);
1254+
});

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

+8-1
Original file line numberDiff line numberDiff line change
@@ -145,9 +145,12 @@ else:
145145
def assert_never(__arg: NoReturn) -> NoReturn: ...
146146

147147
# Experimental (hopefully these will be in 3.11)
148+
149+
# PEP 655
148150
Required: _SpecialForm
149151
NotRequired: _SpecialForm
150152

153+
# PEP 681
151154
def dataclass_transform(
152155
*,
153156
eq_default: bool = ...,
@@ -156,7 +159,7 @@ def dataclass_transform(
156159
field_descriptors: tuple[type[Any] | Callable[..., Any], ...] = ...,
157160
) -> Callable[[_T], _T]: ...
158161

159-
# Experimental types, not yet implemented in typing_extensions library.
162+
# Types not yet implemented in typing_extensions library
160163

161164
# PEP 646
162165
Unpack: _SpecialForm = ...
@@ -165,4 +168,8 @@ class TypeVarTuple:
165168
__name__: str
166169
def __init__(self, name: str) -> None: ...
167170

171+
# PEP 675
172+
LiteralString: _SpecialForm = ...
173+
174+
# Proposed extension to PEP 647
168175
StrictTypeGuard: _SpecialForm = ...

0 commit comments

Comments
 (0)