Added "reportOptionalContextManager" config switch.

This commit is contained in:
Eric Traut 2019-04-18 19:59:59 -07:00
parent 6ecc499de7
commit 9a08af039f
6 changed files with 41 additions and 3 deletions

View File

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

View File

@ -44,6 +44,8 @@ The following settings control pyright's diagnostic output (warnings or errors).
**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'.
**reportOptionalContextManager** [boolean or string, optional]: Generate or suppress diagnostics for an attempt to use an Optional type as a context manager (as a parameter to a `with` 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

@ -623,7 +623,16 @@ export class TypeAnalyzer extends ParseTreeWalker {
});
node.withItems.forEach(item => {
const exprType = this._getTypeOfExpression(item.expression);
let exprType = this._getTypeOfExpression(item.expression);
if (exprType instanceof UnionType && exprType.getTypes().some(t => t instanceof NoneType)) {
this._addDiagnostic(
this._fileInfo.configOptions.reportOptionalContextManager,
`Object of type 'None' cannot be used with 'with'`,
node);
exprType = exprType.removeOptional();
}
const enterMethodName = node.isAsync ? '__aenter__' : '__enter__';
const scopedType = TypeUtils.doForSubtypes(exprType, subtype => {

View File

@ -100,6 +100,9 @@ export class ConfigOptions {
// Report attempts to use an Optional type as an iterable?
reportOptionalIterable: DiagnosticLevel = 'none';
// Report attempts to use an Optional type in a "with" statement?
reportOptionalContextManager: DiagnosticLevel = 'none';
// Report untyped function decorators that obscure the function type?
reportUntypedFunctionDecorator: DiagnosticLevel = 'none';
@ -245,6 +248,10 @@ export class ConfigOptions {
this.reportOptionalIterable = this._convertDiagnosticLevel(
configObj.reportOptionalIterable, 'reportOptionalIterable', 'none');
// Read the "reportOptionalContextManager" entry.
this.reportOptionalContextManager = this._convertDiagnosticLevel(
configObj.reportOptionalContextManager, 'reportOptionalContextManager', 'none');
// Read the "reportUntypedFunctionDecorator" entry.
this.reportUntypedFunctionDecorator = this._convertDiagnosticLevel(
configObj.reportUntypedFunctionDecorator, 'reportUntypedFunctionDecorator', 'none');

View File

@ -7,6 +7,9 @@ class Foo:
def do_stuff(self):
pass
def __enter__(self):
return 3
a = None
if 1:
a = Foo()
@ -41,3 +44,12 @@ c[2]
# this should generate an error.
for val in c:
pass
# If "reportOptionalContextManager" is enabled,
# this should generate an error.
cm = None
if 1:
cm = Foo()
with cm as val:
pass

View File

@ -199,16 +199,18 @@ test('Optional1', () => {
configOptions.reportOptionalMemberAccess = 'warning';
configOptions.reportOptionalCall = 'warning';
configOptions.reportOptionalIterable = 'warning';
configOptions.reportOptionalContextManager = 'warning';
analysisResults = TestUtils.typeAnalyzeSampleFiles(['optional1.py'], configOptions);
validateResults(analysisResults, 0, 4);
validateResults(analysisResults, 0, 5);
// Turn on errors.
configOptions.reportOptionalSubscript = 'error';
configOptions.reportOptionalMemberAccess = 'error';
configOptions.reportOptionalCall = 'error';
configOptions.reportOptionalIterable = 'error';
configOptions.reportOptionalContextManager = 'error';
analysisResults = TestUtils.typeAnalyzeSampleFiles(['optional1.py'], configOptions);
validateResults(analysisResults, 4);
validateResults(analysisResults, 5);
});
test('Private1', () => {