mirror of
https://github.com/microsoft/pyright.git
synced 2024-09-11 07:55:56 +03:00
Extended the defineConstant
mechanism to work with conditional statements that contain member access expressions that reference a defined member name. This addresses https://github.com/microsoft/pyright/issues/4060.
This commit is contained in:
parent
2af65e0de6
commit
8538998719
@ -16,7 +16,7 @@ Relative paths specified within the config file are relative to the config file
|
||||
|
||||
**strict** [array of paths, optional]: Paths of directories or files that should use “strict” analysis if they are included. This is the same as manually adding a “# pyright: strict” comment. In strict mode, most type-checking rules are enabled. Refer to [this table](https://github.com/microsoft/pyright/blob/main/docs/configuration.md#diagnostic-rule-defaults) for details about which rules are enabled in strict mode. Paths may contain wildcard characters ** (a directory or multiple levels of directories), * (a sequence of zero or more characters), or ? (a single character).
|
||||
|
||||
**defineConstant** [map of constants to values (boolean or string), optional]: Set of identifiers that should be assumed to contain a constant value wherever used within this program. For example, `{ "DEBUG": true }` indicates that pyright should assume that the identifier `DEBUG` will always be equal to `True`. If this identifier is used within a conditional expression (such as `if not DEBUG:`) pyright will use the indicated value to determine whether the guarded block is reachable or not.
|
||||
**defineConstant** [map of constants to values (boolean or string), optional]: Set of identifiers that should be assumed to contain a constant value wherever used within this program. For example, `{ "DEBUG": true }` indicates that pyright should assume that the identifier `DEBUG` will always be equal to `True`. If this identifier is used within a conditional expression (such as `if not DEBUG:`) pyright will use the indicated value to determine whether the guarded block is reachable or not. Member expressions that reference one of these constants (e.g. `my_module.DEBUG`) are also supported.
|
||||
|
||||
**typeshedPath** [path, optional]: Path to a directory that contains typeshed type stub files. Pyright ships with a bundled copy of typeshed type stubs. If you want to use a different version of typeshed stubs, you can clone the [typeshed github repo](https://github.com/python/typeshed) to a local directory and reference the location with this path. This option is useful if you’re actively contributing updates to typeshed.
|
||||
|
||||
|
@ -118,11 +118,15 @@ export function evaluateStaticBoolExpression(
|
||||
}
|
||||
} else {
|
||||
// Handle the special case of <definedConstant> == 'X' or <definedConstant> != 'X'.
|
||||
if (
|
||||
node.leftExpression.nodeType === ParseNodeType.Name &&
|
||||
node.rightExpression.nodeType === ParseNodeType.StringList
|
||||
) {
|
||||
const constantValue = definedConstants.get(node.leftExpression.value);
|
||||
if (node.rightExpression.nodeType === ParseNodeType.StringList) {
|
||||
let constantValue: string | number | boolean | undefined;
|
||||
|
||||
if (node.leftExpression.nodeType === ParseNodeType.Name) {
|
||||
constantValue = definedConstants.get(node.leftExpression.value);
|
||||
} else if (node.leftExpression.nodeType === ParseNodeType.MemberAccess) {
|
||||
constantValue = definedConstants.get(node.leftExpression.memberName.value);
|
||||
}
|
||||
|
||||
if (constantValue !== undefined && typeof constantValue === 'string') {
|
||||
const comparisonStringName = node.rightExpression.strings.map((s) => s.value).join('');
|
||||
return _evaluateStringBinaryOperation(node.operator, constantValue, comparisonStringName);
|
||||
@ -144,9 +148,9 @@ export function evaluateStaticBoolExpression(
|
||||
if (constant !== undefined) {
|
||||
return !!constant;
|
||||
}
|
||||
} else if (
|
||||
} else if (node.nodeType === ParseNodeType.MemberAccess) {
|
||||
if (
|
||||
typingImportAliases &&
|
||||
node.nodeType === ParseNodeType.MemberAccess &&
|
||||
node.memberName.value === 'TYPE_CHECKING' &&
|
||||
node.leftExpression.nodeType === ParseNodeType.Name &&
|
||||
typingImportAliases.some((alias) => alias === (node.leftExpression as NameNode).value)
|
||||
@ -154,6 +158,12 @@ export function evaluateStaticBoolExpression(
|
||||
return true;
|
||||
}
|
||||
|
||||
const constant = definedConstants.get(node.memberName.value);
|
||||
if (constant !== undefined) {
|
||||
return !!constant;
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
|
@ -50,3 +50,25 @@ if DEFINED_STR == "hi!":
|
||||
x = 1
|
||||
else:
|
||||
x = "error!"
|
||||
|
||||
class Dummy:
|
||||
DEFINED_FALSE: bool
|
||||
DEFINED_TRUE: bool
|
||||
DEFINED_STR: str
|
||||
|
||||
dummy = Dummy()
|
||||
|
||||
if dummy.DEFINED_TRUE:
|
||||
x = 1
|
||||
else:
|
||||
x = "error!"
|
||||
|
||||
if not dummy.DEFINED_FALSE:
|
||||
x = 1
|
||||
else:
|
||||
x = "error!"
|
||||
|
||||
if dummy.DEFINED_STR == "hi!":
|
||||
x = 1
|
||||
else:
|
||||
x = "error!"
|
||||
|
@ -1374,13 +1374,13 @@ test('StaticExpressions1', () => {
|
||||
configOptions.defaultPythonPlatform = 'windows';
|
||||
|
||||
const analysisResults1 = TestUtils.typeAnalyzeSampleFiles(['staticExpressions1.py'], configOptions);
|
||||
TestUtils.validateResults(analysisResults1, 6);
|
||||
TestUtils.validateResults(analysisResults1, 9);
|
||||
|
||||
configOptions.defaultPythonVersion = PythonVersion.V3_11;
|
||||
configOptions.defaultPythonPlatform = 'Linux';
|
||||
|
||||
const analysisResults2 = TestUtils.typeAnalyzeSampleFiles(['staticExpressions1.py'], configOptions);
|
||||
TestUtils.validateResults(analysisResults2, 3);
|
||||
TestUtils.validateResults(analysisResults2, 6);
|
||||
|
||||
configOptions.defineConstant.set('DEFINED_TRUE', true);
|
||||
configOptions.defineConstant.set('DEFINED_FALSE', false);
|
||||
|
Loading…
Reference in New Issue
Block a user