chore(vipeye-internal): 修剪 samples 残留与孤儿测试辅助
Validation / Typecheck (push) Has been cancelled
Validation / Style (push) Has been cancelled
Validation / Test macos-latest (push) Has been cancelled
Validation / Test ubuntu-latest (push) Has been cancelled
Validation / Test windows-latest (push) Has been cancelled
Validation / Build (push) Has been cancelled
Validation / Required (push) Has been cancelled
Validation / Typecheck (push) Has been cancelled
Validation / Style (push) Has been cancelled
Validation / Test macos-latest (push) Has been cancelled
Validation / Test ubuntu-latest (push) Has been cancelled
Validation / Test windows-latest (push) Has been cancelled
Validation / Build (push) Has been cancelled
Validation / Required (push) Has been cancelled
- samples 根目录 1277 个散落 .py/.pyi 夹具删除,仅保留被现存用例引用的 15 个 (badToken1/test_file1/lines1/parser1-2/suiteExpectedColon1-3/maxParseDepth1-2/ parserRecovery1-3/fstring6/finallyExit1)+ 2 个 viper_*.vp;子目录夹具不动 - 删除已无引用的 harness/fourslash/runner.ts(fourslash 夹具与 testState.test 已删) - 保留 tests/lsp/languageServerTestUtils.ts:仍被 typeServer.virtualFileRedirect 引用 验证: 全量串行 53 套件通过、1 跳过,732 用例全绿
This commit is contained in:
1 parent
04d5a32502
commit
c9acd4ecb8
1269 files changed
-61780
No files matched your search
@@ -1,93 +0,0 @@
|
||||
/*
|
||||
* runner.ts
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
* Licensed under the MIT license.
|
||||
*
|
||||
* Provide APIs to run fourslash tests from provided fourslash markup contents
|
||||
*/
|
||||
|
||||
import * as ts from 'typescript';
|
||||
|
||||
import { combinePaths } from '../../../common/pathUtils';
|
||||
import * as host from '../testHost';
|
||||
import { parseTestData } from './fourSlashParser';
|
||||
import { FourSlashData } from './fourSlashTypes';
|
||||
import { TestState, TestStateOptions } from './testState';
|
||||
import { Consts } from './testState.Consts';
|
||||
|
||||
export type TestStateFactory = (basePath: string, testData: FourSlashData, options?: TestStateOptions) => TestState;
|
||||
|
||||
/**
|
||||
* run given fourslash test file
|
||||
*
|
||||
* @param basePath this is used as a base path of the virtual file system the test will run upon
|
||||
* @param fileName this is the file path where fourslash test file will be read from
|
||||
*/
|
||||
export function runFourSlashTest(
|
||||
basePath: string,
|
||||
fileName: string,
|
||||
cb?: jest.DoneCallback,
|
||||
stateOptions?: TestStateOptions,
|
||||
testStateFactory?: TestStateFactory
|
||||
) {
|
||||
const content = host.HOST.readFile(fileName)!;
|
||||
runFourSlashTestContent(basePath, fileName, content, cb, stateOptions, testStateFactory);
|
||||
}
|
||||
|
||||
/**
|
||||
* run given fourslash markup content
|
||||
*
|
||||
* @param basePath this is used as a base path of the virtual file system the test will run upon
|
||||
* @param fileName this will be used as a filename of the given `content` in the virtual file system
|
||||
* if fourslash markup `content` doesn't have explicit `@filename` option
|
||||
* @param content this is fourslash markup string
|
||||
*/
|
||||
export function runFourSlashTestContent(
|
||||
basePath: string,
|
||||
fileName: string,
|
||||
content: string,
|
||||
cb?: jest.DoneCallback,
|
||||
stateOptions?: TestStateOptions,
|
||||
testStateFactory?: TestStateFactory
|
||||
) {
|
||||
// give file paths an absolute path for the virtual file system
|
||||
const absoluteBasePath = combinePaths('/', basePath);
|
||||
const absoluteFileName = combinePaths('/', fileName);
|
||||
|
||||
// parse out the files and their metadata
|
||||
const testData = parseTestData(absoluteBasePath, content, absoluteFileName);
|
||||
const state =
|
||||
testStateFactory !== undefined
|
||||
? testStateFactory(absoluteBasePath, testData, stateOptions)
|
||||
: new TestState(absoluteBasePath, testData, stateOptions);
|
||||
const output = ts.transpileModule(content, {
|
||||
reportDiagnostics: true,
|
||||
compilerOptions: { target: ts.ScriptTarget.ES2019 },
|
||||
});
|
||||
if (output.diagnostics!.length > 0) {
|
||||
throw new Error(`Syntax error in ${absoluteBasePath}: ${output.diagnostics![0].messageText}`);
|
||||
}
|
||||
|
||||
runCode(output.outputText, state, cb);
|
||||
}
|
||||
|
||||
async function runCode(code: string, state: TestState, cb?: jest.DoneCallback) {
|
||||
// Compile and execute the test
|
||||
try {
|
||||
const wrappedCode = `(async function(helper, Consts) {
|
||||
${code}
|
||||
})`;
|
||||
const f = eval(wrappedCode); // CodeQL [SM01632] test code that doesn't need to be secure.
|
||||
await f(state, Consts);
|
||||
markDone();
|
||||
} catch (ex) {
|
||||
markDone(ex);
|
||||
}
|
||||
|
||||
function markDone(...args: any[]) {
|
||||
if (cb) {
|
||||
cb(...args);
|
||||
}
|
||||
state.dispose();
|
||||
}
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
# This sample tests the type analyzer's ability to flag attempts
|
||||
# to instantiate abstract base classes.
|
||||
|
||||
from abc import ABC, abstractmethod
|
||||
|
||||
|
||||
class AbstractClassA(ABC):
|
||||
@abstractmethod
|
||||
def foo1(self):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def foo2(self):
|
||||
pass
|
||||
|
||||
def foo3(self):
|
||||
return 3
|
||||
|
||||
@classmethod
|
||||
def foo4(cls):
|
||||
# This should not generate an error even though
|
||||
# it would appear to be attempting to instantiate
|
||||
# an abstract class. That's because we need to
|
||||
# assume that the caller is making this call on
|
||||
# a non-abstract subclass.
|
||||
return cls()
|
||||
|
||||
|
||||
v1 = [subclass() for subclass in AbstractClassA.__subclasses__()]
|
||||
reveal_type(v1, expected_text="list[AbstractClassA]")
|
||||
|
||||
|
||||
# This should generate an error because AbstractFoo
|
||||
# is an abstract class.
|
||||
a = AbstractClassA()
|
||||
|
||||
|
||||
class AbstractClassB(AbstractClassA):
|
||||
def foo1(self):
|
||||
pass
|
||||
|
||||
|
||||
# This should generate an error because AbstractBar1
|
||||
# is an abstract class.
|
||||
b = AbstractClassB()
|
||||
|
||||
|
||||
class AbstractClassC(AbstractClassB):
|
||||
def foo2(self):
|
||||
pass
|
||||
|
||||
|
||||
# This should not generate an error because AbstractBar2
|
||||
# overrides all of the abstract methods it inherits.
|
||||
c = AbstractClassC()
|
||||
@@ -1,75 +0,0 @@
|
||||
# This sample tests the detection of static or class method invocations
|
||||
# where the method is marked abstract.
|
||||
|
||||
from abc import ABC, abstractmethod
|
||||
|
||||
|
||||
class A(ABC):
|
||||
@staticmethod
|
||||
@abstractmethod
|
||||
def method1() -> None: ...
|
||||
|
||||
@staticmethod
|
||||
@abstractmethod
|
||||
def method2() -> None:
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
@abstractmethod
|
||||
def method3(cls) -> None:
|
||||
raise NotImplementedError
|
||||
|
||||
@classmethod
|
||||
@abstractmethod
|
||||
def method4(cls) -> None:
|
||||
pass
|
||||
|
||||
|
||||
# This should generate an error.
|
||||
A.method1()
|
||||
|
||||
A.method2()
|
||||
|
||||
# This should generate an error.
|
||||
A.method3()
|
||||
|
||||
A.method4()
|
||||
|
||||
|
||||
class B(A):
|
||||
@staticmethod
|
||||
def method1() -> None:
|
||||
# This should generate an error.
|
||||
return super(B).method1()
|
||||
|
||||
@staticmethod
|
||||
def method2() -> None:
|
||||
return super(B).method2()
|
||||
|
||||
@classmethod
|
||||
def method3(cls) -> None:
|
||||
# This should generate an error.
|
||||
return super().method3()
|
||||
|
||||
@classmethod
|
||||
def method4(cls) -> None:
|
||||
return super().method4()
|
||||
|
||||
|
||||
B.method1()
|
||||
B.method2()
|
||||
|
||||
|
||||
def func1(a: type[A]):
|
||||
a.method1()
|
||||
a.method3()
|
||||
|
||||
|
||||
class C(A): ...
|
||||
|
||||
|
||||
# This should generate an error.
|
||||
C.method1()
|
||||
|
||||
# This should generate an error.
|
||||
C.method3()
|
||||
@@ -1,25 +0,0 @@
|
||||
# This sample tests the handling of a class that is created from a subclass
|
||||
# of ABCMeta.
|
||||
|
||||
from abc import ABCMeta, abstractmethod
|
||||
from typing import final
|
||||
|
||||
|
||||
class CustomMeta(ABCMeta):
|
||||
pass
|
||||
|
||||
|
||||
class A(metaclass=CustomMeta):
|
||||
@abstractmethod
|
||||
def abstract(self):
|
||||
pass
|
||||
|
||||
|
||||
@final
|
||||
# This should generate an error.
|
||||
class B(A):
|
||||
pass
|
||||
|
||||
|
||||
# This should generate an error.
|
||||
B()
|
||||
@@ -1,30 +0,0 @@
|
||||
# This sample tests the cases where a mixin class
|
||||
# overrides an abstract method, making it no longer abstract.
|
||||
|
||||
import abc
|
||||
|
||||
|
||||
class InterfaceA(abc.ABC):
|
||||
@abc.abstractmethod
|
||||
def a(self) -> None:
|
||||
print("InterfaceA.a")
|
||||
|
||||
|
||||
class MixinA(InterfaceA):
|
||||
def a(self) -> None:
|
||||
print("MixinA.a")
|
||||
|
||||
|
||||
class InterfaceAB(InterfaceA):
|
||||
@abc.abstractmethod
|
||||
def b(self) -> None:
|
||||
print("InterfaceAB.b")
|
||||
|
||||
|
||||
class ClassAB(InterfaceAB, MixinA):
|
||||
def b(self) -> None:
|
||||
print("ClassAB.b")
|
||||
|
||||
|
||||
ab = ClassAB()
|
||||
ab.a()
|
||||
@@ -1,30 +0,0 @@
|
||||
# This sample tests the checks for abstract method
|
||||
# overrides. They depend on the order of the subclasses.
|
||||
|
||||
import abc
|
||||
|
||||
|
||||
class MixinA(abc.ABC):
|
||||
pass
|
||||
|
||||
|
||||
class MixinB(abc.ABC):
|
||||
def get_model(self):
|
||||
print("MixinB.get_model")
|
||||
|
||||
|
||||
class MixinC(abc.ABC):
|
||||
@abc.abstractmethod
|
||||
def get_model(self):
|
||||
pass
|
||||
|
||||
def use_model(self):
|
||||
print("MixinC.get_model")
|
||||
|
||||
|
||||
class Trainer_1a(MixinA, MixinB, MixinC):
|
||||
pass
|
||||
|
||||
|
||||
# This should not generate an error
|
||||
trainer = Trainer_1a()
|
||||
@@ -1,30 +0,0 @@
|
||||
# This sample tests the checks for abstract method
|
||||
# overrides. They depend on the order of the subclasses.
|
||||
|
||||
import abc
|
||||
|
||||
|
||||
class MixinA(abc.ABC):
|
||||
pass
|
||||
|
||||
|
||||
class MixinB(abc.ABC):
|
||||
def get_model(self):
|
||||
print("MixinB.get_model")
|
||||
|
||||
|
||||
class MixinC(abc.ABC):
|
||||
@abc.abstractmethod
|
||||
def get_model(self):
|
||||
pass
|
||||
|
||||
def use_model(self):
|
||||
print("MixinC.get_model")
|
||||
|
||||
|
||||
class Trainer_1b(MixinA, MixinC, MixinB):
|
||||
pass
|
||||
|
||||
|
||||
# This should generate an error
|
||||
trainer = Trainer_1b()
|
||||
@@ -1,54 +0,0 @@
|
||||
# This sample tests the type checker's reporting of abstract
|
||||
# overload mismatches.
|
||||
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import Union, overload
|
||||
|
||||
|
||||
class ClassA(ABC):
|
||||
@overload
|
||||
def func1(self, a: int) -> int:
|
||||
pass
|
||||
|
||||
@overload
|
||||
@abstractmethod
|
||||
# This should generate an error because this overload is
|
||||
# missing an abstractmethod overload.
|
||||
def func1(self, a: float) -> float:
|
||||
pass
|
||||
|
||||
@overload
|
||||
def func1(self, a: str) -> str: ...
|
||||
|
||||
def func1(self, a: Union[int, float, str]) -> Union[int, float, str]:
|
||||
raise NotImplementedError()
|
||||
|
||||
@overload
|
||||
def func2(self, a: str) -> str: ...
|
||||
|
||||
@overload
|
||||
@abstractmethod
|
||||
def func2(self, a: int) -> int:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def func2(self, a: Union[int, str]) -> Union[int, str]:
|
||||
raise NotImplementedError()
|
||||
|
||||
@overload
|
||||
def func3(self, a: str) -> str: # viper: ignore[reportNoOverloadImplementation]
|
||||
...
|
||||
|
||||
@overload
|
||||
@abstractmethod
|
||||
# This should generate an error because the abstract status is inconsistent.
|
||||
def func3(self, a: int) -> int: ...
|
||||
|
||||
@overload
|
||||
@abstractmethod
|
||||
def func4(self, a: str) -> str: # viper: ignore[reportNoOverloadImplementation]
|
||||
...
|
||||
|
||||
@overload
|
||||
# This should generate an error because the abstract status is inconsistent.
|
||||
def func4(self, a: int) -> int: ...
|
||||
@@ -1,37 +0,0 @@
|
||||
# This sample validates that a variable that is annotated as
|
||||
# Type[X] where X refers to an abstract base class does not
|
||||
# emit an error when the variable is instantiated.
|
||||
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import Type, TypeVar
|
||||
|
||||
|
||||
class Base(ABC):
|
||||
@abstractmethod
|
||||
def method1(self, x: int) -> int:
|
||||
pass
|
||||
|
||||
|
||||
def func1(base_cls: Type[Base]):
|
||||
base_cls()
|
||||
|
||||
|
||||
def func2():
|
||||
# This should generate an error.
|
||||
Base()
|
||||
|
||||
|
||||
def func3(base_cls: type[Base]):
|
||||
base_cls()
|
||||
|
||||
|
||||
T = TypeVar("T")
|
||||
|
||||
|
||||
def create_instance(cls: Type[T]) -> T:
|
||||
return cls()
|
||||
|
||||
|
||||
def func4():
|
||||
base = create_instance(Base)
|
||||
base.method1(1)
|
||||
@@ -1,22 +0,0 @@
|
||||
# This sample verifies that Protocol classes are treated as
|
||||
# abstract even though they don't derive from ABCMeta.
|
||||
|
||||
from typing import Protocol, Tuple
|
||||
from abc import abstractmethod
|
||||
|
||||
|
||||
class RGB(Protocol):
|
||||
rgb: Tuple[int, int, int]
|
||||
|
||||
@abstractmethod
|
||||
def intensity(self) -> int:
|
||||
return 0
|
||||
|
||||
|
||||
class Point(RGB):
|
||||
def __init__(self, red: int, green: int, blue: int) -> None:
|
||||
self.rgb = red, green, blue
|
||||
|
||||
|
||||
# This should generate an error because "intensity" is not implemented.
|
||||
p = Point(1, 2, 3)
|
||||
@@ -1,26 +0,0 @@
|
||||
# This sample tests the check for abstract methods on a final class.
|
||||
|
||||
from typing import final
|
||||
from abc import ABC, abstractmethod
|
||||
|
||||
|
||||
class Foo(ABC):
|
||||
@abstractmethod
|
||||
def foo(self):
|
||||
pass
|
||||
|
||||
|
||||
class Bar(Foo):
|
||||
@abstractmethod
|
||||
def bar(self):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def bar2(self):
|
||||
pass
|
||||
|
||||
|
||||
@final
|
||||
# This should generate an error because Foo.foo, Bar.bar, and Bar.bar1
|
||||
# are abstract.
|
||||
class Baz(Bar): ...
|
||||
@@ -1,22 +0,0 @@
|
||||
# This sample tests that named tuple fields override abstract methods.
|
||||
|
||||
# viper: reportIncompatibleVariableOverride=false
|
||||
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import NamedTuple
|
||||
|
||||
|
||||
class ClassA(ABC):
|
||||
@property
|
||||
@abstractmethod
|
||||
def myproperty(self) -> str: ...
|
||||
|
||||
|
||||
MixinB = NamedTuple("MixinB", [("myproperty", str)])
|
||||
|
||||
|
||||
class ClassB(MixinB, ClassA):
|
||||
pass
|
||||
|
||||
|
||||
ClassB(myproperty="myproperty")
|
||||
@@ -1,102 +0,0 @@
|
||||
# This sample tests handling of the Python 3.9 "Annotated" feature
|
||||
# described in PEP 593.
|
||||
|
||||
from dataclasses import InitVar, dataclass
|
||||
from typing import Annotated, ClassVar, Final, TypeVar
|
||||
|
||||
|
||||
class struct2:
|
||||
@staticmethod
|
||||
def ctype(a: str):
|
||||
pass
|
||||
|
||||
class Packed:
|
||||
pass
|
||||
|
||||
|
||||
UnsignedShort = Annotated[int, struct2.ctype("H")]
|
||||
SignedChar = Annotated[int, struct2.ctype("b")]
|
||||
|
||||
|
||||
class Student(struct2.Packed):
|
||||
name: Annotated[str, struct2.ctype("<10s")]
|
||||
serial_num: UnsignedShort
|
||||
school: SignedChar
|
||||
|
||||
|
||||
def ValueRange(a: int, b: int):
|
||||
pass
|
||||
|
||||
|
||||
T1 = Annotated[int, ValueRange(-10, 5)]
|
||||
T2 = Annotated[T1, ValueRange(-20, 3)]
|
||||
|
||||
a: Annotated[Annotated[int, "hi"], "hi"] = 3
|
||||
b: T2 = 5
|
||||
|
||||
TypeWithStringArg = Annotated["int", "this string should not be parsed"]
|
||||
|
||||
|
||||
def func2(a: TypeWithStringArg):
|
||||
return 3
|
||||
|
||||
|
||||
# This should generate an error because the first type argument
|
||||
# is not a valid type.
|
||||
c: Annotated["this", "should generate an error"]
|
||||
|
||||
# This should generate an error because all Annotated types should
|
||||
# include at least two type arguments.
|
||||
d: Annotated[int]
|
||||
|
||||
# Verify that generic type aliases can be defined using Annotated.
|
||||
_T = TypeVar("_T")
|
||||
Param = Annotated[_T, "x"]
|
||||
|
||||
x1: Param[int] = 3
|
||||
print(Param[int])
|
||||
|
||||
|
||||
class A:
|
||||
classvar: Annotated[ClassVar[int], (2, 5)] = 4
|
||||
const: Annotated[Final[int], "metadata"] = 4
|
||||
|
||||
|
||||
@dataclass
|
||||
class B:
|
||||
x: Annotated[InitVar[int], "metadata"]
|
||||
|
||||
|
||||
d1 = B(x=4)
|
||||
|
||||
# This should generate an error because x is not an actual member.
|
||||
d1.x
|
||||
|
||||
Alias1 = Annotated[_T, ""]
|
||||
Alias2 = str
|
||||
Alias3 = Alias1[Alias2]
|
||||
|
||||
reveal_type(Alias3, expected_text="type[str]")
|
||||
|
||||
x2: Annotated[str, [*(1, 2)]]
|
||||
x3: Annotated[str, (temp := 1)]
|
||||
|
||||
|
||||
async def func3():
|
||||
x4: Annotated[str, await func3()]
|
||||
|
||||
|
||||
x5: Annotated[str, f""]
|
||||
x6: Annotated[str, "abc"]
|
||||
x7: Annotated[str, "a\nb"]
|
||||
x8: Annotated[str, *(1, 2, 3)]
|
||||
|
||||
|
||||
def func4():
|
||||
return Annotated[int, 2 + 2]
|
||||
|
||||
|
||||
reveal_type(func4(), expected_text="Annotated")
|
||||
|
||||
x9 = list[Annotated[int, ""]]()
|
||||
reveal_type(x9, expected_text="list[int]")
|
||||
@@ -1,16 +0,0 @@
|
||||
# This sample tests the case where Annotated is used with deferred
|
||||
# annotation evaluation.
|
||||
|
||||
from __future__ import annotations
|
||||
from typing import Annotated
|
||||
|
||||
|
||||
v1: Annotated[str, ClassA, func1(), v2[0]] = ""
|
||||
|
||||
v2 = [1, 2, 3]
|
||||
|
||||
|
||||
class ClassA: ...
|
||||
|
||||
|
||||
def func1(): ...
|
||||
@@ -1,20 +0,0 @@
|
||||
# This sample tests type annotations on variables.
|
||||
|
||||
array1 = [1, 2, 3]
|
||||
|
||||
# This should generate an error because the LHS can't
|
||||
# have a declared type.
|
||||
array1[2] = 4 # type: int
|
||||
|
||||
dict1 = {}
|
||||
|
||||
# This should generate an error because the LHS can't
|
||||
# have a declared type.
|
||||
dict1["hello"] = 4 # type: int
|
||||
|
||||
|
||||
def foo():
|
||||
a: int = 3
|
||||
b: float = 4.5
|
||||
c: str = ""
|
||||
d: int = yield 42
|
||||
@@ -1,28 +0,0 @@
|
||||
# This sample tests annotated types on global variables.
|
||||
|
||||
# This should generate an error because the declared
|
||||
# type below does not match the assigned type.
|
||||
glob_var1 = 4
|
||||
|
||||
# This should generate an error because the declared
|
||||
# type doesn't match the later declared type.
|
||||
glob_var1 = Exception() # type: str
|
||||
|
||||
glob_var1 = Exception() # type: Exception
|
||||
|
||||
# This should generate an error because the assigned
|
||||
# type doesn't match the declared type.
|
||||
glob_var1 = "hello" # type: Exception
|
||||
|
||||
# This should generate an error.
|
||||
glob_var2 = 5
|
||||
|
||||
|
||||
def func1():
|
||||
global glob_var1
|
||||
global glob_var2
|
||||
|
||||
# This should generate an error.
|
||||
glob_var1 = 3
|
||||
|
||||
glob_var2 = "hello" # type: str
|
||||
@@ -1,54 +0,0 @@
|
||||
# This sample tests annotated types on local variables.
|
||||
|
||||
from typing import Any, Optional, Union
|
||||
|
||||
|
||||
class ClassB(object):
|
||||
def __enter__(self) -> bytes:
|
||||
return b"hello"
|
||||
|
||||
def __exit__(
|
||||
self,
|
||||
t: Optional[type] = None,
|
||||
exc: Optional[BaseException] = None,
|
||||
tb: Optional[Any] = None,
|
||||
) -> bool:
|
||||
return True
|
||||
|
||||
|
||||
def func2():
|
||||
local_var = 3 # type: Union[int, str]
|
||||
local_var = "hello"
|
||||
|
||||
# This should generate an error because the assigned
|
||||
# type doesn't match the declared type.
|
||||
local_var = b"hello"
|
||||
|
||||
local_var2 = 3 # type: int
|
||||
|
||||
if local_var:
|
||||
# This should generate an error because the
|
||||
# assigned type doesn't match.
|
||||
local_var = 3.4
|
||||
else:
|
||||
# This should generate an error because the assigned
|
||||
# type doesn't match the declared type.
|
||||
local_var2 = b"hello"
|
||||
|
||||
# This should generate an error because the declared type
|
||||
# of local_var is not compatible.
|
||||
with ClassB() as local_var:
|
||||
pass
|
||||
|
||||
bytes_list = [b"hello"]
|
||||
|
||||
# This should generate an error because the declared type
|
||||
# of local_var is not compatible.
|
||||
for local_var in bytes_list:
|
||||
pass
|
||||
|
||||
# This should generate an error.
|
||||
(local_var, local_var2) = (b"hello", 3)
|
||||
|
||||
# This should generate an error.
|
||||
(local_var, local_var2) = ("hello", b"h")
|
||||
@@ -1,24 +0,0 @@
|
||||
# This sample tests annotated types for class variables.
|
||||
|
||||
|
||||
class ClassA(object):
|
||||
# This should generate an error because the declared
|
||||
# type doesn't match the latter declared type.
|
||||
class_var1 = 4 # type: str
|
||||
|
||||
# This should generate an error because the assigned
|
||||
# value doesn't match the declared type.
|
||||
class_var1 = "hello" # type: int
|
||||
|
||||
class_var1 = 3 # type: int
|
||||
|
||||
# This should generate an error because the declared
|
||||
# type doesn't match the latter declared type.
|
||||
class_var2 = 3 # type: int
|
||||
|
||||
def __init__(self):
|
||||
# This should generate an error because the assigned
|
||||
# type doesn't match the declared type.
|
||||
self.class_var2 = 3 # type: str
|
||||
|
||||
self.class_var2 = "hello"
|
||||
@@ -1,37 +0,0 @@
|
||||
# This sample tests type annotations for instance variables.
|
||||
|
||||
|
||||
class ClassC(object):
|
||||
def __init__(self):
|
||||
self.inst_var1 = 3
|
||||
|
||||
@property
|
||||
def prop1(self):
|
||||
return 1
|
||||
|
||||
@prop1.setter
|
||||
def prop1(self, val):
|
||||
pass
|
||||
|
||||
def foo(self):
|
||||
# This should generate an error because the assigned
|
||||
# type doesn't match the declared type.
|
||||
self.inst_var1 = 3 # type: str
|
||||
|
||||
self.inst_var1: str = "hello"
|
||||
|
||||
# This should generate an error because the declared
|
||||
# type doesn't match the previously declared type.
|
||||
self.inst_var1: int = "hello"
|
||||
|
||||
# This should generate an error because the assigned
|
||||
# type doesn't match the declared type.
|
||||
self.inst_var1 = "hello" # type: int
|
||||
|
||||
self.prop1 = 3
|
||||
|
||||
|
||||
class ClassE(ClassC):
|
||||
def __init__(self):
|
||||
# This should generate an error.
|
||||
self.inst_var1 = 3
|
||||
@@ -1,22 +0,0 @@
|
||||
# This sample tests that class-scoped variables with a declared type
|
||||
# but without a ClassVar designation are treated as instance variables.
|
||||
# Notably, Callable variables should be assumed to be pre-bound to
|
||||
# the object.
|
||||
|
||||
from typing import Callable
|
||||
|
||||
|
||||
def add1(n: int):
|
||||
return n + 1
|
||||
|
||||
|
||||
class Foo:
|
||||
f: Callable[[int], int]
|
||||
|
||||
def m(self):
|
||||
print(self.f(1))
|
||||
|
||||
|
||||
foo = Foo()
|
||||
foo.f = add1
|
||||
foo.m()
|
||||
@@ -1,13 +0,0 @@
|
||||
# This sample tests the reportTypeCommentUsage diagnostic check.
|
||||
|
||||
# This should generate an error if reportTypeCommentUsage is enabled.
|
||||
x = 3 # type: int
|
||||
|
||||
|
||||
class Foo:
|
||||
# This should generate an error if reportTypeCommentUsage is enabled.
|
||||
y = 0 # type: int
|
||||
|
||||
def __init__(self):
|
||||
# This should generate an error if reportTypeCommentUsage is enabled.
|
||||
self.x = 2 # type: int
|
||||
@@ -1,29 +0,0 @@
|
||||
# This sample tests that incompatible types implicitly assigned
|
||||
# to an annotated variable via an import statement are flagged
|
||||
# as an error.
|
||||
|
||||
from typing import Callable, Final
|
||||
|
||||
# This should generate an error because random is already declared.
|
||||
import random
|
||||
|
||||
random: int = 3
|
||||
|
||||
# This should generate an error because os is Final
|
||||
import os.path
|
||||
|
||||
os: Final = 3
|
||||
|
||||
|
||||
# This should generate an error because x is already declared.
|
||||
from math import pow as x
|
||||
|
||||
x: Callable[[], None]
|
||||
|
||||
# This should generate an error because pow is already declared.
|
||||
from math import pow
|
||||
|
||||
pow: int = 3
|
||||
|
||||
y: Callable[[float, float], float]
|
||||
from math import pow as y
|
||||
@@ -1,159 +0,0 @@
|
||||
# This sample tests the handling of type annotations within a
|
||||
# python source file (as opposed to a stub file).
|
||||
|
||||
from typing import Any, Callable, TypeVar, Union
|
||||
import uuid
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
class ClassA:
|
||||
# This should generate an error because ClassA
|
||||
# is not yet defined at the time it's used.
|
||||
def func0(self) -> ClassA | None:
|
||||
return None
|
||||
|
||||
|
||||
class ClassB(ClassA):
|
||||
def func1(self) -> ClassA:
|
||||
return ClassA()
|
||||
|
||||
# This should generate an error because ClassC
|
||||
# is a forward reference, which is not allowed
|
||||
# in a python source file.
|
||||
def func2(self) -> ClassC | None:
|
||||
return None
|
||||
|
||||
def func3(self) -> "ClassC | None":
|
||||
return None
|
||||
|
||||
def func4(self) -> "ClassC | None":
|
||||
return None
|
||||
|
||||
def func5(self) -> "int | None":
|
||||
return None
|
||||
|
||||
|
||||
class ClassC:
|
||||
pass
|
||||
|
||||
|
||||
def func10():
|
||||
pass
|
||||
|
||||
|
||||
# This should generate an error because function calls
|
||||
# are not allowed within a type annotation.
|
||||
x1: func10()
|
||||
|
||||
x2: """
|
||||
Union[
|
||||
int,
|
||||
str
|
||||
]
|
||||
"""
|
||||
|
||||
|
||||
class ClassD:
|
||||
ClassA: "ClassA"
|
||||
|
||||
# This should generate an error because ClassF refers
|
||||
# to itself, and there is no ClassF declared at the module
|
||||
# level. It should also generate a second error because
|
||||
# ClassF is a variable and can't be used as an annotation.
|
||||
ClassF: "ClassF"
|
||||
|
||||
str: "str"
|
||||
|
||||
def int(self): ...
|
||||
|
||||
foo: "int"
|
||||
|
||||
# This should generate an error because it refers to the local
|
||||
# "int" symbol rather than the builtins "int".
|
||||
bar: int
|
||||
|
||||
|
||||
# This should generate an error because modules are not allowed in
|
||||
# type annotations.
|
||||
x3: typing
|
||||
|
||||
|
||||
class ClassG:
|
||||
uuid = uuid.uuid4()
|
||||
|
||||
|
||||
class ClassH:
|
||||
# This should generate an error because uuid refers to the local
|
||||
# symbol in this case, which is a circular reference.
|
||||
uuid: uuid.UUID = uuid.uuid4()
|
||||
|
||||
|
||||
def func11():
|
||||
for t in [str, float]:
|
||||
# This should generate an error because t is not a valid annotation.
|
||||
def f(x: str) -> t:
|
||||
return t(x) + 1
|
||||
|
||||
f("")
|
||||
|
||||
|
||||
def func12(x: type[int]):
|
||||
# These should not generate an error because they are used
|
||||
# in a location that is not considered a type annotation, so the
|
||||
# normal annotation limitations do not apply here.
|
||||
print(Union[x, x])
|
||||
print(x | None)
|
||||
|
||||
|
||||
# This should generate an error because x4 isn't defined.
|
||||
x4: int = x4
|
||||
|
||||
|
||||
class ClassJ:
|
||||
datetime: datetime
|
||||
|
||||
|
||||
T = TypeVar("T")
|
||||
|
||||
|
||||
x5: type[int] = int
|
||||
|
||||
# This should generate an error because variables are not allowed
|
||||
# in a type annotation.
|
||||
x6: x5 = 1
|
||||
|
||||
# This should generate an error because variables are not allowed
|
||||
# in a type annotation.
|
||||
x7: list[x5] = [1]
|
||||
|
||||
# This should generate an error because a Callable isn't allowed
|
||||
# in a "type".
|
||||
x8: type[Callable]
|
||||
|
||||
# This should generate an error because a Callable isn't allowed
|
||||
# in a "type".
|
||||
x9: type[func11]
|
||||
|
||||
# This should generate an error because a Callable isn't allowed
|
||||
# in a "type".
|
||||
x10: type[Callable[..., Any]]
|
||||
|
||||
# This should generate an error because raw strings aren't allowed.
|
||||
x11: r"int"
|
||||
|
||||
# This should generate an error because bytes strings aren't allowed.
|
||||
x12: b"int"
|
||||
|
||||
# This should generate an error because format strings aren't allowed.
|
||||
x13: f"int"
|
||||
|
||||
|
||||
class A:
|
||||
def method1(self):
|
||||
# This should result in an error.
|
||||
x: self
|
||||
|
||||
@classmethod
|
||||
def method2(cls):
|
||||
# This should result in an error.
|
||||
x: cls
|
||||
@@ -1,33 +0,0 @@
|
||||
# This sample tests the parser and type checker's ability to use
|
||||
# type annotations in comments following assignment expressions.
|
||||
# These are used in some older typestub files because they're
|
||||
# compatible with versions of Python before 3.6.
|
||||
|
||||
from typing import List, Optional, Tuple
|
||||
|
||||
a = 3 # type: int
|
||||
|
||||
b = "3" # type: str
|
||||
|
||||
c = [1, 2, 3] # type: Optional[List[int]]
|
||||
|
||||
|
||||
# A type on the next line shouldn't be honored
|
||||
d = "hello"
|
||||
# type: int
|
||||
|
||||
# A type comment with a space between the type and
|
||||
# the colon is also not honored.
|
||||
e = "hello" # type : int
|
||||
|
||||
# Neither is a capital "Type"
|
||||
f = "hello" # Type: int
|
||||
|
||||
|
||||
# This should generate an error because the type doesn't match
|
||||
g = "hello" # type: int
|
||||
|
||||
|
||||
# This should generate an error because the last entry
|
||||
# of the tuple is the wrong type.
|
||||
h = (1, "hello", (5,)) # type: Tuple[int, str, Tuple[str]]
|
||||
@@ -1,37 +0,0 @@
|
||||
# This sample tests the handling of type annotations within a
|
||||
# python source file with the __future__ annotations symbol present.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Optional
|
||||
|
||||
|
||||
class ClassA:
|
||||
def func0(self) -> Optional[ClassA]:
|
||||
return None
|
||||
|
||||
|
||||
class ClassB(ClassA):
|
||||
def func1(self) -> ClassA:
|
||||
return ClassA()
|
||||
|
||||
def func2(self) -> Optional[ClassC]:
|
||||
return None
|
||||
|
||||
def func3(self) -> "Optional[ClassC]":
|
||||
return None
|
||||
|
||||
def func4(self) -> Optional["ClassC"]:
|
||||
return None
|
||||
|
||||
def func5(self, x: ClassA):
|
||||
x.func0()
|
||||
|
||||
class ClassA: ...
|
||||
|
||||
def func6(self, x: ClassC):
|
||||
x.my_int
|
||||
|
||||
|
||||
class ClassC:
|
||||
my_int: int
|
||||
@@ -1,67 +0,0 @@
|
||||
# This sample tests the type checker's reporting of
|
||||
# incompatible declared types.
|
||||
|
||||
from collections.abc import Callable
|
||||
|
||||
|
||||
def a():
|
||||
pass
|
||||
|
||||
|
||||
# This should generate an error for an incompatible assignment.
|
||||
a = 1
|
||||
|
||||
|
||||
# This should generate an error for an obscured type.
|
||||
def b():
|
||||
pass
|
||||
|
||||
|
||||
b: int = 1
|
||||
|
||||
# This should generate an error for an obscured type.
|
||||
c: int = 1
|
||||
c: float = 1.1
|
||||
|
||||
# This should generate two errors - one for an
|
||||
# obscured type, the second for an incompatible assignment.
|
||||
d: int = 2
|
||||
|
||||
|
||||
def d():
|
||||
pass
|
||||
|
||||
|
||||
class Foo:
|
||||
# This should generate an error because aa is redeclared.
|
||||
aa: int
|
||||
|
||||
def aa(self):
|
||||
return 3
|
||||
|
||||
|
||||
# This should generate two errors, one for each param.
|
||||
def my_func(param1: int, param2):
|
||||
param1: int = 3
|
||||
param2: int = 4
|
||||
|
||||
|
||||
# This should be fine because both declarations of 'e'
|
||||
# use the same type.
|
||||
e: list[int]
|
||||
e = [3]
|
||||
e: list[int]
|
||||
|
||||
|
||||
def register(fn: Callable[[], None]) -> None: ...
|
||||
|
||||
|
||||
# These should be be fine because they use the "_" name.
|
||||
@register
|
||||
def _():
|
||||
print("Callback 1 called")
|
||||
|
||||
|
||||
@register
|
||||
def _():
|
||||
print("Callback 2 called")
|
||||
@@ -1,9 +0,0 @@
|
||||
# This sample tests the handling of tuple expressions within a subscript
|
||||
# when used with type annotations.
|
||||
|
||||
a1: dict[(str, str)] = {"hi": "there"}
|
||||
|
||||
# This should generate an error because there are too many type arguments.
|
||||
a2: dict[(str, str, str)] = {"hi": "there"}
|
||||
|
||||
b1: list[(int,)] = [3, 4, 5]
|
||||
@@ -1,29 +0,0 @@
|
||||
# This sample verifies that the Type[] and type[] annotations work
|
||||
# as expected when the type argument is Any.
|
||||
|
||||
from typing import Type, Any
|
||||
|
||||
|
||||
def is_type1(x: object, y: Type[Any]) -> bool:
|
||||
return isinstance(x, y)
|
||||
|
||||
|
||||
is_type1(1, int)
|
||||
|
||||
# This should generate an error.
|
||||
is_type1(1, 1)
|
||||
|
||||
|
||||
def is_type2(x: object, y: type[Any]) -> bool:
|
||||
return isinstance(x, y)
|
||||
|
||||
|
||||
is_type2(1, int)
|
||||
|
||||
# This should generate an error.
|
||||
is_type2(1, 1)
|
||||
|
||||
|
||||
def func1(v1: Type[Any], v2: type[Any]):
|
||||
reveal_type(v1, expected_text="Type[Any]")
|
||||
reveal_type(v2, expected_text="type[Any]")
|
||||
@@ -1,45 +0,0 @@
|
||||
# This sample tests certain uses of Any that should be flagged as illegal.
|
||||
|
||||
import typing
|
||||
from typing import Any, cast
|
||||
|
||||
# This should generate an error because Any is not valid for isinstance.
|
||||
isinstance(0, Any)
|
||||
|
||||
# This should generate an error because Any is not valid for isinstance.
|
||||
isinstance(0, typing.Any)
|
||||
|
||||
v1 = cast(Any, 0)
|
||||
v2 = cast(typing.Any, 0)
|
||||
|
||||
|
||||
class A(Any): ...
|
||||
|
||||
|
||||
class B(typing.Any): ...
|
||||
|
||||
|
||||
# This should generate an error because Any is not callable.
|
||||
Any()
|
||||
|
||||
# This should generate an error because Any is not callable.
|
||||
typing.Any()
|
||||
|
||||
|
||||
def func1() -> int:
|
||||
# This should generate an error because Any cannot be used as a value.
|
||||
return Any
|
||||
|
||||
|
||||
def func2() -> int:
|
||||
# This should generate an error because Any cannot be used as a value.
|
||||
return typing.Any
|
||||
|
||||
|
||||
v3: type[Any] = type(Any)
|
||||
|
||||
# This should generate an error.
|
||||
v4: type[type] = type(Any)
|
||||
|
||||
# This should generate an error.
|
||||
v5: type = Any
|
||||
@@ -1,22 +0,0 @@
|
||||
# This sample tests the ability to detect errant assert calls
|
||||
# that are always true - the "reportAssertAlwaysTrue" option.
|
||||
|
||||
from typing import Any, Tuple
|
||||
|
||||
|
||||
# This should generate a warning.
|
||||
assert (1 != 2, "Error message")
|
||||
|
||||
|
||||
def foo(a: Tuple[int, ...]):
|
||||
assert a
|
||||
|
||||
|
||||
b = ()
|
||||
assert b
|
||||
|
||||
|
||||
c = (2, 3)
|
||||
|
||||
# This should generate a warning.
|
||||
assert c
|
||||
@@ -1,48 +0,0 @@
|
||||
# This sample tests the assert_type call.
|
||||
|
||||
from typing import Any, Literal
|
||||
from typing_extensions import assert_type # viper: ignore[reportMissingModuleSource]
|
||||
|
||||
|
||||
def func1():
|
||||
# This should generate an error.
|
||||
assert_type()
|
||||
|
||||
# This should generate an error.
|
||||
assert_type(1)
|
||||
|
||||
# This should generate an error.
|
||||
assert_type(1, 2, 3)
|
||||
|
||||
# This should generate an error.
|
||||
assert_type(*[])
|
||||
|
||||
|
||||
def func2(x: int, y: int | str, z: list):
|
||||
assert_type(x, int)
|
||||
|
||||
# This should generate an error.
|
||||
assert_type(x, str)
|
||||
|
||||
# This should generate an error.
|
||||
assert_type(x, Any)
|
||||
|
||||
x = 3
|
||||
assert_type(x, Literal[3])
|
||||
|
||||
# This should generate an error.
|
||||
assert_type(x, int)
|
||||
|
||||
assert_type(y, int | str)
|
||||
assert_type(y, str | int)
|
||||
|
||||
# This should generate an error.
|
||||
assert_type(y, str)
|
||||
|
||||
# This should generate an error.
|
||||
assert_type(y, None)
|
||||
|
||||
# This should generate two errors.
|
||||
assert_type(y, 3)
|
||||
|
||||
assert_type(z[0], Any)
|
||||
@@ -1,72 +0,0 @@
|
||||
# This sample tests the type checker's handling of
|
||||
# member assignments.
|
||||
|
||||
from not_present import NotPresentClass # type: ignore
|
||||
|
||||
|
||||
class ClassA:
|
||||
def __init__(self):
|
||||
self.string_list: list[str] = []
|
||||
|
||||
def do_something(self, num: int) -> str:
|
||||
return ""
|
||||
|
||||
|
||||
a = ClassA()
|
||||
|
||||
a.string_list = ["yep"]
|
||||
|
||||
# This should generate an error because of a type mismatch.
|
||||
a.string_list = "bbb"
|
||||
|
||||
# This should generate an error because of a type mismatch.
|
||||
a.string_list = {}
|
||||
|
||||
# This should generate an error because of a type mismatch.
|
||||
a.string_list = [1]
|
||||
|
||||
# This should generate an error because there is no member
|
||||
# called string_list2 defined.
|
||||
a.string_list2 = 4
|
||||
|
||||
|
||||
def patch1(num: int) -> str:
|
||||
return ""
|
||||
|
||||
|
||||
def patch2(self, num: int) -> str:
|
||||
return ""
|
||||
|
||||
|
||||
a.do_something = lambda num: "hello"
|
||||
a.do_something = patch1
|
||||
|
||||
# This should generate an error because of a param count mismatch
|
||||
a.do_something = lambda: "hello"
|
||||
|
||||
# This should generate an error because of a return type mismatch
|
||||
a.do_something = lambda x: 1
|
||||
|
||||
|
||||
ClassA.do_something = patch2
|
||||
|
||||
# This should generate an error because of a param count mismatch
|
||||
ClassA.do_something = patch1
|
||||
|
||||
|
||||
class ClassB:
|
||||
# This should generate an error because assignment expressions
|
||||
# can't be used within a class.
|
||||
[(j := i) for i in range(5)]
|
||||
|
||||
|
||||
class ClassC:
|
||||
def __init__(self):
|
||||
self.x = NotPresentClass # type: int
|
||||
self.y: int
|
||||
self.y = NotPresentClass
|
||||
self.z: int = NotPresentClass
|
||||
|
||||
reveal_type(self.x, expected_text="Unknown | int")
|
||||
reveal_type(self.y, expected_text="Unknown | int")
|
||||
reveal_type(self.z, expected_text="Unknown | int")
|
||||
@@ -1,83 +0,0 @@
|
||||
# This sample tests some cases where types are narrowed on assignment,
|
||||
# including some cases that involve "Any".
|
||||
|
||||
from typing import Any, Generic, Iterable, TypeVar
|
||||
|
||||
|
||||
class A:
|
||||
instance: "A | None"
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.foo: bool
|
||||
|
||||
@classmethod
|
||||
def method1(cls) -> bool:
|
||||
if cls.instance is None:
|
||||
cls.instance = cls()
|
||||
return cls.instance.foo
|
||||
|
||||
|
||||
T = TypeVar("T")
|
||||
|
||||
|
||||
class B(Generic[T]): ...
|
||||
|
||||
|
||||
def func1(v1: list[Any | None], v2: list[int | str]):
|
||||
x1: list[int | None] = v1
|
||||
reveal_type(x1, expected_text="list[int | None]")
|
||||
|
||||
x2: list[Any] = v2
|
||||
reveal_type(x2, expected_text="list[Any]")
|
||||
|
||||
x3: list[Any | str] = v2
|
||||
reveal_type(x3, expected_text="list[Any | str]")
|
||||
|
||||
|
||||
def func2(v1: dict[int, Any | None], v2: dict[int, int | str]):
|
||||
x1: dict[int, int | None] = v1
|
||||
reveal_type(x1, expected_text="dict[int, int | None]")
|
||||
|
||||
x2: dict[Any, Any] = v2
|
||||
reveal_type(x2, expected_text="dict[Any, Any]")
|
||||
|
||||
x3: dict[Any, Any | str] = v2
|
||||
reveal_type(x3, expected_text="dict[Any, Any | str]")
|
||||
|
||||
|
||||
def func3(y: list[int]):
|
||||
x1: Iterable[int | B[Any]] = y
|
||||
reveal_type(x1, expected_text="list[int]")
|
||||
|
||||
x2: Iterable[Any | B[Any]] = y
|
||||
reveal_type(x2, expected_text="list[int]")
|
||||
|
||||
x3: Iterable[Any] = y
|
||||
reveal_type(x3, expected_text="list[int]")
|
||||
|
||||
|
||||
def func4(y: list[Any]):
|
||||
x1: Iterable[int | B[Any]] = y
|
||||
reveal_type(x1, expected_text="list[Any]")
|
||||
|
||||
x2: Iterable[Any | B[Any]] = y
|
||||
reveal_type(x2, expected_text="list[Any]")
|
||||
|
||||
x3: Iterable[Any] = y
|
||||
reveal_type(x3, expected_text="list[Any]")
|
||||
|
||||
|
||||
def func5(v1: list[Any | None]):
|
||||
x1: list[int | None] = v1
|
||||
reveal_type(x1, expected_text="list[int | None]")
|
||||
|
||||
|
||||
def func6(v1: tuple[Any], v2: tuple[int, Any], v3: tuple[Any, ...]):
|
||||
x1: tuple[int] = v1
|
||||
reveal_type(x1, expected_text="tuple[int]")
|
||||
|
||||
x2: tuple[int, str] = v2
|
||||
reveal_type(x2, expected_text="tuple[int, str]")
|
||||
|
||||
x3: tuple[str, ...] = v3
|
||||
reveal_type(x3, expected_text="tuple[str, ...]")
|
||||
@@ -1,20 +0,0 @@
|
||||
# This sample tests the type checker's handling of chained assignments.
|
||||
|
||||
a1 = b1 = c1 = d1 = 3
|
||||
|
||||
my_list = [10]
|
||||
a2 = my_list[a2] = b2 = my_list[b2] = 0
|
||||
|
||||
# This should generate an error because a3 is read before written.
|
||||
my_list[a3] = a3 = 0
|
||||
|
||||
|
||||
# This should generate an error because type comments are not
|
||||
# allowed for chained assignments.
|
||||
x1 = x2 = x3 = [3] # type: list[float]
|
||||
|
||||
|
||||
# Bidirectional type inference should be used in this case.
|
||||
y2: list[list[float]]
|
||||
y1 = y2 = [[3]]
|
||||
reveal_type(y1, expected_text="list[list[float]]")
|
||||
@@ -1,24 +0,0 @@
|
||||
# This sample tests the case where a variable with a declared type
|
||||
# is assigned an unknown value or partially-unknown value.
|
||||
|
||||
|
||||
def a_test(x1: int, x2: list):
|
||||
u = x1.upper() # type: ignore
|
||||
reveal_type(u, expected_text="Unknown")
|
||||
|
||||
# This should generate an error if reportUnknownVariableType is enabled.
|
||||
y: str = u
|
||||
reveal_type(y, expected_text="Unknown | str")
|
||||
|
||||
# This should generate an error if reportUnknownVariableType is enabled.
|
||||
z: list[str] = x2
|
||||
reveal_type(z, expected_text="list[str]")
|
||||
|
||||
|
||||
def b_test(x: int | str):
|
||||
u = x.upper() # type: ignore
|
||||
reveal_type(u, expected_text="str | Unknown")
|
||||
|
||||
# This should generate an error if reportUnknownVariableType is enabled.
|
||||
y: str = u
|
||||
reveal_type(y, expected_text="str | Unknown")
|
||||
@@ -1,43 +0,0 @@
|
||||
# This sample tests assignments to indexed expressions
|
||||
# where the base is a specialized object.
|
||||
|
||||
# Enable the reportUnknownArgumentType check so we can verify that it
|
||||
# doesn't generate an error when assigning an empty list to an indexed
|
||||
# expression.
|
||||
# viper: reportUnknownArgumentType=true
|
||||
|
||||
|
||||
v1: list[int] = [1, 2, 3, 4, 5]
|
||||
# This should generate an error because the assigned type is wrong.
|
||||
v1[0] = "a"
|
||||
|
||||
v2: dict[int, str] = {1: "str"}
|
||||
# This should generate an error because the assigned type is wrong.
|
||||
v2[1] = 123
|
||||
|
||||
v3: list[int | str] = ["a"]
|
||||
v3[0] = 3
|
||||
reveal_type(v3[0], expected_text="Literal[3]")
|
||||
|
||||
|
||||
v4: dict[str, int | str] = {}
|
||||
v4["aaa"] = 3
|
||||
v4["bbb"] = "bbb"
|
||||
reveal_type(v4["aaa"], expected_text="Literal[3]")
|
||||
reveal_type(v4["bbb"], expected_text="Literal['bbb']")
|
||||
reveal_type(v4["ccc"], expected_text="int | str")
|
||||
|
||||
|
||||
class Asymmetric:
|
||||
def __setitem__(self, i: int, value: object) -> None: ...
|
||||
|
||||
def __getitem__(self, i: int) -> int: ...
|
||||
|
||||
|
||||
v5 = Asymmetric()
|
||||
v5[0] = 3
|
||||
reveal_type(v5[0], expected_text="int")
|
||||
|
||||
|
||||
v6 = [1, 2, 3]
|
||||
v6[1:] = []
|
||||
@@ -1,51 +0,0 @@
|
||||
# This sample tests various assignment scenarios where
|
||||
# there is an expected type, so bidirectional type
|
||||
# inference is used.
|
||||
|
||||
from typing import Callable, Literal, Protocol
|
||||
|
||||
f1: Callable[[int, int], int] = lambda a, b: a + b
|
||||
|
||||
# This should generate an error because x should be
|
||||
# determined to be an "int", so "len(x)" is invalid.
|
||||
map(lambda x: len(x), [1, 2, 3])
|
||||
|
||||
|
||||
def must_be_int(val: int):
|
||||
return val
|
||||
|
||||
|
||||
d1: dict[str, tuple[int, Callable[[int], int]]] = {
|
||||
"hello": (3, lambda x: must_be_int(x))
|
||||
}
|
||||
|
||||
d2: dict[str, tuple[int, Callable[[int], int]]] = {
|
||||
# This should generate an error because the key is not a str.
|
||||
3: (3, lambda x: must_be_int(x))
|
||||
}
|
||||
|
||||
d3: dict[str, tuple[int, Callable[[int], int]]] = {
|
||||
# This should generate an error because the first element
|
||||
# of the tuple is not the correct type.
|
||||
"3": (3.0, lambda x: must_be_int(x))
|
||||
}
|
||||
|
||||
d4: dict[str, tuple[int, Callable[[int], int]]] = {
|
||||
# This should generate an error because the lambda
|
||||
# type doesn't match.
|
||||
"3": (3, lambda _: 3.4)
|
||||
}
|
||||
|
||||
|
||||
class Adder(Protocol):
|
||||
def __call__(self, x: int, y: dict[str, int]) -> int: ...
|
||||
|
||||
|
||||
v1: Adder = lambda x, y: x + y["hi"]
|
||||
reveal_type(v1, expected_text="(x: int, y: dict[str, int]) -> int")
|
||||
|
||||
|
||||
class A:
|
||||
@classmethod
|
||||
def method1(cls):
|
||||
cls.v1: list[Literal[0]] = [] if issubclass(cls, int) else [0]
|
||||
@@ -1,20 +0,0 @@
|
||||
# This sample tests various assignment scenarios where
|
||||
# there is an expected type, so bidirectional type
|
||||
# inference is used.
|
||||
|
||||
# viper: strict
|
||||
|
||||
from typing import Callable, Sequence
|
||||
|
||||
AAA = float
|
||||
BBB = int
|
||||
CCC = str
|
||||
DDD = str
|
||||
AAATuple = tuple[AAA, BBB, Callable[[Sequence[int], AAA], Sequence[float]]]
|
||||
|
||||
|
||||
def foo():
|
||||
var1: dict[str, tuple[AAA, BBB, CCC, DDD]] = {}
|
||||
var2: dict[str, AAATuple] = {}
|
||||
for k, (var3, var4, _, _) in var1.items():
|
||||
var2[k] = (var3, var4, lambda var5, var6: [v * var6 for v in var5])
|
||||
@@ -1,16 +0,0 @@
|
||||
# This sample tests the handling of tuple assignments
|
||||
# where the order of assignment within the tuple is important.
|
||||
|
||||
from typing import Optional
|
||||
|
||||
|
||||
class Node:
|
||||
key: str
|
||||
next: Optional["Node"] = None
|
||||
|
||||
|
||||
node = Node()
|
||||
|
||||
# This should analyze fine because node.next should be assigned
|
||||
# None before node is assigned None.
|
||||
node.next, node = None, None
|
||||
@@ -1,25 +0,0 @@
|
||||
# This sample tests that the type checker handles the case
|
||||
# where a symbol within a class scope is assigned an expression
|
||||
# that includes the same symbol, but that same symbol is defined
|
||||
# in an outer scope.
|
||||
|
||||
a = 0
|
||||
b = 1
|
||||
c = 4
|
||||
|
||||
|
||||
class MyClass:
|
||||
# This should not generate an error because
|
||||
# the RHS of the assignment refers to a different
|
||||
# "a", declared in an outer scope.
|
||||
a = a
|
||||
|
||||
# Same with "b" here.
|
||||
(b, a) = (b, 3)
|
||||
|
||||
# Same with "c" here.
|
||||
[c] = [c]
|
||||
|
||||
# This should generate an error because "d" is
|
||||
# not declared in the outer scope.
|
||||
e = d
|
||||
@@ -1,13 +0,0 @@
|
||||
# This sample tests a particularly difficult set of dependent
|
||||
# assignments that involve tuple packing and unpacking.
|
||||
|
||||
# viper: strict
|
||||
|
||||
v1 = ""
|
||||
v3 = ""
|
||||
|
||||
v2, _ = v1, v3
|
||||
v4 = v2
|
||||
for _ in range(1):
|
||||
v1 = v4
|
||||
v2, v3 = v1, ""
|
||||
@@ -1,38 +0,0 @@
|
||||
# This sample ensures that a variable of type "object" can be
|
||||
# assigned any other type.
|
||||
|
||||
import os
|
||||
from typing import Any, TypeVar, overload
|
||||
|
||||
|
||||
class Foo:
|
||||
@overload
|
||||
def bar(self, obj: None) -> object: ...
|
||||
|
||||
@overload
|
||||
def bar(self, obj: object) -> Any: ...
|
||||
|
||||
def bar(self, obj: object | None) -> Any:
|
||||
pass
|
||||
|
||||
@staticmethod
|
||||
def baz():
|
||||
return 3
|
||||
|
||||
|
||||
_T = TypeVar("_T")
|
||||
|
||||
my_obj: object
|
||||
|
||||
my_obj = None
|
||||
my_obj = os
|
||||
my_obj = Foo
|
||||
my_obj = Foo()
|
||||
my_obj = Foo.bar
|
||||
my_obj = Foo.baz
|
||||
my_obj = ()
|
||||
my_obj = lambda x: x
|
||||
my_obj = _T
|
||||
|
||||
# This should generate an error because a is unbound.
|
||||
my_obj = a
|
||||
@@ -1,23 +0,0 @@
|
||||
# This sample tests assignment when the types are invariant and the
|
||||
# source or destination are unions that contains subtypes which are
|
||||
# subclasses of each other.
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
class FloatSubclass(float):
|
||||
pass
|
||||
|
||||
|
||||
float_list: list[float] = [1.0, 2.0]
|
||||
|
||||
v1: list[float | FloatSubclass] = float_list
|
||||
|
||||
v2: list[int | float] = float_list
|
||||
|
||||
# This should generate an error.
|
||||
v3: list[int | float | datetime] = float_list
|
||||
|
||||
|
||||
v4: list[FloatSubclass | float] = []
|
||||
v5: list[float] = v4
|
||||
@@ -1,26 +0,0 @@
|
||||
# This sample tests the Python 3.8 assignment expressions.
|
||||
|
||||
# viper: reportUnusedExpression=false
|
||||
|
||||
def func1():
|
||||
b = 'a'
|
||||
d = 'b'
|
||||
|
||||
a = (b := 3)
|
||||
|
||||
# This should generate an error because the
|
||||
# item to the left of an assignment expression
|
||||
# must be a name.
|
||||
a + 3 := 3
|
||||
|
||||
# This should generate an error because parens
|
||||
# are required in this case.
|
||||
c = d := 3
|
||||
|
||||
# This should generate an error because parens are required in this case.
|
||||
val if val := 1 + 2 else None
|
||||
|
||||
val2 if (val2 := 1 + 2) else None
|
||||
|
||||
# This should generate an error because parens are not allowed in asserts.
|
||||
assert e := 1
|
||||
@@ -1,67 +0,0 @@
|
||||
# This sample tests the Python 3.8 assignment expressions. This sample
|
||||
# is taken from PEP 257.
|
||||
|
||||
# viper: reportUnusedExpression=false
|
||||
|
||||
import re
|
||||
|
||||
def func1(x: float):
|
||||
...
|
||||
|
||||
def pep572_examples():
|
||||
if (match := re.search('123', '252')) is not None:
|
||||
print(match)
|
||||
print(match)
|
||||
|
||||
file = open('hello')
|
||||
while chunk := file.read(8192):
|
||||
print(chunk)
|
||||
print(chunk)
|
||||
|
||||
def f(x: float):
|
||||
return x
|
||||
mylist = [y := f(25), y**2, y**3]
|
||||
|
||||
data = [1, 2, 3]
|
||||
filtered_data = [y for x in data if (y := f(x)) is not None]
|
||||
print(filtered_data)
|
||||
|
||||
# This should generate an error.
|
||||
y := f(25) # INVALID
|
||||
(y := f(25)) # Valid, though not recommended
|
||||
|
||||
y1 = 1
|
||||
|
||||
# This should generate an error.
|
||||
y0 = y1 := f(25) # INVALID
|
||||
y0 = (y1 := f(25)) # Valid, though discouraged
|
||||
|
||||
# This should generate an error.
|
||||
func1(x = y := f(25)) # INVALID
|
||||
func1(x=(y := f(25))) # Valid, though probably confusing
|
||||
|
||||
# This should generate an error.
|
||||
[y for x in [0, 1] if y := x - 1]
|
||||
|
||||
[y for x in [0, 1] if (y := x - 1)]
|
||||
|
||||
|
||||
def func2():
|
||||
# This should generate an error.
|
||||
yield y := 1
|
||||
|
||||
def func3():
|
||||
# This should generate an error.
|
||||
yield from y := [1]
|
||||
|
||||
def func4():
|
||||
# This should generate an error.
|
||||
v1 = {x := 'a': 0}
|
||||
|
||||
v2 = {(x := 'a'): 0}
|
||||
|
||||
# This should generate an error.
|
||||
v3 = {x := 'a': i for i in range(4)}
|
||||
|
||||
v4 = {(x := 'a'): i for i in range(4)}
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
# This sample tests the Python 3.8 assignment expressions.
|
||||
|
||||
import re
|
||||
|
||||
def foo1(x: float):
|
||||
...
|
||||
|
||||
p = 3
|
||||
|
||||
# This should generate an error.
|
||||
def foo2(answer = p := 42): # INVALID
|
||||
...
|
||||
|
||||
def foo3(answer=(p := 42)): # Valid, though not great style
|
||||
...
|
||||
|
||||
default_value: int = 3
|
||||
|
||||
# This should generate two errors.
|
||||
def foo4(answer: p := default_value = 5): # INVALID
|
||||
...
|
||||
|
||||
# This should generate an error.
|
||||
(lambda: x := 1) # INVALID
|
||||
lambda: (x := 1) # Valid, but unlikely to be useful
|
||||
(x := lambda: 1) # Valid
|
||||
lambda line: (m := re.match('pattern', 'line')) and m.group(1) # Valid
|
||||
@@ -1,49 +0,0 @@
|
||||
# This sample tests error detection for certain cases that
|
||||
# are explicitly disallowed by PEP 572 for assignment expressions
|
||||
# when used in context of a list comprehension.
|
||||
|
||||
pairs = []
|
||||
stuff = []
|
||||
|
||||
# These should generate an error because assignment
|
||||
# expressions aren't allowed within an iterator expression
|
||||
# in a "for" clause of a list comprehension.
|
||||
[x for x, y in (pairs2 := pairs) if x % 2 == 0]
|
||||
[x for x, y in ([1, 2, 3, pairs2 := pairs]) if x % 2 == 0]
|
||||
{x: y for x, y in (pairs2 := pairs) if x % 2 == 0}
|
||||
{x for x, y in (pairs2 := pairs) if x % 2 == 0}
|
||||
foo = (x for x, y in ([1, 2, 3, pairs2 := pairs]) if x % 2 == 0)
|
||||
|
||||
# This should generate an error because 'j' is used as a
|
||||
# "for target" and the target of an assignment expression.
|
||||
[[(j := j) for i in range(5)] for j in range(5)]
|
||||
[i := 0 for i, j in stuff]
|
||||
[i + 1 for i in (i := stuff)]
|
||||
|
||||
[False and (i := 0) for i, j in stuff]
|
||||
[i for i, j in stuff if True or (j := 1)]
|
||||
|
||||
# These should generate an error because assignment
|
||||
# expressions aren't allowed within an iterator expression
|
||||
# in a "for" clause of a list comprehension.
|
||||
[i + 1 for i in (j := stuff)]
|
||||
[i + 1 for i in range(2) for j in (k := stuff)]
|
||||
[i + 1 for i in [j for j in (k := stuff)]]
|
||||
[i + 1 for i in (lambda: (j := stuff))()]
|
||||
|
||||
|
||||
class Example:
|
||||
# This should generate an error because the containing
|
||||
# scope for the list comprehension is a class.
|
||||
[(j := i) for i in range(5)]
|
||||
|
||||
x = ((y := 1), (z := 2))
|
||||
|
||||
|
||||
Example.x
|
||||
Example.y
|
||||
Example.z
|
||||
|
||||
# This should generate an error because 'j' is used as a
|
||||
# "for target" and the target of an assignment expression.
|
||||
[i for i in [1, 2] if True or (j := 1) for j in range(10)]
|
||||
@@ -1,23 +0,0 @@
|
||||
# This sample tests the scoping rules for assignment expressions
|
||||
# within a list comprehension.
|
||||
|
||||
# viper: strict
|
||||
|
||||
from typing import Tuple
|
||||
|
||||
|
||||
def func1() -> Tuple[str, int]:
|
||||
a = 3
|
||||
y = 4
|
||||
_ = [(a := x) for x in ["1", "2"] for _ in ["1", "2"]]
|
||||
|
||||
# The type of "y" should be int because the "y" within
|
||||
# the list comprehension doesn't leak outside. On the
|
||||
# other hand, "a" does leak outside the list comprehension.
|
||||
return (a, y)
|
||||
|
||||
|
||||
def get_value(x: int) -> int: ...
|
||||
|
||||
|
||||
x = sum(max(value for x in range(10) if (value := get_value(x))) for _ in range(10))
|
||||
@@ -1,10 +0,0 @@
|
||||
# This sample tests that type guards work correctly
|
||||
# with the walrus operator.
|
||||
|
||||
import re
|
||||
|
||||
|
||||
def foo(s: str) -> str:
|
||||
if m := re.fullmatch("(test).+", s):
|
||||
return m.group(1)
|
||||
return "oops"
|
||||
@@ -1,23 +0,0 @@
|
||||
# This sample tests assignment expressions used within arguments.
|
||||
|
||||
from dataclasses import dataclass
|
||||
from typing import Mapping
|
||||
import collections
|
||||
|
||||
|
||||
class NearestKeyDict(collections.UserDict):
|
||||
def method1(self, key):
|
||||
a = len(keys := [k for k in sorted(self.data) if k >= key])
|
||||
|
||||
# This should generate an error because walrus operators
|
||||
# are not allowed with named arguments.
|
||||
b = list(iterable = keys := [k for k in sorted(self.data) if k >= key])
|
||||
|
||||
|
||||
@dataclass
|
||||
class DC1:
|
||||
x: str
|
||||
|
||||
|
||||
def func1(mapping: Mapping[str, dict]):
|
||||
return [DC1(temp := "x", **mapping[temp])]
|
||||
@@ -1,11 +0,0 @@
|
||||
# This sample checks that parsing for the assignment expression
|
||||
# operator is using the correct precedence. It should be parsing
|
||||
# the RHS as a "test expression" which allows for ternary
|
||||
# expressions.
|
||||
|
||||
result = None
|
||||
|
||||
if items := 3 if result else None:
|
||||
pass
|
||||
|
||||
print(items)
|
||||
@@ -1,42 +0,0 @@
|
||||
# This sample tests the case where an assignment expression target
|
||||
# is found within a function decorator or a function default value expression.
|
||||
|
||||
from typing import Any, Callable, TypeVar, overload
|
||||
|
||||
|
||||
_T = TypeVar("_T")
|
||||
|
||||
|
||||
def decorator(*args: Any, **kwargs: Any) -> Callable[[_T], _T]: ...
|
||||
|
||||
|
||||
@decorator(
|
||||
[
|
||||
walrus_target_1
|
||||
for combination in [[1]]
|
||||
if None not in (walrus_target_1 := set(combination))
|
||||
],
|
||||
)
|
||||
def decorated(
|
||||
x: list[str] = [x for x in ["a", "b"] if x in (walrus_target_2 := ["a", "b"])],
|
||||
):
|
||||
pass
|
||||
|
||||
|
||||
reveal_type(walrus_target_1, expected_text="set[int]")
|
||||
reveal_type(walrus_target_2, expected_text="list[str]")
|
||||
|
||||
|
||||
@overload
|
||||
def func1(value: None = None) -> None: ...
|
||||
|
||||
|
||||
@overload
|
||||
def func1(value: str) -> str: ...
|
||||
|
||||
|
||||
def func1(value: str | None = None) -> str | None:
|
||||
return value
|
||||
|
||||
|
||||
func1(value=(param_value := "test"))
|
||||
@@ -1,49 +0,0 @@
|
||||
# This sample validates that "async" is flagged as an error when
|
||||
# used in inappropriate locations.
|
||||
|
||||
from contextlib import AsyncExitStack
|
||||
|
||||
|
||||
async def b():
|
||||
for i in range(5):
|
||||
yield i
|
||||
|
||||
|
||||
cm = AsyncExitStack()
|
||||
|
||||
|
||||
def func1():
|
||||
# This should generate an error because
|
||||
# "async" cannot be used in a non-async function.
|
||||
async for x in b():
|
||||
print("")
|
||||
|
||||
# This is allowed because it's in a generator.
|
||||
y = (x async for x in b())
|
||||
|
||||
# This should generate an error because
|
||||
# "async" cannot be used in a non-async function.
|
||||
async with cm:
|
||||
pass
|
||||
|
||||
# This should generate an error because
|
||||
# "async" cannot be used in a non-async function.
|
||||
return [x async for x in b()]
|
||||
|
||||
|
||||
# This should generate an error because
|
||||
# "async" cannot be used in a non-async function.
|
||||
async for x in b():
|
||||
print("")
|
||||
|
||||
# This is allowed because it's in a generator.
|
||||
y = (x async for x in b())
|
||||
|
||||
# This should generate an error because
|
||||
# "async" cannot be used in a non-async function.
|
||||
async with cm:
|
||||
pass
|
||||
|
||||
# This should generate an error because
|
||||
# "async" cannot be used in a non-async function.
|
||||
[x async for x in b()]
|
||||
@@ -1,62 +0,0 @@
|
||||
# This sample tests the type checker's handling of
|
||||
# augmented assignments (combining a binary operator
|
||||
# with an assignment).
|
||||
|
||||
|
||||
a = 1
|
||||
b = 3.4
|
||||
|
||||
a += b
|
||||
reveal_type(a, expected_text="float")
|
||||
|
||||
a -= b
|
||||
reveal_type(a, expected_text="float")
|
||||
|
||||
a *= b
|
||||
reveal_type(a, expected_text="float")
|
||||
|
||||
a /= b
|
||||
reveal_type(a, expected_text="float")
|
||||
|
||||
a //= b
|
||||
reveal_type(a, expected_text="float")
|
||||
|
||||
a %= b
|
||||
reveal_type(a, expected_text="float")
|
||||
|
||||
a **= b
|
||||
reveal_type(a, expected_text="Any")
|
||||
|
||||
a = 1
|
||||
|
||||
# This should generate an error because
|
||||
# matrix multiply isn't supported by int.
|
||||
a @= b
|
||||
|
||||
a |= b
|
||||
a &= b
|
||||
a ^= b
|
||||
a <<= b
|
||||
a >>= b
|
||||
|
||||
|
||||
list1 = [1, 2, 3]
|
||||
list1 += [4]
|
||||
|
||||
# This should generate an error
|
||||
list1 += 4
|
||||
|
||||
# This should generate an error
|
||||
list2 = [1]
|
||||
list2 *= 4
|
||||
|
||||
# This should generate an error
|
||||
list2 *= [4]
|
||||
|
||||
|
||||
# Test __iadd__ override in list class, which accepts
|
||||
# any iterator as an argument.
|
||||
bar = ("d",)
|
||||
foo = ["a", "b"]
|
||||
foo += ["c"]
|
||||
foo += bar
|
||||
@@ -1,18 +0,0 @@
|
||||
# This sample tests expected diagnostics for augmented assignment
|
||||
# expressions.
|
||||
|
||||
|
||||
def func1(values1: list[float] = [], values2: list[float] | None = None) -> None:
|
||||
values3 = None
|
||||
|
||||
# This should generate an error
|
||||
values1 += values2
|
||||
|
||||
if values2 is not None:
|
||||
values1 += values2
|
||||
|
||||
# This should generate an error
|
||||
values1 -= values2
|
||||
|
||||
# This should generate an error
|
||||
values1 += values3
|
||||
@@ -1,21 +0,0 @@
|
||||
# This sample tests the case where a class-scoped variable
|
||||
# type needs to be inferred from an augmented assignment.
|
||||
|
||||
|
||||
class ClassA:
|
||||
y = 0
|
||||
z = 0
|
||||
z += 0.5
|
||||
|
||||
def __init__(self):
|
||||
self.x = 0
|
||||
self.x += 0.5
|
||||
|
||||
@classmethod
|
||||
def method1(cls):
|
||||
cls.y += 0.5
|
||||
|
||||
|
||||
reveal_type(ClassA().x, expected_text="int | float")
|
||||
reveal_type(ClassA.y, expected_text="int | float")
|
||||
reveal_type(ClassA.z, expected_text="int | float")
|
||||
@@ -1,164 +0,0 @@
|
||||
# This sample tests variance inference for type variables that use
|
||||
# autovariance.
|
||||
|
||||
from dataclasses import dataclass
|
||||
from typing import Final, Iterator, Sequence, overload
|
||||
|
||||
|
||||
class ShouldBeCovariant1[T]:
|
||||
def __getitem__(self, index: int) -> T: ...
|
||||
|
||||
def __iter__(self) -> Iterator[T]: ...
|
||||
|
||||
|
||||
vco1_1: ShouldBeCovariant1[float] = ShouldBeCovariant1[int]()
|
||||
|
||||
# This should generate an error based on variance.
|
||||
vco1_2: ShouldBeCovariant1[int] = ShouldBeCovariant1[float]()
|
||||
|
||||
|
||||
class ShouldBeCovariant2[T](Sequence[T]):
|
||||
def __len__(self) -> int: ...
|
||||
@overload
|
||||
def __getitem__(self, index: int) -> T: ...
|
||||
@overload
|
||||
def __getitem__(self, index: slice) -> Sequence[T]: ...
|
||||
def __getitem__(self, index: int | slice) -> T | Sequence[T]: ...
|
||||
|
||||
|
||||
vco2_1: ShouldBeCovariant2[float] = ShouldBeCovariant2[int]()
|
||||
# This should generate an error based on variance.
|
||||
vco2_2: ShouldBeCovariant2[int] = ShouldBeCovariant2[float]()
|
||||
|
||||
|
||||
class ShouldBeCovariant3[T]:
|
||||
def method1(self) -> "ShouldBeCovariant2[T]": ...
|
||||
|
||||
|
||||
vco3_1: ShouldBeCovariant3[float] = ShouldBeCovariant3[int]()
|
||||
# This should generate an error based on variance.
|
||||
vco3_2: ShouldBeCovariant3[int] = ShouldBeCovariant3[float]()
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class ShouldBeCovariant4[T]:
|
||||
x: T
|
||||
|
||||
|
||||
vo4_1: ShouldBeCovariant4[float] = ShouldBeCovariant4[int](1)
|
||||
# This should generate an error based on variance.
|
||||
vo4_2: ShouldBeCovariant4[int] = ShouldBeCovariant4[float](1)
|
||||
|
||||
|
||||
class ShouldBeCovariant5[T]:
|
||||
def __init__(self, x: T) -> None:
|
||||
self._x = x
|
||||
|
||||
@property
|
||||
def x(self) -> T:
|
||||
return self._x
|
||||
|
||||
|
||||
vo5_1: ShouldBeCovariant5[float] = ShouldBeCovariant5[int](1)
|
||||
# This should generate an error based on variance.
|
||||
vo5_2: ShouldBeCovariant5[int] = ShouldBeCovariant5[float](1)
|
||||
|
||||
|
||||
class ShouldBeCovariant6[T]:
|
||||
def f1[T2: int](self: "ShouldBeCovariant6[T2]") -> T2: ...
|
||||
|
||||
@property
|
||||
def f2[T2: int](self: "ShouldBeCovariant6[T2]") -> T2: ...
|
||||
|
||||
|
||||
# This should generate an error based on variance.
|
||||
vo6_1: ShouldBeCovariant6[int] = ShouldBeCovariant6[float]()
|
||||
|
||||
vo6_2: ShouldBeCovariant6[float] = ShouldBeCovariant6[int]()
|
||||
|
||||
|
||||
class ShouldBeInvariant1[T]:
|
||||
def __init__(self, value: T) -> None:
|
||||
self._value = value
|
||||
|
||||
@property
|
||||
def value(self):
|
||||
return self._value
|
||||
|
||||
@value.setter
|
||||
def value(self, value: T):
|
||||
self._value = value
|
||||
|
||||
|
||||
# This should generate an error based on variance.
|
||||
vinv1_1: ShouldBeInvariant1[float] = ShouldBeInvariant1[int](1)
|
||||
|
||||
# This should generate an error based on variance.
|
||||
vinv1_2: ShouldBeInvariant1[int] = ShouldBeInvariant1[float](1.1)
|
||||
|
||||
|
||||
class ShouldBeInvariant2[T]:
|
||||
def __init__(self, value: T) -> None:
|
||||
self._value = value
|
||||
|
||||
def get_value(self) -> T:
|
||||
return self._value
|
||||
|
||||
def set_value(self, value: T):
|
||||
self._value = value
|
||||
|
||||
|
||||
# This should generate an error based on variance.
|
||||
vinv2_1: ShouldBeInvariant2[float] = ShouldBeInvariant2[int](1)
|
||||
|
||||
# This should generate an error based on variance
|
||||
vinv2_2: ShouldBeInvariant2[int] = ShouldBeInvariant2[float](1.1)
|
||||
|
||||
|
||||
class ShouldBeInvariant3[K, V](dict[K, V]):
|
||||
pass
|
||||
|
||||
|
||||
# This should generate an error based on variance.
|
||||
vinv3_1: ShouldBeInvariant3[float, str] = ShouldBeInvariant3[int, str]()
|
||||
|
||||
# This should generate an error based on variance.
|
||||
vinv3_2: ShouldBeInvariant3[int, str] = ShouldBeInvariant3[float, str]()
|
||||
|
||||
# This should generate an error based on variance.
|
||||
vinv3_3: ShouldBeInvariant3[str, float] = ShouldBeInvariant3[str, int]()
|
||||
|
||||
# This should generate an error based on variance.
|
||||
vinv3_4: ShouldBeInvariant3[str, int] = ShouldBeInvariant3[str, float]()
|
||||
|
||||
|
||||
@dataclass
|
||||
class ShouldBeInvariant4[T]:
|
||||
x: T
|
||||
|
||||
|
||||
# This should generate an error based on variance
|
||||
vinv4_1: ShouldBeInvariant4[float] = ShouldBeInvariant4[int](1)
|
||||
|
||||
|
||||
class ShouldBeInvariant5[T]:
|
||||
def __init__(self, x: T) -> None:
|
||||
self.x = x
|
||||
|
||||
|
||||
# This should generate an error based on variance.
|
||||
vinv5_1: ShouldBeInvariant5[float] = ShouldBeInvariant5[int](1)
|
||||
|
||||
|
||||
class ShouldBeContravariant1[T]:
|
||||
def __init__(self, value: T) -> None:
|
||||
pass
|
||||
|
||||
def set_value(self, value: T) -> None:
|
||||
pass
|
||||
|
||||
|
||||
# This should generate an error based on variance.
|
||||
vcontra1_1: ShouldBeContravariant1[float] = ShouldBeContravariant1[int](1)
|
||||
|
||||
vcontra1_2: ShouldBeContravariant1[int] = ShouldBeContravariant1[float](1.2)
|
||||
@@ -1,30 +0,0 @@
|
||||
# This sample tests an auto-invariance case that involves recursive types.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Callable
|
||||
from dataclasses import dataclass
|
||||
from typing import Concatenate, Protocol
|
||||
|
||||
|
||||
@dataclass
|
||||
class Node[T]:
|
||||
left: Node[T]
|
||||
right: Node[T]
|
||||
value: T
|
||||
|
||||
|
||||
class MyPartial[**P, R]:
|
||||
def __init__(self, first: int, func: Callable[Concatenate[int, P], R]) -> None:
|
||||
self.first = first
|
||||
self.func = func
|
||||
|
||||
def __call__(self, *args: P.args, **kwargs: P.kwargs) -> R: ...
|
||||
|
||||
|
||||
class CallbackKeyed[*Ts](Protocol):
|
||||
def __call__(self, *args: *Ts, keyed: bool) -> tuple[*Ts]: ...
|
||||
|
||||
|
||||
def invoke_keyed[*Ts](fn: CallbackKeyed[*Ts], *args: *Ts) -> tuple[*Ts]:
|
||||
return fn(*args, keyed=True)
|
||||
@@ -1,163 +0,0 @@
|
||||
# This sample tests variance inference for traditional type variables.
|
||||
|
||||
from typing import Generic, Iterator, Sequence, overload
|
||||
from typing_extensions import TypeVar # viper: ignore[reportMissingModuleSource]
|
||||
from dataclasses import dataclass
|
||||
|
||||
T = TypeVar("T", infer_variance=True)
|
||||
K = TypeVar("K", infer_variance=True)
|
||||
V = TypeVar("V", infer_variance=True)
|
||||
|
||||
# This should generate an error because covariant cannot be used
|
||||
# with infer_variance.
|
||||
S1 = TypeVar("S1", covariant=True, infer_variance=True)
|
||||
|
||||
# This should generate an error because contravariant cannot be used
|
||||
# with infer_variance.
|
||||
S2 = TypeVar("S2", contravariant=True, infer_variance=True)
|
||||
|
||||
|
||||
class ShouldBeCovariant1(Generic[T]):
|
||||
def __getitem__(self, index: int) -> T: ...
|
||||
|
||||
def __iter__(self) -> Iterator[T]: ...
|
||||
|
||||
|
||||
vco1_1: ShouldBeCovariant1[float] = ShouldBeCovariant1[int]()
|
||||
|
||||
# This should generate an error based on variance.
|
||||
vco1_2: ShouldBeCovariant1[int] = ShouldBeCovariant1[float]()
|
||||
|
||||
|
||||
class ShouldBeCovariant2(Sequence[T]):
|
||||
def __len__(self) -> int: ...
|
||||
@overload
|
||||
def __getitem__(self, index: int) -> T: ...
|
||||
@overload
|
||||
def __getitem__(self, index: slice) -> Sequence[T]: ...
|
||||
def __getitem__(self, index: int | slice) -> T | Sequence[T]: ...
|
||||
|
||||
|
||||
vco2_1: ShouldBeCovariant2[float] = ShouldBeCovariant2[int]()
|
||||
# This should generate an error based on variance.
|
||||
vco2_2: ShouldBeCovariant2[int] = ShouldBeCovariant2[float]()
|
||||
|
||||
|
||||
class ShouldBeCovariant3(Generic[T]):
|
||||
def method1(self) -> "ShouldBeCovariant2[T]": ...
|
||||
|
||||
|
||||
vco3_1: ShouldBeCovariant3[float] = ShouldBeCovariant3[int]()
|
||||
# This should generate an error based on variance.
|
||||
vco3_2: ShouldBeCovariant3[int] = ShouldBeCovariant3[float]()
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class ShouldBeCovariant4(Generic[T]):
|
||||
x: T
|
||||
|
||||
|
||||
vo4_1: ShouldBeCovariant4[float] = ShouldBeCovariant4[int](1)
|
||||
# This should generate an error based on variance.
|
||||
vo4_4: ShouldBeCovariant4[int] = ShouldBeCovariant4[float](1.0)
|
||||
|
||||
|
||||
class ShouldBeCovariant5(Generic[T]):
|
||||
def __init__(self, x: T) -> None:
|
||||
self._x = x
|
||||
|
||||
@property
|
||||
def x(self) -> T:
|
||||
return self._x
|
||||
|
||||
|
||||
vo5_1: ShouldBeCovariant5[float] = ShouldBeCovariant5[int](1)
|
||||
# This should generate an error based on variance.
|
||||
vo5_2: ShouldBeCovariant5[int] = ShouldBeCovariant5[float](1.0)
|
||||
|
||||
|
||||
class ShouldBeInvariant1(Generic[T]):
|
||||
def __init__(self, value: T) -> None:
|
||||
self._value = value
|
||||
|
||||
@property
|
||||
def value(self):
|
||||
return self._value
|
||||
|
||||
@value.setter
|
||||
def value(self, value: T):
|
||||
self._value = value
|
||||
|
||||
|
||||
# This should generate an error based on variance.
|
||||
vinv1_1: ShouldBeInvariant1[float] = ShouldBeInvariant1[int](1)
|
||||
|
||||
# This should generate an error based on variance.
|
||||
vinv1_2: ShouldBeInvariant1[int] = ShouldBeInvariant1[float](1.1)
|
||||
|
||||
|
||||
class ShouldBeInvariant2(Generic[T]):
|
||||
def __init__(self, value: T) -> None:
|
||||
self._value = value
|
||||
|
||||
def get_value(self) -> T:
|
||||
return self._value
|
||||
|
||||
def set_value(self, value: T):
|
||||
self._value = value
|
||||
|
||||
|
||||
# This should generate an error based on variance.
|
||||
vinv2_1: ShouldBeInvariant2[float] = ShouldBeInvariant2[int](1)
|
||||
|
||||
# This should generate an error based on variance.
|
||||
vinv2_2: ShouldBeInvariant2[int] = ShouldBeInvariant2[float](1.1)
|
||||
|
||||
|
||||
class ShouldBeInvariant3(dict[K, V]):
|
||||
pass
|
||||
|
||||
|
||||
# This should generate an error based on variance.
|
||||
vinv3_1: ShouldBeInvariant3[float, str] = ShouldBeInvariant3[int, str]()
|
||||
|
||||
# This should generate an error based on variance.
|
||||
vinv3_2: ShouldBeInvariant3[int, str] = ShouldBeInvariant3[float, str]()
|
||||
|
||||
# This should generate an error based on variance.
|
||||
vinv3_3: ShouldBeInvariant3[str, float] = ShouldBeInvariant3[str, int]()
|
||||
|
||||
# This should generate an error based on variance.
|
||||
vinv3_4: ShouldBeInvariant3[str, int] = ShouldBeInvariant3[str, float]()
|
||||
|
||||
|
||||
@dataclass
|
||||
class ShouldBeInvariant4[T]:
|
||||
x: T
|
||||
|
||||
|
||||
# This should generate an error based on variance.
|
||||
vinv4_1: ShouldBeInvariant4[float] = ShouldBeInvariant4[int](1)
|
||||
|
||||
|
||||
class ShouldBeInvariant5[T]:
|
||||
def __init__(self, x: T) -> None:
|
||||
self.x = x
|
||||
|
||||
|
||||
# This should generate an error based on variance.
|
||||
vinv5_1: ShouldBeInvariant5[float] = ShouldBeInvariant5[int](1)
|
||||
|
||||
|
||||
class ShouldBeContravariant1(Generic[T]):
|
||||
def __init__(self, value: T) -> None:
|
||||
pass
|
||||
|
||||
def set_value(self, value: T):
|
||||
pass
|
||||
|
||||
|
||||
# This should generate an error based on variance.
|
||||
vcontra1_1: ShouldBeContravariant1[float] = ShouldBeContravariant1[int](1)
|
||||
|
||||
vcontra1_2: ShouldBeContravariant1[int] = ShouldBeContravariant1[float](1.2)
|
||||
@@ -1,51 +0,0 @@
|
||||
# This sample tests the case where a class uses auto-variance but derives
|
||||
# from a class that does not.
|
||||
|
||||
from typing import Generic, TypeVar
|
||||
|
||||
T = TypeVar("T")
|
||||
T_co = TypeVar("T_co", covariant=True)
|
||||
T_contra = TypeVar("T_contra", contravariant=True)
|
||||
|
||||
|
||||
class Parent_Invariant(Generic[T]):
|
||||
pass
|
||||
|
||||
|
||||
class ShouldBeInvariant[T](Parent_Invariant[T]):
|
||||
pass
|
||||
|
||||
|
||||
# This should generate an error.
|
||||
a1: ShouldBeInvariant[int] = ShouldBeInvariant[float]()
|
||||
|
||||
# This should generate an error.
|
||||
a2: ShouldBeInvariant[float] = ShouldBeInvariant[int]()
|
||||
|
||||
|
||||
class Parent_Covariant(Generic[T_co]):
|
||||
pass
|
||||
|
||||
|
||||
class ShouldBeCovariant[T](Parent_Covariant[T]):
|
||||
pass
|
||||
|
||||
|
||||
# This should generate an error.
|
||||
b1: ShouldBeCovariant[int] = ShouldBeCovariant[float]()
|
||||
|
||||
b2: ShouldBeCovariant[float] = ShouldBeCovariant[int]()
|
||||
|
||||
|
||||
class Parent_Contravariant(Generic[T_contra]):
|
||||
pass
|
||||
|
||||
|
||||
class ShouldBeContravariant[T](Parent_Contravariant[T]):
|
||||
pass
|
||||
|
||||
|
||||
c1: ShouldBeContravariant[int] = ShouldBeContravariant[float]()
|
||||
|
||||
# This should generate an error.
|
||||
c2: ShouldBeContravariant[float] = ShouldBeContravariant[int]()
|
||||
@@ -1,20 +0,0 @@
|
||||
# This sample tests a case that involves an interaction between a class
|
||||
# that uses auto-variance and a decorator that uses a generic type alias.
|
||||
|
||||
from typing import Any, Concatenate, Generic, ParamSpec, TypeAlias, Callable
|
||||
from typing_extensions import TypeVar # viper: ignore[reportMissingModuleSource]
|
||||
|
||||
T = TypeVar("T", infer_variance=True)
|
||||
P = ParamSpec("P")
|
||||
R = TypeVar("R")
|
||||
S = TypeVar("S", bound="A[Any]")
|
||||
|
||||
TA1: TypeAlias = Callable[Concatenate[S, P], R]
|
||||
|
||||
|
||||
def deco(func: TA1[S, P, R], /) -> TA1[S, P, R]: ...
|
||||
|
||||
|
||||
class A(Generic[T]):
|
||||
@deco
|
||||
def select_all(self, *args: object) -> list[Any]: ...
|
||||
@@ -1,57 +0,0 @@
|
||||
# This sample validates that the await keyword participates in
|
||||
# bidirectional type inference.
|
||||
|
||||
from typing import (
|
||||
Any,
|
||||
AsyncIterator,
|
||||
Callable,
|
||||
Iterable,
|
||||
Literal,
|
||||
TypeVar,
|
||||
Generic,
|
||||
overload,
|
||||
)
|
||||
|
||||
T = TypeVar("T")
|
||||
AnyMsg = TypeVar("AnyMsg", bound="Msg")
|
||||
|
||||
|
||||
class Msg(Generic[T]):
|
||||
body: T
|
||||
|
||||
|
||||
class Request:
|
||||
id: int
|
||||
|
||||
|
||||
async def func1(check: "Callable[[AnyMsg], bool]") -> AnyMsg: ...
|
||||
|
||||
|
||||
async def func2():
|
||||
_: Msg[Request] = await func1(check=lambda msg: (msg.body.id == 12345))
|
||||
|
||||
|
||||
async def func3() -> AsyncIterator[int]:
|
||||
yield 1
|
||||
|
||||
|
||||
async def func4() -> int:
|
||||
return await anext(func3())
|
||||
|
||||
|
||||
async def func5(__fn: Callable[..., T]) -> T: ...
|
||||
|
||||
|
||||
@overload
|
||||
def sum(__iterable: Iterable[Literal[0]]) -> int: ...
|
||||
|
||||
|
||||
@overload
|
||||
def sum(__iterable: Iterable[T]) -> T: ...
|
||||
|
||||
|
||||
def sum(__iterable: Iterable[Any]) -> Any: ...
|
||||
|
||||
|
||||
async def func6(f: Callable[[], list[int]]):
|
||||
sum(await func5(f))
|
||||
@@ -1,31 +0,0 @@
|
||||
# This sample tests that types defined by type variables can be
|
||||
# awaited.
|
||||
|
||||
from typing import Generator, Any, NoReturn
|
||||
|
||||
|
||||
class MyAwaitable:
|
||||
def __await__(self) -> Generator[Any, None, int]:
|
||||
async def foo() -> int:
|
||||
return 1
|
||||
|
||||
return foo().__await__()
|
||||
|
||||
async def foo(self) -> int:
|
||||
return await self
|
||||
|
||||
|
||||
async def func1() -> None:
|
||||
p = MyAwaitable()
|
||||
print(await p.foo())
|
||||
print(await p)
|
||||
|
||||
|
||||
async def func2() -> NoReturn:
|
||||
raise Exception()
|
||||
|
||||
|
||||
async def func3(x: int | None):
|
||||
if x is None:
|
||||
await func2()
|
||||
print(x.bit_count())
|
||||
@@ -1,37 +0,0 @@
|
||||
# This sample tests various places where await is invalid.
|
||||
|
||||
from typing import Any
|
||||
|
||||
|
||||
def func1() -> Any: ...
|
||||
|
||||
|
||||
def func2():
|
||||
# These are OK because generators can be called
|
||||
# outside of the context of the current function.
|
||||
(v async for v in func1())
|
||||
(await v for v in func1())
|
||||
|
||||
# This should generate an error because async
|
||||
# cannot be used outside of an async function.
|
||||
[x async for x in func1()]
|
||||
|
||||
# This should generate an error because async
|
||||
# cannot be used outside of an async function.
|
||||
{x async for x in func1()}
|
||||
|
||||
# This should generate an error because async
|
||||
# cannot be used outside of an async function.
|
||||
{k: v async for k, v in func1()}
|
||||
|
||||
# This should generate an error because await
|
||||
# cannot be used outside of an async function.
|
||||
(x for x in await func1())
|
||||
|
||||
# This should generate an error because await
|
||||
# cannot be used outside of an async function.
|
||||
[await x for x in func1()]
|
||||
|
||||
# This should generate an error because await
|
||||
# cannot be used outside of an async function.
|
||||
{await k: v for k, v in func1()}
|
||||
@@ -1,2 +0,0 @@
|
||||
# This file is intentionally blank. It's used to test
|
||||
# the implicitly-imported builtins module and its symbols.
|
||||
@@ -1,7 +0,0 @@
|
||||
# This sample tests that builtins can be overridden at the module level
|
||||
# without generating a "possibly unbound" error.
|
||||
|
||||
if input():
|
||||
print = lambda *x: None
|
||||
|
||||
print("")
|
||||
@@ -1,93 +0,0 @@
|
||||
# This sample tests various function type checking
|
||||
# behavior including arg/param matching.
|
||||
|
||||
from typing import Callable
|
||||
|
||||
# ------------------------------------------------------
|
||||
# Test function type matching
|
||||
|
||||
|
||||
class FooBase:
|
||||
pass
|
||||
|
||||
|
||||
class Foo(FooBase):
|
||||
pass
|
||||
|
||||
|
||||
class Bar(Foo):
|
||||
pass
|
||||
|
||||
|
||||
def needs_function1(callback: Callable[[Foo], Foo]):
|
||||
pass
|
||||
|
||||
|
||||
def callback1():
|
||||
pass
|
||||
|
||||
|
||||
def callback2(a: Foo) -> Foo:
|
||||
return Foo()
|
||||
|
||||
|
||||
def callback3(a: Foo) -> str:
|
||||
return "1"
|
||||
|
||||
|
||||
def callback4(a: Foo, b: Foo) -> Foo:
|
||||
return Foo()
|
||||
|
||||
|
||||
def callback5(a: Foo, b: int = 3) -> Foo:
|
||||
return Foo()
|
||||
|
||||
|
||||
def callback6(*a) -> Foo:
|
||||
return Foo()
|
||||
|
||||
|
||||
def callback7(a: str) -> Foo:
|
||||
return Foo()
|
||||
|
||||
|
||||
def callback8(a: Bar) -> Foo:
|
||||
return Foo()
|
||||
|
||||
|
||||
def callback9(a: FooBase) -> Foo:
|
||||
return Foo()
|
||||
|
||||
|
||||
# This should generate an error because callback1
|
||||
# takes no parameters.
|
||||
needs_function1(callback1)
|
||||
|
||||
needs_function1(callback2)
|
||||
|
||||
# This should generate an error because the return
|
||||
# type of callback3 doesn't match.
|
||||
needs_function1(callback3)
|
||||
|
||||
# This should generate an error because callback4
|
||||
# takes too many parameters.
|
||||
needs_function1(callback4)
|
||||
|
||||
needs_function1(callback5)
|
||||
needs_function1(callback6)
|
||||
|
||||
# This should fail because the parameter is the
|
||||
# wrong type.
|
||||
needs_function1(callback7)
|
||||
|
||||
# This should fail because the parameter is the
|
||||
# wrong type.
|
||||
needs_function1(callback8)
|
||||
|
||||
needs_function1(callback9)
|
||||
|
||||
|
||||
import typing
|
||||
|
||||
# This should generate an error because modules are not callable.
|
||||
typing()
|
||||
@@ -1,75 +0,0 @@
|
||||
# This sample tests that the type checker properly handles
|
||||
# types of args and kwargs correctly.
|
||||
|
||||
from typing import Any, Hashable, Mapping, Protocol
|
||||
|
||||
|
||||
def requires_hashable_tuple(p1: tuple[Hashable, ...]): ...
|
||||
|
||||
|
||||
def requires_hashable_dict(p1: dict[str, Hashable]): ...
|
||||
|
||||
|
||||
def test_args(*args: Hashable):
|
||||
if args:
|
||||
aaa = list(args)
|
||||
bbb = tuple(aaa)
|
||||
args = bbb
|
||||
requires_hashable_tuple(args)
|
||||
|
||||
|
||||
def test_kwargs(**kwargs: Hashable):
|
||||
requires_hashable_dict(kwargs)
|
||||
|
||||
|
||||
class StrSubclass(str): ...
|
||||
|
||||
|
||||
def test_kwargs2(
|
||||
a: Mapping[str, Any],
|
||||
b: Mapping[Any, Hashable],
|
||||
c: dict[StrSubclass, Hashable],
|
||||
d: int,
|
||||
e: Mapping[int, Hashable],
|
||||
f: tuple[str, ...],
|
||||
):
|
||||
test_kwargs(**a)
|
||||
test_kwargs(**b)
|
||||
test_kwargs(**c)
|
||||
|
||||
# This should generate an error
|
||||
test_kwargs(**d)
|
||||
|
||||
# This should generate an error
|
||||
test_kwargs(**e)
|
||||
|
||||
# This should generate an error
|
||||
test_kwargs(**f)
|
||||
|
||||
|
||||
class Callback1(Protocol):
|
||||
def __call__(self) -> None: ...
|
||||
|
||||
|
||||
def func1(
|
||||
value: str = ...,
|
||||
*args: object,
|
||||
) -> None: ...
|
||||
|
||||
|
||||
def func2(
|
||||
value: str = ...,
|
||||
**kwargs: object,
|
||||
) -> None: ...
|
||||
|
||||
|
||||
def func3(
|
||||
value: str = ...,
|
||||
*args: object,
|
||||
**kwargs: object,
|
||||
) -> None: ...
|
||||
|
||||
|
||||
v1: Callback1 = func1
|
||||
v2: Callback1 = func2
|
||||
v3: Callback1 = func3
|
||||
@@ -1,44 +0,0 @@
|
||||
# This sample tests the case where a call expression involves a union
|
||||
# on the LHS where the subtypes of the union have different signatures.
|
||||
|
||||
# viper: strict
|
||||
|
||||
from __future__ import annotations
|
||||
from typing import Any, Callable, Generic, Self, TypeAlias, TypeVar
|
||||
|
||||
T = TypeVar("T")
|
||||
E = TypeVar("E")
|
||||
U = TypeVar("U")
|
||||
F = TypeVar("F")
|
||||
|
||||
Either: TypeAlias = "Left[T]" | "Right[E]"
|
||||
|
||||
|
||||
class Left(Generic[T]):
|
||||
def __init__(self, value: T) -> None:
|
||||
self.value = value
|
||||
|
||||
def map_left(self, fn: Callable[[T], U]) -> Left[U]:
|
||||
return Left(fn(self.value))
|
||||
|
||||
def map_right(self, fn: Callable[[Any], Any]) -> Self:
|
||||
return self
|
||||
|
||||
|
||||
class Right(Generic[E]):
|
||||
def __init__(self, value: E) -> None:
|
||||
self.value = value
|
||||
|
||||
def map_left(self, fn: Callable[[Any], Any]) -> Self:
|
||||
return self
|
||||
|
||||
def map_right(self, fn: Callable[[E], F]) -> Right[F]:
|
||||
return Right(fn(self.value))
|
||||
|
||||
|
||||
def func() -> Either[int, str]:
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
result = func().map_left(lambda lv: lv + 1).map_right(lambda rv: rv + "a")
|
||||
reveal_type(result, expected_text="Right[str] | Left[int]")
|
||||
@@ -1,47 +0,0 @@
|
||||
# This sample tests that positional arg expressions are evaluated prior
|
||||
# to keyword arg expressions even if they don't appear in that order
|
||||
# within the arg list.
|
||||
|
||||
|
||||
from typing import TypedDict
|
||||
|
||||
|
||||
def func1(a: int | None = None, b: int | None = None, c: int | None = None) -> None:
|
||||
pass
|
||||
|
||||
|
||||
func1((v1 := 1), b=v1 + 1)
|
||||
|
||||
# This should generate an error.
|
||||
func1(b=(v2 := 1), *[v2 + 1])
|
||||
|
||||
func1(b=v3 + 1, *[(v3 := 1)])
|
||||
|
||||
|
||||
class A(TypedDict):
|
||||
a: int
|
||||
|
||||
|
||||
class B(TypedDict):
|
||||
b: int
|
||||
|
||||
|
||||
class C(TypedDict):
|
||||
c: int
|
||||
|
||||
|
||||
func1(a=(v4 := 1), **B(b=(v4 + 1)))
|
||||
|
||||
# This should generate an error.
|
||||
func1(**A(a=(v5 + 1)), b=(v5 := 1))
|
||||
|
||||
func1(**A(a=(v5 := 1)), b=(v5 + 1))
|
||||
|
||||
func1(b=(v6 + 1), *[(v6 := 1)], **C(c=(v6 + 2)))
|
||||
|
||||
|
||||
def func2(a: int, b: int):
|
||||
pass
|
||||
|
||||
|
||||
func2(b=1, *(2,))
|
||||
@@ -1,15 +0,0 @@
|
||||
# This sample tests the case where a call invokes a generic function that
|
||||
# uses a default argument assigned to a parameter whose type is generic.
|
||||
|
||||
from typing import TypeVar, Iterable, Callable
|
||||
|
||||
T1 = TypeVar("T1")
|
||||
T2 = TypeVar("T2")
|
||||
|
||||
|
||||
def func1(values: Iterable[T1], func: Callable[[T1], T2] = lambda x: x) -> list[T2]:
|
||||
return [func(value) for value in values]
|
||||
|
||||
|
||||
v1 = func1([1, 2, 3])
|
||||
reveal_type(v1, expected_text="list[int]")
|
||||
@@ -1,57 +0,0 @@
|
||||
# This sample tests the pre-3.8 position-only parameter convention.
|
||||
|
||||
|
||||
from typing import Any
|
||||
|
||||
|
||||
def func1(__a: int, __b: int, c: int) -> None: ...
|
||||
|
||||
|
||||
func1(1, 2, c=3)
|
||||
|
||||
# This should generate an error because __b is position-only.
|
||||
func1(1, __b=2, c=3)
|
||||
|
||||
|
||||
# This should generate an error because a position-only parameter cannot
|
||||
# follow a non-position-only parameter.
|
||||
def func2(a: int, __b: int) -> None: ...
|
||||
|
||||
|
||||
def func3(a: int, *args: Any, __b: int) -> None: ...
|
||||
|
||||
|
||||
func3(a=1, __b=2)
|
||||
|
||||
|
||||
def func4(a: int, /, __b: int) -> None: ...
|
||||
|
||||
|
||||
func4(1, __b=2)
|
||||
|
||||
|
||||
class A:
|
||||
def m1(self, __a: int, b: int) -> None:
|
||||
pass
|
||||
|
||||
# This should generate an error.
|
||||
def m2(self, a: int, __b: int) -> None:
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def c1(cls, __a, int, b: int) -> None:
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
# This should generate an error.
|
||||
def c2(cls, a, int, __b: int) -> None:
|
||||
pass
|
||||
|
||||
@staticmethod
|
||||
def s1(__a: int, b: int) -> None:
|
||||
pass
|
||||
|
||||
@staticmethod
|
||||
# This should generate an error.
|
||||
def s2(a: int, __b: int) -> None:
|
||||
pass
|
||||
@@ -1,66 +0,0 @@
|
||||
# This sample tests the case where a generic function has a default argument
|
||||
# value for a parameter with a generic type.
|
||||
|
||||
from collections.abc import Callable
|
||||
from typing import Iterable, TypeVar
|
||||
|
||||
T = TypeVar("T")
|
||||
|
||||
default_value: dict[str, int] = {}
|
||||
|
||||
|
||||
def func1(x: T, y: dict[str, T] = default_value, /) -> T: ...
|
||||
|
||||
|
||||
def func2(x: T, y: dict[str, T] = default_value) -> T: ...
|
||||
|
||||
|
||||
def func3(x: T, *, y: dict[str, T] = default_value) -> T: ...
|
||||
|
||||
|
||||
def test1(func: Callable[[T], T], value: T) -> T:
|
||||
return func(value)
|
||||
|
||||
|
||||
# This should generate an error.
|
||||
test1(func1, "")
|
||||
|
||||
# This should generate an error.
|
||||
test1(func2, "")
|
||||
|
||||
# This should generate an error.
|
||||
test1(func3, "")
|
||||
|
||||
reveal_type(test1(func1, 1), expected_text="int")
|
||||
reveal_type(test1(func2, 1), expected_text="int")
|
||||
reveal_type(test1(func3, 1), expected_text="int")
|
||||
|
||||
|
||||
def func4(x: T, y: Iterable[T] = default_value, z: T = "", /) -> T: ...
|
||||
|
||||
|
||||
def func5(x: T, y: Iterable[T] = default_value, z: T = "") -> T: ...
|
||||
|
||||
|
||||
def func6(x: T, *, y: Iterable[T] = default_value, z: T = "") -> T: ...
|
||||
|
||||
|
||||
reveal_type(test1(func4, 1), expected_text="str | int")
|
||||
reveal_type(test1(func5, 1), expected_text="str | int")
|
||||
reveal_type(test1(func6, 1), expected_text="str | int")
|
||||
|
||||
|
||||
class A[T]:
|
||||
def __init__(self, value: T) -> None:
|
||||
self._value: T = value
|
||||
|
||||
def update(self, value: T = 0, /) -> "A[T]":
|
||||
return A(value)
|
||||
|
||||
|
||||
a = A("")
|
||||
|
||||
a.update("")
|
||||
|
||||
# This should generate an error.
|
||||
a.update()
|
||||
@@ -1,38 +0,0 @@
|
||||
# This sample tests bidirectional type inference for calls where the expected
|
||||
# type is a union.
|
||||
|
||||
from typing import Any, AnyStr, Iterable, Literal, TypeVar, overload
|
||||
|
||||
T = TypeVar("T")
|
||||
|
||||
|
||||
class ItemBase: ...
|
||||
|
||||
|
||||
class Item(ItemBase): ...
|
||||
|
||||
|
||||
def gen_items() -> Iterable[Item]:
|
||||
return []
|
||||
|
||||
|
||||
def make_list(val: Iterable[T]) -> list[T]:
|
||||
return list(val)
|
||||
|
||||
|
||||
x: ItemBase | list[ItemBase | None] = make_list(gen_items())
|
||||
|
||||
|
||||
@overload
|
||||
def urlunsplit(components: Iterable[None]) -> Literal[b""]: ...
|
||||
|
||||
|
||||
@overload
|
||||
def urlunsplit(components: Iterable[AnyStr | None]) -> AnyStr: ...
|
||||
|
||||
|
||||
def urlunsplit(components: Iterable[Any]) -> Any: ...
|
||||
|
||||
|
||||
def func(url: str, candidates: list[Any]) -> str | None:
|
||||
return urlunsplit(candidates[0])
|
||||
@@ -1,32 +0,0 @@
|
||||
# This sample tests a case of bidirectional type inference for calls
|
||||
# that involves a union in the expected type.
|
||||
|
||||
# viper: strict
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Callable
|
||||
from typing import Generic, TypeVar
|
||||
|
||||
T_co = TypeVar("T_co", covariant=True)
|
||||
E_co = TypeVar("E_co", covariant=True)
|
||||
F = TypeVar("F")
|
||||
|
||||
|
||||
class Ok(Generic[T_co]):
|
||||
def or_else(self, op: object) -> Ok[T_co]: ...
|
||||
|
||||
|
||||
class Err(Generic[E_co]):
|
||||
def or_else(self, op: Callable[[E_co], Result[T_co, F]]) -> Result[T_co, F]: ...
|
||||
|
||||
|
||||
Result = Ok[T_co] | Err[E_co]
|
||||
|
||||
|
||||
def inner(func: Callable[[E_co], Err[F]], r: Result[T_co, E_co]) -> Result[T_co, F]:
|
||||
match r:
|
||||
case Ok():
|
||||
return r.or_else(func)
|
||||
case Err():
|
||||
return r.or_else(func)
|
||||
@@ -1,183 +0,0 @@
|
||||
# This sample tests function parameter matching logic.
|
||||
|
||||
|
||||
from typing import Any, Callable, Literal
|
||||
|
||||
|
||||
def func1(a: int, *b: int):
|
||||
pass
|
||||
|
||||
|
||||
func1(3)
|
||||
func1(3, 4)
|
||||
func1(3, *[1, 2, 3])
|
||||
|
||||
# This should generate an error
|
||||
func1(3, "hello")
|
||||
|
||||
# This should generate an error
|
||||
func1(3, 5, 2, "str")
|
||||
|
||||
# This should generate an error
|
||||
func1("hello", 3)
|
||||
|
||||
str_list = ["he", "2", "3"]
|
||||
|
||||
# This should generate an error
|
||||
func1(3, *str_list)
|
||||
|
||||
|
||||
def func2(a: str, **b: int):
|
||||
pass
|
||||
|
||||
|
||||
func2("hi")
|
||||
func2("hi", b=3, c=4, d=5)
|
||||
|
||||
str_dict = {"a": "3", "b": "2"}
|
||||
|
||||
# This should generate a type error
|
||||
func2("hi", **str_dict)
|
||||
|
||||
|
||||
# This should generate a type error
|
||||
func2("hi", 3)
|
||||
|
||||
# This should generate a type error
|
||||
func2("hi", b="hi")
|
||||
|
||||
|
||||
def func4(*args: int):
|
||||
pass
|
||||
|
||||
|
||||
def func5(a: int, *args):
|
||||
pass
|
||||
|
||||
|
||||
tuple1 = (2, 3)
|
||||
func4(*tuple1)
|
||||
func5(*tuple1)
|
||||
|
||||
# This should generate an error because a is assigned twice.
|
||||
func2(a="", a="")
|
||||
|
||||
# This should generate an error because c is assigned twice.
|
||||
func2("", c=4, d=5, c=5)
|
||||
|
||||
|
||||
def func6(param1: int, param2: str):
|
||||
pass
|
||||
|
||||
|
||||
def func7(*args: Any, param0: int, param1: int, param2: str):
|
||||
func6(*args, param1=param1, param2=param2)
|
||||
|
||||
func6(param0, param2=param2)
|
||||
|
||||
# This should generate two errors because param0 has no match
|
||||
# and param2 is missing.
|
||||
func6(param0, param1=param1)
|
||||
|
||||
|
||||
def func8(
|
||||
y: str,
|
||||
z: bool = ...,
|
||||
) -> None: ...
|
||||
|
||||
|
||||
kwargs1: dict[str, int] = {}
|
||||
# This should generate an error because int is not compatible with str.
|
||||
func8(z=False, **kwargs1)
|
||||
|
||||
|
||||
class MyStr(str): ...
|
||||
|
||||
|
||||
kwargs2: dict[MyStr, MyStr] = {}
|
||||
func8(z=False, **kwargs2)
|
||||
|
||||
|
||||
def func9(
|
||||
x: int,
|
||||
y: str,
|
||||
*,
|
||||
a: str = ...,
|
||||
b: str,
|
||||
c: str,
|
||||
) -> None: ...
|
||||
|
||||
|
||||
kwargs3: dict[str, str] = {}
|
||||
func9(0, "", **kwargs3)
|
||||
|
||||
args4: list[str] = ["hi"]
|
||||
func9(0, *args4, **kwargs3)
|
||||
|
||||
# This should generate an error.
|
||||
func9(*args4, **kwargs3)
|
||||
|
||||
|
||||
def func10(x: int): ...
|
||||
|
||||
|
||||
func10(1, *())
|
||||
|
||||
# This should generate an error.
|
||||
func10(1, *(1,))
|
||||
|
||||
func10(*(1,))
|
||||
|
||||
# This should generate an error.
|
||||
func10(*(1, 1))
|
||||
|
||||
# This should generate an error.
|
||||
func10(*("",))
|
||||
|
||||
|
||||
def func11(y: tuple[int, ...]):
|
||||
func10(1, *y)
|
||||
|
||||
|
||||
def func12(x: int, /, y: str):
|
||||
pass
|
||||
|
||||
|
||||
# This should generate an error.
|
||||
func12(1, **{"z": None})
|
||||
|
||||
|
||||
def func13(*, a: str, b: str, c: int | None = None):
|
||||
...
|
||||
|
||||
|
||||
func_args1: dict[Literal["a", "b", "d"], str] = {
|
||||
"a": "a",
|
||||
"b": "b",
|
||||
"d": "d",
|
||||
}
|
||||
|
||||
func13(**func_args1)
|
||||
|
||||
func_args2: dict[Literal["a", "b", "c"], str] = {
|
||||
"a": "a",
|
||||
"b": "b",
|
||||
"c": "c",
|
||||
}
|
||||
|
||||
|
||||
# This should generate an error.
|
||||
func13(**func_args2)
|
||||
|
||||
|
||||
def func14(cb1: Callable[..., Any], cb2: Any, x: None):
|
||||
cb1(**x) # This should generate an error
|
||||
cb2(**x) # This should generate an error
|
||||
|
||||
|
||||
def func15(cb1: Callable[..., Any], cb2: Any, a: int, b: None | str):
|
||||
print(*a) # This should generate an error
|
||||
print(*b) # This should generate an error
|
||||
cb1(*a) # This should generate an error
|
||||
cb2(*b) # This should generate an error
|
||||
|
||||
@@ -1,180 +0,0 @@
|
||||
# This sample tests the Python 3.8 "positional-only parameter" feature.
|
||||
|
||||
from typing import Any, Dict, Protocol, Tuple
|
||||
|
||||
|
||||
def f0(a: int, b: int):
|
||||
return 3
|
||||
|
||||
|
||||
def f1(a: int, b: int, /):
|
||||
return 3
|
||||
|
||||
# This should generate an error because only one
|
||||
# '/' parameter is allowed.
|
||||
def f2(a: int, /, b: int, /):
|
||||
return 3
|
||||
|
||||
def f3(a: int, /, b: int):
|
||||
return 3
|
||||
|
||||
def f4(a: int, /, b: int, *, c: int):
|
||||
return 3
|
||||
|
||||
# This should generate an error because a '/'
|
||||
# parameter shouldn't appear after '*'.
|
||||
def f5(a: int, *, b: int, /, c: int):
|
||||
return 3
|
||||
|
||||
# This should generate an error because a '/'
|
||||
# parameter cannot be the first in a param list.
|
||||
def f6(/, a: int, *, b: int):
|
||||
return 3
|
||||
|
||||
|
||||
f0(2, 3)
|
||||
|
||||
f1(2, 3)
|
||||
|
||||
# This should generate an error because b
|
||||
# is a position-only parameter.
|
||||
f1(2, b=3)
|
||||
|
||||
# This should generate an error because a and b
|
||||
# are position-only parameters.
|
||||
f1(a=2, b=3)
|
||||
|
||||
f2(2, 3)
|
||||
|
||||
# This should generate an error.
|
||||
f2(a=2, b=3)
|
||||
|
||||
f3(2, 3)
|
||||
f3(2, b=3)
|
||||
|
||||
# This should generate 1 error because a is a
|
||||
# position-only parameter.
|
||||
f3(a=2, b=3)
|
||||
|
||||
f4(1, 2, c=3)
|
||||
f4(1, b=2, c=3)
|
||||
|
||||
# This should generate an error because c is a
|
||||
# keyword-only parameter.
|
||||
f4(1, 2, 3)
|
||||
|
||||
# This should generate an error because a is a
|
||||
# positional-only parameter.
|
||||
f4(a=1, b=2, c=3)
|
||||
|
||||
# This will an error because of the bad
|
||||
# declaration. Test to make sure we don't crash.
|
||||
f5(1, b=2, c=3)
|
||||
|
||||
f6(1, b=2)
|
||||
f6(a=1, b=2)
|
||||
|
||||
class A:
|
||||
def f(self, g: bool = False, /, **kwargs) -> None:
|
||||
...
|
||||
|
||||
a = A()
|
||||
|
||||
a.f(hello="world")
|
||||
|
||||
|
||||
def f7(name: str, /, **kwargs: Any):
|
||||
return 3
|
||||
|
||||
f7("hi", name=3)
|
||||
|
||||
# This should generate an error
|
||||
f7("hi", name=3, name=4)
|
||||
|
||||
|
||||
class P1(Protocol):
|
||||
def f(self, x: Any, /):
|
||||
...
|
||||
|
||||
|
||||
class C1:
|
||||
def f(
|
||||
self,
|
||||
y: Any,
|
||||
):
|
||||
...
|
||||
|
||||
|
||||
c1: P1 = C1()
|
||||
|
||||
|
||||
class P2(Protocol):
|
||||
def f(self, x: Any):
|
||||
...
|
||||
|
||||
|
||||
class C2:
|
||||
def f(self, y: Any, /):
|
||||
...
|
||||
|
||||
|
||||
# This should generate an error
|
||||
c2: P2 = C2()
|
||||
|
||||
|
||||
def f8(a: int, b: int = 3, /):
|
||||
...
|
||||
|
||||
|
||||
kwargs: Dict[str, Any] = {}
|
||||
|
||||
# This should generate an error
|
||||
f8()
|
||||
|
||||
# This should generate an error
|
||||
f8(**kwargs)
|
||||
|
||||
|
||||
f8(0, **kwargs)
|
||||
|
||||
def f9(*, c: int):
|
||||
pass
|
||||
|
||||
# This should generate an error because it is missing a keyword
|
||||
# argument for keyword parameter "c".
|
||||
f9(*[1, 2, 3])
|
||||
|
||||
|
||||
# This should generate an error because "/" cannot be used after "*args"
|
||||
def f10(x, *args, /, y):
|
||||
pass
|
||||
|
||||
# This should generate an error because "*" cannot be used after "*args"
|
||||
def f11(x, *args, *, y):
|
||||
pass
|
||||
|
||||
def f15(x, /, *args):
|
||||
pass
|
||||
|
||||
# This should generate an error because x
|
||||
# is a position-only parameter.
|
||||
f15(x=1)
|
||||
|
||||
def f16(x, /, *args, **kw):
|
||||
pass
|
||||
|
||||
# This should generate an error because x
|
||||
# is a position-only parameter.
|
||||
f16(x=1)
|
||||
|
||||
def f12(a: int, b: str, /):
|
||||
...
|
||||
|
||||
|
||||
def f13(v: Tuple[int, str]):
|
||||
f12(*v)
|
||||
|
||||
def f14(v: Tuple[int]):
|
||||
# This should generate an error because parameter "b" has
|
||||
# no corresponding argument.
|
||||
f12(*v)
|
||||
@@ -1,11 +0,0 @@
|
||||
# This sample tests that the TypeVar matching logic for
|
||||
# functions is working correctly.
|
||||
|
||||
a: list[str] = ["a", "bc"]
|
||||
|
||||
# This should work because the "sorted" is defined
|
||||
# with the first parameter of Iterable[_T] and the
|
||||
# 'key' parameter Callable[[_T], Any]. Since "len"
|
||||
# is a function that takes a "Sized" and "str" is
|
||||
# a "Sized", the result of this should be List[str].
|
||||
b: list[str] = sorted(a, key=len)
|
||||
@@ -1,94 +0,0 @@
|
||||
# This sample tests handling of unpack operators used
|
||||
# for arguments that are of a specified length (specifically,
|
||||
# tuples with a specified list of elements types).
|
||||
|
||||
from typing import NamedTuple, List, Tuple
|
||||
|
||||
X = NamedTuple("X", [("a", int), ("b", str), ("c", str)])
|
||||
|
||||
q0: List[Tuple[int, str, str]] = [(1, "", ""), (2, "", "")]
|
||||
|
||||
[X(*item) for item in q0]
|
||||
|
||||
|
||||
q1: List[Tuple[int, str, float]] = [(1, "a", 3), (2, "b", 4), (3, "c", 5)]
|
||||
|
||||
# This should generate an error because the items in q1 are not the
|
||||
# right type for the X constructor.
|
||||
[X(*item) for item in q1]
|
||||
|
||||
|
||||
q2: List[Tuple[int, str]] = [(1, "1"), (2, "2"), (3, "3")]
|
||||
|
||||
# This should generate an error because the items in q2 contain only
|
||||
# two elements, and we need three to populate all three parameters
|
||||
# in the X constructor.
|
||||
[X(*item) for item in q2]
|
||||
|
||||
|
||||
q3: List[Tuple[int, str, str, float]] = [
|
||||
(1, "a", "3", 4),
|
||||
(2, "b", "4", 5),
|
||||
(3, "c", "5", 6),
|
||||
]
|
||||
|
||||
# This should generate an error because the items in q3 contain
|
||||
# four elements, and we need three to populate all parameters
|
||||
# in the X constructor.
|
||||
[X(*item) for item in q3]
|
||||
|
||||
|
||||
q4: List[Tuple[int, ...]] = [
|
||||
(1, 3),
|
||||
(2, 5),
|
||||
(3, 6),
|
||||
]
|
||||
|
||||
# This should generate two errors because it isn't assignable to parameter
|
||||
# b or c.
|
||||
[X(*item) for item in q4]
|
||||
|
||||
|
||||
Y = NamedTuple("Y", [("a", str), ("b", str), ("c", str)])
|
||||
|
||||
q5: List[Tuple[str, ...]] = [
|
||||
("a", "b"),
|
||||
("a", "b"),
|
||||
]
|
||||
|
||||
[Y(*item) for item in q5]
|
||||
|
||||
|
||||
class Z(NamedTuple):
|
||||
a: list[str]
|
||||
b: list[int]
|
||||
|
||||
|
||||
q6 = Z(["1"], [3])
|
||||
|
||||
for a, b in zip(*q6):
|
||||
reveal_type(a, expected_text="str")
|
||||
reveal_type(b, expected_text="int")
|
||||
|
||||
|
||||
def func1(a: list[str], c: list[int]): ...
|
||||
|
||||
|
||||
func1(*q6)
|
||||
|
||||
|
||||
class ABC(NamedTuple):
|
||||
a: float
|
||||
b: float
|
||||
c: float
|
||||
|
||||
def to_rgba(self) -> "ABC":
|
||||
return ABC(*self)
|
||||
|
||||
|
||||
class AB(NamedTuple):
|
||||
a: float
|
||||
b: float
|
||||
|
||||
def to_abc(self) -> ABC:
|
||||
return ABC(*self, 1)
|
||||
@@ -1,50 +0,0 @@
|
||||
# This sample tests the handling of unpack operators
|
||||
# used in argument expressions when used in conjunction with
|
||||
# tuples and *args parameters.
|
||||
|
||||
|
||||
def func1(a: int, b: int):
|
||||
pass
|
||||
|
||||
|
||||
def func2(*args: int):
|
||||
pass
|
||||
|
||||
|
||||
fixed_tuple_0 = ()
|
||||
func1(*fixed_tuple_0, 2, 3)
|
||||
func2(*fixed_tuple_0, 2)
|
||||
|
||||
fixed_tuple_1 = (1,)
|
||||
|
||||
# This should generate an error because there
|
||||
# are too many parameters.
|
||||
func1(*fixed_tuple_1, 2, 3)
|
||||
|
||||
func2(*fixed_tuple_1, 2, *fixed_tuple_0)
|
||||
|
||||
fixed_tuple_3 = (1, 3, 5)
|
||||
|
||||
# This should generate an error because there
|
||||
# are too many parameters.
|
||||
func1(*fixed_tuple_3, 2)
|
||||
|
||||
func2(*fixed_tuple_3, 2, *fixed_tuple_0)
|
||||
|
||||
unbounded_tuple: tuple[int, ...] = (1, 5, 3)
|
||||
|
||||
func2(*unbounded_tuple)
|
||||
func2(*unbounded_tuple, 2)
|
||||
|
||||
|
||||
def func3(*args: str): ...
|
||||
|
||||
|
||||
def func4(v1: list[str] | None, v2: None, v3: list[str]):
|
||||
# This should generate an error.
|
||||
func3(*v1)
|
||||
|
||||
# This should generate an error.
|
||||
func3(*v2)
|
||||
|
||||
func3(*v3)
|
||||
@@ -1,85 +0,0 @@
|
||||
# This sample tests the handling of an unpacked TypedDict passed as
|
||||
# an argument to a function.
|
||||
|
||||
from typing import TypedDict, Unpack
|
||||
|
||||
|
||||
class TD1(TypedDict):
|
||||
arg1: int
|
||||
arg2: str
|
||||
|
||||
|
||||
class TD2(TD1):
|
||||
arg3: float
|
||||
|
||||
|
||||
def func1(arg1: int, arg2: str):
|
||||
pass
|
||||
|
||||
|
||||
def func2(arg1: int, arg2: str, arg3: float):
|
||||
pass
|
||||
|
||||
|
||||
def func3(arg1: int, arg2: str, **kwargs: float):
|
||||
pass
|
||||
|
||||
|
||||
def func4(arg1: int, arg2: str, **kwargs: int):
|
||||
pass
|
||||
|
||||
|
||||
def func5(arg1: int, arg2: str, **kwargs: object):
|
||||
pass
|
||||
|
||||
|
||||
td1: TD1 = {"arg1": 10, "arg2": "something"}
|
||||
td2: TD2 = {"arg1": 10, "arg2": "something", "arg3": 3.4}
|
||||
|
||||
func1(**td1)
|
||||
|
||||
# This should generate an error because "arg1" is already assigned
|
||||
func1(arg1=3, **td1)
|
||||
|
||||
# This should generate an error because "arg3" isn't provided
|
||||
func1(**td2)
|
||||
|
||||
# This should generate an error because "arg3" isn't matched
|
||||
func2(**td1)
|
||||
|
||||
func2(**td2)
|
||||
|
||||
|
||||
# This should generate an error because the extra entries
|
||||
# in the TD are of type object.
|
||||
func3(**td1)
|
||||
|
||||
# This should generate an error because the extra entries
|
||||
# in the TD are of type object.
|
||||
func3(**td2)
|
||||
|
||||
# This should generate an error because the extra entries
|
||||
# in the TD are of type object.
|
||||
func4(**td1)
|
||||
|
||||
func5(**td1)
|
||||
func5(**td2)
|
||||
|
||||
# This should generate two errors because "arg3" cannot be matched
|
||||
# due to the type of the **kwargs parameter. Also, the extra entries
|
||||
# in the TD are of type object.
|
||||
func4(**td2)
|
||||
|
||||
|
||||
class Options(TypedDict, total=False):
|
||||
opt1: bool
|
||||
opt2: str
|
||||
|
||||
|
||||
def func6(code: str | None = None, **options: Unpack[Options]):
|
||||
pass
|
||||
|
||||
|
||||
func6(**{})
|
||||
func6(**{"opt1": True})
|
||||
func6(**{"opt2": "hi"})
|
||||
@@ -1,40 +0,0 @@
|
||||
# This sample tests a case where multiple overloaded calls are nested
|
||||
# within each other.
|
||||
|
||||
from typing import Any, Iterable, TypeVar, Protocol, overload
|
||||
from typing_extensions import ( # viper: ignore[reportMissingModuleSource]
|
||||
LiteralString,
|
||||
)
|
||||
|
||||
_T = TypeVar("_T")
|
||||
_T_co = TypeVar("_T_co", covariant=True)
|
||||
|
||||
|
||||
class SupportsLenAndGetItem(Protocol[_T_co]):
|
||||
def __getitem__(self, __k: int) -> _T_co: ...
|
||||
|
||||
|
||||
def choices(population: SupportsLenAndGetItem[_T]) -> list[_T]: ...
|
||||
|
||||
|
||||
@overload
|
||||
def join(__iterable: Iterable[LiteralString]) -> LiteralString: # type:ignore
|
||||
...
|
||||
|
||||
|
||||
@overload
|
||||
def join(__iterable: Iterable[str]) -> str: ...
|
||||
|
||||
|
||||
@overload
|
||||
def array(object: int) -> list[Any]: ...
|
||||
|
||||
|
||||
@overload
|
||||
def array(object: object) -> list[Any]: ...
|
||||
|
||||
|
||||
def array(object: object) -> list[Any]: ...
|
||||
|
||||
|
||||
array([join(choices("")) for i in range(1)])
|
||||
@@ -1,51 +0,0 @@
|
||||
# This sample tests the case where a dictionary expansion operator
|
||||
# is used in a call. The type checker should verify that the
|
||||
# type supports a SupportsKeyAndGetItem protocol.
|
||||
|
||||
from typing import Any, Generic, Iterator, TypeVar, Mapping, KeysView
|
||||
|
||||
|
||||
class MyMapping(Mapping[str, Any]):
|
||||
def __getitem__(self, __key: str) -> Any: ...
|
||||
|
||||
def __iter__(self) -> Iterator[str]: ...
|
||||
|
||||
def __len__(self) -> int: ...
|
||||
|
||||
|
||||
class StrRecord:
|
||||
def __getitem__(self, __key: str) -> str: ...
|
||||
|
||||
def keys(self) -> KeysView[str]: ...
|
||||
|
||||
|
||||
T = TypeVar("T")
|
||||
|
||||
|
||||
class GenericRecord(Generic[T]):
|
||||
def __getitem__(self, __key: str) -> T: ...
|
||||
|
||||
def keys(self) -> KeysView[T]: ...
|
||||
|
||||
|
||||
def func1(**kwargs: Any) -> None: ...
|
||||
|
||||
|
||||
m = MyMapping()
|
||||
r = StrRecord()
|
||||
|
||||
|
||||
def func2(
|
||||
m: MyMapping,
|
||||
r: StrRecord,
|
||||
g: GenericRecord[str],
|
||||
mrg: MyMapping | StrRecord | GenericRecord[str],
|
||||
bad: GenericRecord[bytes],
|
||||
):
|
||||
func1(**m)
|
||||
func1(**r)
|
||||
func1(**g)
|
||||
func1(**mrg)
|
||||
|
||||
# This should generate an error.
|
||||
func1(**bad)
|
||||
@@ -1,35 +0,0 @@
|
||||
# This sample tests pyright's ability to perform return type
|
||||
# analysis of functions based on call-site arguments.
|
||||
|
||||
|
||||
# This function has no type annotations
|
||||
from typing import TypeVar
|
||||
|
||||
T = TypeVar("T")
|
||||
|
||||
|
||||
def add(a, b):
|
||||
return a + b
|
||||
|
||||
|
||||
async def async_call(x):
|
||||
return x
|
||||
|
||||
|
||||
def deco1(f: T) -> T:
|
||||
return f
|
||||
|
||||
|
||||
@deco1
|
||||
def add2(a, b):
|
||||
return a + b
|
||||
|
||||
|
||||
def identity(a):
|
||||
return a
|
||||
|
||||
|
||||
def func1(x: T) -> T:
|
||||
a = identity(x)
|
||||
reveal_type(a, expected_text="T@func1")
|
||||
return a
|
||||
@@ -1,16 +0,0 @@
|
||||
# This sample tests pyright's ability to perform return type
|
||||
# analysis of functions based on call-site arguments.
|
||||
|
||||
from .callSite1 import add, add2, async_call
|
||||
|
||||
v1 = add(1, 2)
|
||||
reveal_type(v1, expected_text="Literal[3]")
|
||||
|
||||
v2 = add("hi", "there")
|
||||
reveal_type(v2, expected_text="Literal['hithere']")
|
||||
|
||||
v3 = add2(1, 2)
|
||||
reveal_type(v3, expected_text="Unknown")
|
||||
|
||||
v4 = async_call(1)
|
||||
reveal_type(v4, expected_text="CoroutineType[Any, Any, Unknown]")
|
||||
@@ -1,50 +0,0 @@
|
||||
# This sample tests the case where a call-site return type evaluation
|
||||
# is invoked multiple times within a loop using different literal values
|
||||
# each time.
|
||||
|
||||
|
||||
def func1(h, ids):
|
||||
for _ in ids:
|
||||
h = func2(h, 1)
|
||||
h = func2(h, 2)
|
||||
h = func2(h, 3)
|
||||
h = func2(h, 4)
|
||||
h = func2(h, 5)
|
||||
h = func2(h, 6)
|
||||
h = func2(h, 7)
|
||||
h = func2(h, 8)
|
||||
h = func2(h, 9)
|
||||
h = func2(h, 10)
|
||||
h = func2(h, 11)
|
||||
h = func2(h, 12)
|
||||
h = func2(h, 13)
|
||||
h = func2(h, 14)
|
||||
h = func2(h, 15)
|
||||
h = func2(h, 16)
|
||||
h = func2(h, 17)
|
||||
h = func2(h, 18)
|
||||
h = func2(h, 19)
|
||||
h = func2(h, 20)
|
||||
h = func2(h, 21)
|
||||
h = func2(h, 22)
|
||||
h = func2(h, 23)
|
||||
h = func2(h, 24)
|
||||
h = func2(h, 25)
|
||||
h = func2(h, 26)
|
||||
h = func2(h, 27)
|
||||
h = func2(h, 28)
|
||||
h = func2(h, 29)
|
||||
h = func2(h, 30)
|
||||
h = func2(h, 31)
|
||||
h = func2(h, 32)
|
||||
h = func2(h, 33)
|
||||
h = func2(h, 34)
|
||||
h = func2(h, 35)
|
||||
h = func2(h, 36)
|
||||
h = func2(h, 37)
|
||||
h = func2(h, 38)
|
||||
h = func2(h, 39)
|
||||
|
||||
|
||||
def func2(a, unused):
|
||||
return a
|
||||
@@ -1,51 +0,0 @@
|
||||
# This sample tests the type checker's handling of the
|
||||
# builtin "Callable" class.
|
||||
|
||||
from typing import Callable
|
||||
|
||||
Callable1 = Callable[["A"], None]
|
||||
|
||||
|
||||
class A:
|
||||
pass
|
||||
|
||||
|
||||
Callable2 = Callable[[A], None]
|
||||
|
||||
|
||||
def func1(a: Callable1):
|
||||
a(A())
|
||||
|
||||
|
||||
def func2(a: Callable2):
|
||||
a(A())
|
||||
|
||||
|
||||
Callable3 = Callable[..., int]
|
||||
|
||||
|
||||
def func3(a: Callable3) -> int:
|
||||
return a(1, 2, 3) + a() + a("hello") + a([])
|
||||
|
||||
|
||||
# This should generate an error (... not allowed in param list).
|
||||
Callable4 = Callable[[...], int]
|
||||
|
||||
# This should generate an error (too many arguments).
|
||||
Callable5 = Callable[..., int, int]
|
||||
|
||||
|
||||
# Test Callable with no parameters
|
||||
Callable6 = Callable[[], str]
|
||||
|
||||
|
||||
def func6(a: Callable6):
|
||||
a()
|
||||
# This should generate an error.
|
||||
a(1)
|
||||
|
||||
|
||||
def func7(a: Callable):
|
||||
reveal_type(a, expected_text="(...) -> Unknown")
|
||||
b = a(3, 4, 5)
|
||||
reveal_type(b, expected_text="Unknown")
|
||||
@@ -1,55 +0,0 @@
|
||||
# This sample tests the assignment of generic callables
|
||||
# to concrete callable types.
|
||||
|
||||
from asyncio.futures import Future
|
||||
from asyncio.tasks import ensure_future
|
||||
from typing import Any, Awaitable, Callable, Iterable, Sequence, TypeVar
|
||||
|
||||
|
||||
_T1 = TypeVar("_T1")
|
||||
|
||||
|
||||
def func1(__iterable: Iterable[_T1]) -> _T1: ...
|
||||
|
||||
|
||||
a: Callable[[Sequence[float]], float] = func1
|
||||
b: Callable[[Sequence[Any]], Any] = func1
|
||||
|
||||
|
||||
def func2(__iterable: Sequence[_T1]) -> _T1: ...
|
||||
|
||||
|
||||
# This should generate an error because an Iterable parameter
|
||||
# is not assignable to a Sequence parameter.
|
||||
c: Callable[[Iterable[float]], float] = func2
|
||||
|
||||
|
||||
_T2 = TypeVar("_T2", bound=float)
|
||||
|
||||
|
||||
def func3(__iterable: Iterable[_T2]) -> _T2: ...
|
||||
|
||||
|
||||
d: Callable[[Sequence[int]], int] = func3
|
||||
|
||||
# This should generate an error because Sequence[str]
|
||||
# is not compatible with the bound TypeVar _T2.
|
||||
e: Callable[[Sequence[str]], Any] = func3
|
||||
|
||||
|
||||
_T3 = TypeVar("_T3")
|
||||
|
||||
TA1 = Callable[[_T3], None]
|
||||
TA2 = Callable[[TA1[_T3]], None]
|
||||
|
||||
|
||||
def func4(cb: TA2[_T3]) -> Awaitable[_T3]:
|
||||
future: Future[_T3] = Future()
|
||||
return ensure_future(future)
|
||||
|
||||
|
||||
def func5(done: TA1[int]) -> None:
|
||||
pass
|
||||
|
||||
|
||||
reveal_type(func4(func5), expected_text="Awaitable[int]")
|
||||
@@ -1,23 +0,0 @@
|
||||
# This sample tests the case where a callable type contains a
|
||||
# callable type as an input parameter, and the latter callable
|
||||
# contains generic types.
|
||||
|
||||
from typing import Callable, Generic, TypeVar
|
||||
|
||||
T = TypeVar("T")
|
||||
R = TypeVar("R")
|
||||
|
||||
|
||||
class ClassA(Generic[R]): ...
|
||||
|
||||
|
||||
class ClassB(Generic[T]):
|
||||
def method1(self, val: Callable[[ClassA[R]], T]) -> R | None:
|
||||
return None
|
||||
|
||||
|
||||
b1: ClassB[tuple[int, ClassA[str]]] = ClassB()
|
||||
v1: Callable[[ClassA[str]], tuple[int, ClassA[str]]] = lambda r: (42, r)
|
||||
|
||||
ret = b1.method1(v1)
|
||||
reveal_type(ret, expected_text="str | None")
|
||||
@@ -1,32 +0,0 @@
|
||||
# This sample tests the case where a callable type within a function
|
||||
# signature contains a generic return type within a union.
|
||||
|
||||
from typing import TypeVar
|
||||
from collections.abc import Callable
|
||||
|
||||
|
||||
T = TypeVar("T")
|
||||
U = TypeVar("U")
|
||||
|
||||
|
||||
def func1(f: Callable[[T], U | None], x: T) -> U:
|
||||
y = f(x)
|
||||
|
||||
reveal_type(y, expected_text="U@func1 | None")
|
||||
|
||||
if y is not None:
|
||||
reveal_type(y, expected_text="U@func1")
|
||||
return y
|
||||
|
||||
raise ValueError()
|
||||
|
||||
|
||||
def func2(x: T, f: Callable[[T], U | None]) -> U:
|
||||
def g() -> U:
|
||||
y = f(x)
|
||||
if y is not None:
|
||||
return y
|
||||
|
||||
raise ValueError()
|
||||
|
||||
return g()
|
||||
@@ -1,37 +0,0 @@
|
||||
# This sample covers the case where a function accepts a generic callable
|
||||
# as a parameter along with another parameter that uses the same type variable
|
||||
# and a caller provides an overloaded function as an argument.
|
||||
|
||||
from typing import Any, Callable, TypeVar, overload
|
||||
|
||||
T = TypeVar("T")
|
||||
|
||||
|
||||
@overload
|
||||
def func1(real: float): ...
|
||||
|
||||
|
||||
@overload
|
||||
def func1(real: str): ...
|
||||
|
||||
|
||||
def func1(real: float | str) -> None: ...
|
||||
|
||||
|
||||
def func2(f: Callable[[T], Any], p: T):
|
||||
return f(p)
|
||||
|
||||
|
||||
func2(func1, 4)
|
||||
func2(func1, "4")
|
||||
|
||||
# This should generate an error because a "bytes" argument
|
||||
# doesn't match any of the overloads.
|
||||
func2(func1, b"")
|
||||
|
||||
|
||||
map(complex, ["3j", "4"])
|
||||
|
||||
# This should generate two errors because a "bytes" argument
|
||||
# doesn't match any of the overloads in the "complex" constructor.
|
||||
map(complex, [b"3j"])
|
||||
@@ -1,91 +0,0 @@
|
||||
# This sample tests the use of unpacked tuples in a Callable, as described
|
||||
# in PEP 646.
|
||||
|
||||
from typing import Callable, TypeVar
|
||||
from typing_extensions import ( # viper: ignore[reportMissingModuleSource]
|
||||
TypeVarTuple,
|
||||
Unpack,
|
||||
)
|
||||
|
||||
_T = TypeVar("_T", bound=int)
|
||||
|
||||
TA1 = Callable[[_T, Unpack[tuple[int, ...]], tuple[int, int, str], str], _T]
|
||||
|
||||
# This should generate an error.
|
||||
TA2 = Callable[
|
||||
[int, Unpack[tuple[int, ...]], Unpack[tuple[int, int, str, ...]], str], int
|
||||
]
|
||||
|
||||
TA3 = Callable[[int, Unpack[tuple[int, int]], str], int]
|
||||
|
||||
TA4 = Callable[[Unpack[tuple[int, ...]]], _T]
|
||||
|
||||
|
||||
def func1(x: TA1[int]):
|
||||
r1 = x(3, 4, 5, (1, 2, "hi"), "hi")
|
||||
reveal_type(r1, expected_text="int")
|
||||
|
||||
x(3, (1, 2, "hi"), "hi")
|
||||
|
||||
# This should generate an error because the first argument is not an int.
|
||||
x(None, (1, 2, "hi"), "hi")
|
||||
|
||||
y = [1, 2, 3]
|
||||
x(1, *y, (1, 2, "hi"), "hi")
|
||||
|
||||
|
||||
def func2(x: TA3):
|
||||
x(3, 4, 5, "hi")
|
||||
|
||||
# This should generate an error.
|
||||
x(3, 4, "hi")
|
||||
|
||||
# This should generate an error.
|
||||
x(3, 4, "hi", "hi")
|
||||
|
||||
|
||||
def func6(x: TA4):
|
||||
x()
|
||||
|
||||
|
||||
Ts = TypeVarTuple("Ts")
|
||||
|
||||
|
||||
def func3(
|
||||
path: str, *args: Unpack[tuple[Unpack[Ts], str]]
|
||||
) -> tuple[Unpack[Ts], int]: ...
|
||||
|
||||
|
||||
v3 = func3("", 1, "2", 3.3, None, "")
|
||||
reveal_type(v3, expected_text="tuple[int, str, float, None, int]")
|
||||
|
||||
func3("", "")
|
||||
|
||||
# This should generate an error because the type of the first arg is wrong.
|
||||
func3(1, "")
|
||||
|
||||
# This should generate an error because the type of the last arg is wrong.
|
||||
func3("", 1)
|
||||
|
||||
# This should generate an error because the type of the last arg is wrong.
|
||||
func3("", 1, 2, 3, "hi", 1)
|
||||
|
||||
|
||||
def func4(
|
||||
path: str, *args: Unpack[tuple[Unpack[Ts], str]]
|
||||
) -> tuple[Unpack[Ts], complex]: ...
|
||||
|
||||
|
||||
v4 = func4("", 1, "2", 3.3, None, "")
|
||||
reveal_type(v4, expected_text="tuple[int, str, float, None, complex]")
|
||||
|
||||
|
||||
def func5(path: str, *args: Unpack[tuple[str, ...]]) -> None: ...
|
||||
|
||||
|
||||
# This should generate an errors.
|
||||
func5("", 1, "2", "")
|
||||
func5("", "1", "2", "3.3", "None", "")
|
||||
|
||||
# This should generate one error.
|
||||
func5("", "1", "2", "3.3", "None", 3)
|
||||
@@ -1,33 +0,0 @@
|
||||
# This sample tests the handling of the `__call__` attribute.
|
||||
|
||||
|
||||
from typing import Iterable, Iterator
|
||||
|
||||
|
||||
class A:
|
||||
def __init__(self):
|
||||
self.__call__ = self.method1
|
||||
|
||||
def method1(self, a: int):
|
||||
return a
|
||||
|
||||
|
||||
# This should generate an error because `__call__` is
|
||||
# callable only if it's a class variable.
|
||||
A()(0)
|
||||
|
||||
|
||||
class B:
|
||||
def method1(self, a: int):
|
||||
return a
|
||||
|
||||
__call__ = method1
|
||||
|
||||
|
||||
B()(0)
|
||||
|
||||
|
||||
class C[K](Iterable[K]):
|
||||
def keys(self) -> Iterator[K]: ...
|
||||
|
||||
__iter__ = keys
|
||||
@@ -1,159 +0,0 @@
|
||||
# This sample tests support for callback protocols (defined in PEP 544).
|
||||
|
||||
from typing import Callable, Protocol
|
||||
|
||||
|
||||
class TestClass1(Protocol):
|
||||
def __call__(self, *vals: bytes, maxlen: int | None = None) -> list[bytes]:
|
||||
return []
|
||||
|
||||
|
||||
def good_cb(*vals: bytes, maxlen: int | None = None) -> list[bytes]:
|
||||
return []
|
||||
|
||||
|
||||
def bad_cb1(*vals: bytes, maxlen: int | None, maxitems: int | None) -> list[bytes]:
|
||||
return []
|
||||
|
||||
|
||||
def bad_cb2(*vals: bytes) -> list[bytes]:
|
||||
return []
|
||||
|
||||
|
||||
def bad_cb3(*vals: bytes, maxlen: str | None) -> list[bytes]:
|
||||
return []
|
||||
|
||||
|
||||
var1: TestClass1 = good_cb
|
||||
|
||||
# This should generate an error because maxitems is unmatched.
|
||||
var1 = bad_cb1
|
||||
|
||||
# This should generate an error because maxlen is unmatched.
|
||||
var1 = bad_cb2
|
||||
|
||||
# This should generate an error because maxlen is the wrong type.
|
||||
var1 = bad_cb3
|
||||
|
||||
|
||||
class TestClass2(Protocol):
|
||||
def __call__(self, *vals: bytes, **kwargs: str) -> None:
|
||||
pass
|
||||
|
||||
|
||||
def func1(*a: bytes, **b: str):
|
||||
pass
|
||||
|
||||
|
||||
def func2(*a: bytes):
|
||||
pass
|
||||
|
||||
|
||||
def func3(*a: str, **b: str):
|
||||
pass
|
||||
|
||||
|
||||
def func4(*a: bytes, **b: bytes):
|
||||
pass
|
||||
|
||||
|
||||
def func5(**b: str):
|
||||
pass
|
||||
|
||||
|
||||
var2: TestClass2 = func1
|
||||
|
||||
# This should generate an error.
|
||||
var2 = func2
|
||||
|
||||
# This should generate an error.
|
||||
var2 = func3
|
||||
|
||||
# This should generate an error.
|
||||
var2 = func4
|
||||
|
||||
# This should generate an error.
|
||||
var2 = func5
|
||||
|
||||
|
||||
class NotProto:
|
||||
def __call__(self, *vals: bytes, maxlen: int | None = None) -> list[bytes]:
|
||||
return []
|
||||
|
||||
|
||||
# This should generate an error because NotProto is not a protocol class.
|
||||
not_proto: NotProto = good_cb
|
||||
|
||||
|
||||
class TestClass3(Protocol):
|
||||
def __call__(self) -> None:
|
||||
pass
|
||||
|
||||
|
||||
var3: TestClass3 = func1
|
||||
|
||||
var3 = func2
|
||||
var3 = func3
|
||||
var3 = func4
|
||||
var3 = func5
|
||||
|
||||
|
||||
class TestClass4(Protocol):
|
||||
foo: int
|
||||
|
||||
def __call__(self, x: int) -> None:
|
||||
pass
|
||||
|
||||
|
||||
def test_func4(x: int) -> None:
|
||||
pass
|
||||
|
||||
|
||||
# This should generate an error.
|
||||
var4: TestClass4 = test_func4
|
||||
|
||||
|
||||
class TestClass5(Protocol):
|
||||
def __call__(self, *, a: int, b: str) -> int: ...
|
||||
|
||||
|
||||
def test_func5(a: int, b: str) -> int:
|
||||
return 123
|
||||
|
||||
|
||||
f5: TestClass5 = test_func5
|
||||
|
||||
|
||||
class TestClass6(Protocol):
|
||||
def __call__(self, a: int, /, *, b: str) -> int: ...
|
||||
|
||||
|
||||
def test_func6(a: int, b: str) -> int:
|
||||
return 123
|
||||
|
||||
|
||||
f6: TestClass6 = test_func6
|
||||
|
||||
|
||||
class TestClass7:
|
||||
def __call__(self) -> None:
|
||||
pass
|
||||
|
||||
|
||||
def test_func7(*args: *tuple[int, *tuple[int, ...]]) -> int:
|
||||
return 123
|
||||
|
||||
|
||||
# This should generate an error.
|
||||
f7: TestClass7 = test_func7
|
||||
|
||||
|
||||
class TestClass8:
|
||||
def __call__(self: Callable[[int], int], v: int) -> int:
|
||||
return v
|
||||
|
||||
|
||||
def func8(f: Callable[[int], int]): ...
|
||||
|
||||
|
||||
func8(TestClass8())
|
||||
@@ -1,61 +0,0 @@
|
||||
# This sample tests the case where a callback protocol uses
|
||||
# a (*args: Any, **kwargs: Any) signature.
|
||||
|
||||
|
||||
from typing import Any, Callable, Concatenate, ParamSpec, Protocol, TypeVar
|
||||
|
||||
P = ParamSpec("P")
|
||||
T_contra = TypeVar("T_contra", contravariant=True)
|
||||
|
||||
|
||||
class Proto1(Protocol):
|
||||
def __call__(self, *args, **kwargs) -> None: ...
|
||||
|
||||
|
||||
class Proto2(Protocol):
|
||||
def __call__(self, a: int, /, *args, **kwargs) -> None: ...
|
||||
|
||||
|
||||
class Proto3(Protocol):
|
||||
def __call__(self, a: int, *args: Any, **kwargs: Any) -> None: ...
|
||||
|
||||
|
||||
class Proto4(Protocol[P]):
|
||||
def __call__(self, a: int, *args: P.args, **kwargs: P.kwargs) -> None: ...
|
||||
|
||||
|
||||
class Proto5(Protocol[T_contra]):
|
||||
def __call__(self, *args: T_contra, **kwargs: T_contra) -> None: ...
|
||||
|
||||
|
||||
class Proto6(Protocol):
|
||||
def __call__(self, a: int, /, *args: Any, k: str, **kwargs: Any) -> None:
|
||||
pass
|
||||
|
||||
|
||||
class Proto7(Protocol):
|
||||
def __call__(self, a: float, /, b: int, *, k: str, m: str) -> None:
|
||||
pass
|
||||
|
||||
|
||||
def func(
|
||||
p1: Proto1,
|
||||
p2: Proto2,
|
||||
p3: Proto3,
|
||||
p4: Proto4[...],
|
||||
p5: Proto5[Any],
|
||||
p7: Proto7,
|
||||
c1: Callable[..., None],
|
||||
c2: Callable[Concatenate[int, ...], None],
|
||||
):
|
||||
x1: Callable[..., None] = p1
|
||||
x2: Proto1 = c1
|
||||
x3: Callable[..., None] = p5
|
||||
x4: Proto5[Any] = c1
|
||||
x5: Callable[Concatenate[int, ...], None] = p2
|
||||
x6: Proto2 = c2
|
||||
x7: Callable[..., None] = p3
|
||||
x8: Proto3 = c1
|
||||
x9: Proto4[...] = p3
|
||||
x10: Proto3 = p4
|
||||
x11: Proto6 = p7
|
||||
@@ -1,21 +0,0 @@
|
||||
# This sample tests the case where a callback protocol uses a function-
|
||||
# scoped type variable.
|
||||
|
||||
from typing import Generic, Protocol, TypeVar
|
||||
|
||||
T = TypeVar("T")
|
||||
T_co = TypeVar("T_co", covariant=True)
|
||||
U_co = TypeVar("U_co", covariant=True)
|
||||
|
||||
|
||||
class A(Generic[T_co, U_co]): ...
|
||||
|
||||
|
||||
class BProto(Protocol):
|
||||
def __call__(self, x: T) -> A[list[T], T]: ...
|
||||
|
||||
|
||||
def func1() -> BProto:
|
||||
def make_a(x: T) -> A[list[T], T]: ...
|
||||
|
||||
return make_a
|
||||
@@ -1,28 +0,0 @@
|
||||
# This sample tests the case where an object is assigned to a
|
||||
# callback protocol and the object's "__call__" has unannotated
|
||||
# or "Any" parameter types.
|
||||
|
||||
from typing import Any, Protocol, TypeVar
|
||||
|
||||
InputT = TypeVar("InputT", contravariant=True)
|
||||
OutputT = TypeVar("OutputT", covariant=True)
|
||||
|
||||
|
||||
class MyCallable(Protocol[InputT, OutputT]):
|
||||
def __call__(self, inputs: InputT) -> OutputT: ...
|
||||
|
||||
|
||||
class Class1:
|
||||
def __call__(self, inputs) -> int:
|
||||
return 5
|
||||
|
||||
|
||||
g1: MyCallable[int, int] = Class1()
|
||||
|
||||
|
||||
class Class2:
|
||||
def __call__(self, inputs: Any) -> int:
|
||||
return 5
|
||||
|
||||
|
||||
g2: MyCallable[int, int] = Class2()
|
||||
@@ -1,20 +0,0 @@
|
||||
# This sample tests the case where a callback protocol uses a
|
||||
# class-level type variable and a combination of Type[T] and T.
|
||||
|
||||
from typing import Protocol, TypeVar, Type
|
||||
|
||||
TE = TypeVar("TE", bound=Exception)
|
||||
|
||||
|
||||
class CallbackProtocol1(Protocol[TE]):
|
||||
def __call__(self, s_exc: Exception, t_exc_class: Type[TE]) -> TE: ...
|
||||
|
||||
|
||||
def func1(s_exc: Exception, t_exc_class: Type[TE]) -> TE: ...
|
||||
|
||||
|
||||
def func2(
|
||||
s_exc_class: Exception,
|
||||
t_exc_class: Type[TE],
|
||||
mapper: CallbackProtocol1[TE] = func1,
|
||||
): ...
|
||||
@@ -1,65 +0,0 @@
|
||||
# This sample tests the case where a callback protocol uses
|
||||
# an overloaded __call__ method.
|
||||
|
||||
from typing import Any, Protocol, overload
|
||||
|
||||
|
||||
class P1(Protocol):
|
||||
@overload
|
||||
def __call__(self, x: int) -> int: ...
|
||||
|
||||
@overload
|
||||
def __call__(self, x: str) -> str: ...
|
||||
|
||||
def __call__(self, x: Any) -> Any: ...
|
||||
|
||||
|
||||
def func0(x: Any) -> Any:
|
||||
return x
|
||||
|
||||
|
||||
def func1(x: int) -> Any:
|
||||
return x
|
||||
|
||||
|
||||
a0: P1 = func0
|
||||
|
||||
# This should generate an error
|
||||
a1: P1 = func1
|
||||
|
||||
|
||||
@overload
|
||||
def of1(x: int) -> int: ...
|
||||
|
||||
|
||||
@overload
|
||||
def of1(x: str) -> str: ...
|
||||
|
||||
|
||||
def of1(x: Any) -> Any:
|
||||
return x
|
||||
|
||||
|
||||
@overload
|
||||
def of2(x: int) -> complex: ...
|
||||
|
||||
|
||||
@overload
|
||||
def of2(x: str) -> str: ...
|
||||
|
||||
|
||||
def of2(x: Any) -> Any:
|
||||
return x
|
||||
|
||||
|
||||
b0: P1 = of1
|
||||
|
||||
# This should generate an error
|
||||
b1: P1 = of2
|
||||
|
||||
|
||||
class P2(Protocol):
|
||||
def __call__(self, *args: int) -> Any: ...
|
||||
|
||||
|
||||
a: P2 = lambda *args: map(lambda arg: arg + 0, args)
|
||||
@@ -1,84 +0,0 @@
|
||||
# This sample tests the case where a callback protocol defines additional
|
||||
# attributes.
|
||||
|
||||
from typing import Any, Callable, Protocol, TypeVar, cast
|
||||
from typing_extensions import ParamSpec # viper: ignore[reportMissingModuleSource]
|
||||
|
||||
|
||||
P = ParamSpec("P")
|
||||
R = TypeVar("R", covariant=True)
|
||||
|
||||
|
||||
class CallbackProto1(Protocol[P, R]):
|
||||
__name__: str
|
||||
|
||||
other_attribute: int
|
||||
|
||||
def __call__(self, *args: P.args, **kwargs: P.kwargs) -> R: ...
|
||||
|
||||
|
||||
def decorator1(f: Callable[P, R]) -> CallbackProto1[P, R]:
|
||||
converted = cast(CallbackProto1, f)
|
||||
|
||||
print(converted.__name__)
|
||||
|
||||
converted.other_attribute = 1
|
||||
|
||||
# This should generate an error
|
||||
converted.other_attribute = "str"
|
||||
|
||||
# This should generate an error
|
||||
converted.xxx = 3
|
||||
|
||||
return converted
|
||||
|
||||
|
||||
@decorator1
|
||||
def func1(x: int) -> str: ...
|
||||
|
||||
|
||||
reveal_type(func1, expected_text="CallbackProto1[(x: int), str]")
|
||||
|
||||
func1.other_attribute
|
||||
|
||||
# This should generate an error
|
||||
func1.other_attribute2
|
||||
|
||||
func1(x=3)
|
||||
|
||||
|
||||
class CallbackProto2(Protocol):
|
||||
__name__: str
|
||||
__module__: str
|
||||
__qualname__: str
|
||||
__annotations__: dict[str, Any]
|
||||
__slots__ = ()
|
||||
|
||||
def __call__(self) -> None: ...
|
||||
|
||||
|
||||
def func2() -> None: ...
|
||||
|
||||
|
||||
v: CallbackProto2 = func2
|
||||
|
||||
|
||||
class TestClass7(Protocol):
|
||||
def __call__(self, x: int, /, y: str) -> Any: ...
|
||||
|
||||
|
||||
def func8(x: int, y: str, /) -> Any:
|
||||
pass
|
||||
|
||||
|
||||
def func9(__x: int, __y: str) -> Any:
|
||||
pass
|
||||
|
||||
|
||||
# This should generate an error because "y" is position-only
|
||||
# in the source but not the dest.
|
||||
var7: TestClass7 = func8
|
||||
|
||||
# This should generate an error because "y" is position-only
|
||||
# in the source but not the dest.
|
||||
var8: TestClass7 = func9
|
||||
Loaded 100 of 1269 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user