Added new config switch to control reporting of uses of Optional type as an iterable.

This commit is contained in:
Eric Traut 2019-04-15 23:14:39 -07:00
parent 23f9d4b1f3
commit 65239ba766
6 changed files with 29 additions and 4 deletions

View File

@ -97,6 +97,12 @@
"title": "Controls reporting of attempts to call a variable with Optional type",
"default": "none"
},
"reportOptionalIterable": {
"$id": "#/properties/reportOptionalIterable",
"$ref": "#/definitions/diagnostic",
"title": "Controls reporting of attempts to use an Optional type as an iterable value",
"default": "none"
},
"reportUntypedFunctionDecorator": {
"$id": "#/properties/reportUntypedFunctionDecorator",
"$ref": "#/definitions/diagnostic",

View File

@ -40,6 +40,8 @@ The following settings control pyright's diagnostic output (warnings or errors).
**reportOptionalCall** [boolean or string, optional]: Generate or suppress diagnostics for an attempt to call a variable with an Optional type. The default value for this setting is 'none'.
**reportOptionalIterable** [boolean or string, optional]: Generate or suppress diagnostics for an attempt to use an Optional type as an iterable value (e.g. within a `for` statement). The default value for this setting is 'none'.
**reportUntypedFunctionDecorator** [boolean or string, optional]: Generate or suppress diagnostics for function decorators that have no type annotations. These obscure the function type, defeating many type analysis features.
**reportUntypedClassDecorator** [boolean or string, optional]: Generate or suppress diagnostics for class decorators that have no type annotations. These obscure the class type, defeating many type analysis features.

View File

@ -235,8 +235,11 @@ export class ExpressionEvaluator {
const iterMethodName = isAsync ? '__aiter__' : '__iter__';
const nextMethodName = isAsync ? '__anext__' : '__next__';
// TODO - tighten this up, perhaps with a configuration switch.
if (type instanceof UnionType) {
if (type instanceof UnionType && type.getTypes().some(t => t instanceof NoneType)) {
this._addDiagnostic(
this._configOptions.reportOptionalIterable,
`Object of type 'None' cannot be used as iterable value`,
errorNode);
type = type.removeOptional();
}

View File

@ -94,6 +94,9 @@ export class ConfigOptions {
// Report attempts to call a Optional type?
reportOptionalCall: DiagnosticLevel = 'none';
// Report attempts to use an Optional type as an iterable?
reportOptionalIterable: DiagnosticLevel = 'none';
// Report untyped function decorators that obscure the function type?
reportUntypedFunctionDecorator: DiagnosticLevel = 'none';
@ -218,6 +221,10 @@ export class ConfigOptions {
this.reportOptionalCall = this._convertDiagnosticLevel(
configObj.reportOptionalCall, 'reportOptionalCall', 'none');
// Read the "reportOptionalIterable" entry.
this.reportOptionalIterable = this._convertDiagnosticLevel(
configObj.reportOptionalIterable, 'reportOptionalIterable', 'none');
// Read the "reportUntypedFunctionDecorator" entry.
this.reportUntypedFunctionDecorator = this._convertDiagnosticLevel(
configObj.reportUntypedFunctionDecorator, 'reportUntypedFunctionDecorator', 'none');

View File

@ -36,3 +36,8 @@ if 1:
# this should generate an error.
c[2]
# If "reportOptionalIterable" is enabled,
# this should generate an error.
for val in c:
pass

View File

@ -198,15 +198,17 @@ test('Optional1', () => {
configOptions.reportOptionalSubscript = 'warning';
configOptions.reportOptionalMemberAccess = 'warning';
configOptions.reportOptionalCall = 'warning';
configOptions.reportOptionalIterable = 'warning';
analysisResults = TestUtils.typeAnalyzeSampleFiles(['optional1.py'], configOptions);
validateResults(analysisResults, 0, 3);
validateResults(analysisResults, 0, 4);
// Turn on errors.
configOptions.reportOptionalSubscript = 'error';
configOptions.reportOptionalMemberAccess = 'error';
configOptions.reportOptionalCall = 'error';
configOptions.reportOptionalIterable = 'error';
analysisResults = TestUtils.typeAnalyzeSampleFiles(['optional1.py'], configOptions);
validateResults(analysisResults, 3);
validateResults(analysisResults, 4);
});
test('Tuples1', () => {