From f48f8856f7111c55cba060380ca3c0089b8ef916 Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Fri, 15 Feb 2013 18:21:25 +0100 Subject: [PATCH 1/9] SOE protection in PyPathEvaluator wasn't complete (PY-8880) --- .../src/com/jetbrains/python/psi/impl/PyPathEvaluator.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/python/src/com/jetbrains/python/psi/impl/PyPathEvaluator.java b/python/src/com/jetbrains/python/psi/impl/PyPathEvaluator.java index bb3e2257e688..ce8e00216acb 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyPathEvaluator.java +++ b/python/src/com/jetbrains/python/psi/impl/PyPathEvaluator.java @@ -43,7 +43,7 @@ public class PyPathEvaluator { return argValue == null ? null : new File(argValue).getParent(); } else if (call.isCalleeText(PyNames.JOIN) && args.length >= 1) { - return evaluatePathInJoin(containingFilePath, args, args.length); + return evaluatePathInJoin(containingFilePath, args, args.length, visited); } else if (call.isCalleeText(PyNames.ABSPATH) && args.length == 1) { String argValue = evaluate(args[0], containingFilePath, visited); @@ -97,10 +97,10 @@ public class PyPathEvaluator { return null; } - public static String evaluatePathInJoin(String containingFilePath, PyExpression[] args, int endElement) { + public static String evaluatePathInJoin(String containingFilePath, PyExpression[] args, int endElement, Set visited) { String result = null; for (int i = 0; i < endElement; i++) { - String arg = evaluate(args[i], containingFilePath, new HashSet()); + String arg = evaluate(args[i], containingFilePath, visited); if (arg == null) { return null; } From ad6105d2f6419bb7715dc074a9c16ade593f0f85 Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Fri, 15 Feb 2013 18:41:08 +0100 Subject: [PATCH 2/9] Don't report pep8.py issue about tabs if code style settings use tabs (PY-8864) --- .../validation/Pep8ExternalAnnotator.java | 23 +++++++++++++------ 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/python/src/com/jetbrains/python/validation/Pep8ExternalAnnotator.java b/python/src/com/jetbrains/python/validation/Pep8ExternalAnnotator.java index 98fd2eb652e3..136b9f76efdb 100644 --- a/python/src/com/jetbrains/python/validation/Pep8ExternalAnnotator.java +++ b/python/src/com/jetbrains/python/validation/Pep8ExternalAnnotator.java @@ -143,13 +143,7 @@ public class Pep8ExternalAnnotator extends ExternalAnnotator Date: Fri, 15 Feb 2013 19:10:21 +0100 Subject: [PATCH 3/9] align children of generator expressions (PY-8822) --- python/src/com/jetbrains/python/formatter/PyBlock.java | 3 ++- python/testData/formatter/alignInGenerators.py | 6 ++++++ python/testData/formatter/alignInGenerators_after.py | 6 ++++++ python/testSrc/com/jetbrains/python/PyFormatterTest.java | 4 ++++ 4 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 python/testData/formatter/alignInGenerators.py create mode 100644 python/testData/formatter/alignInGenerators_after.py diff --git a/python/src/com/jetbrains/python/formatter/PyBlock.java b/python/src/com/jetbrains/python/formatter/PyBlock.java index 5f9cd0d0f834..5519949e3f4b 100644 --- a/python/src/com/jetbrains/python/formatter/PyBlock.java +++ b/python/src/com/jetbrains/python/formatter/PyBlock.java @@ -53,7 +53,8 @@ public class PyBlock implements ASTBlock { PyElementTypes.TUPLE_EXPRESSION, PyElementTypes.PARENTHESIZED_EXPRESSION, PyElementTypes.SLICE_EXPRESSION, - PyElementTypes.SUBSCRIPTION_EXPRESSION); + PyElementTypes.SUBSCRIPTION_EXPRESSION, + PyElementTypes.GENERATOR_EXPRESSION); private static final TokenSet ourBrackets = TokenSet.create(PyTokenTypes.LPAR, PyTokenTypes.RPAR, PyTokenTypes.LBRACE, PyTokenTypes.RBRACE, diff --git a/python/testData/formatter/alignInGenerators.py b/python/testData/formatter/alignInGenerators.py new file mode 100644 index 000000000000..dfb98a3833ea --- /dev/null +++ b/python/testData/formatter/alignInGenerators.py @@ -0,0 +1,6 @@ +def supprice(): + if True: + if True: + agdrn = sum(VARS[drn + price] * md.c[drn][1] * md.c[drn][3] * + exp(md.c[drn][2] * VARS['SEEPAGE'] - md.c[drn][3] * pmp) + for drn in md.agdrn_nodes if drn in md.c) diff --git a/python/testData/formatter/alignInGenerators_after.py b/python/testData/formatter/alignInGenerators_after.py new file mode 100644 index 000000000000..921598625224 --- /dev/null +++ b/python/testData/formatter/alignInGenerators_after.py @@ -0,0 +1,6 @@ +def supprice(): + if True: + if True: + agdrn = sum(VARS[drn + price] * md.c[drn][1] * md.c[drn][3] * + exp(md.c[drn][2] * VARS['SEEPAGE'] - md.c[drn][3] * pmp) + for drn in md.agdrn_nodes if drn in md.c) diff --git a/python/testSrc/com/jetbrains/python/PyFormatterTest.java b/python/testSrc/com/jetbrains/python/PyFormatterTest.java index f17d0a2ecd63..7da411bbb1ea 100644 --- a/python/testSrc/com/jetbrains/python/PyFormatterTest.java +++ b/python/testSrc/com/jetbrains/python/PyFormatterTest.java @@ -260,6 +260,10 @@ public class PyFormatterTest extends PyTestCase { doTest(); } + public void testAlignInGenerators() { // PY-8822 + doTest(); + } + public void testContinuationIndentForCallInStatementPart() { // PY-8577 doTest(); } From 7ebf23490f6a61030c815f1c3e7e6290c2b55da1 Mon Sep 17 00:00:00 2001 From: Andrey Vlasovskikh Date: Fri, 15 Feb 2013 22:46:20 +0400 Subject: [PATCH 4/9] Split Python unbound variable tests into separate test cases (CR-PY-5855) --- .../BuiltinAndSelfAttribute.py | 3 + .../ClassLevelSameName.py | 9 + .../ControlFlowInAssert.py | 10 + .../ControlFlowInTryExceptFinally.py | 20 ++ .../DecoratorAndParameter.py | 7 + .../DefaultArgument.py | 5 + .../DefinedInTryAndExcept.py | 8 + .../DefinedInTryElse.py | 9 + .../DefinedInTryUsedAfter.py | 6 + .../ForBreakElse.py | 8 + .../ImplicitIfNotNone.py | 6 + .../InstanceAttributeOutsideClass.py | 11 ++ .../InstanceFieldAndGlobal.py | 5 + .../LocalFunctionAndVariable.py | 4 + .../OuterFunctionsAndSelfAttributes.py | 13 ++ .../ParamAfterTryExcept.py | 6 + .../Simple.py | 30 +++ .../StarImportTopLevel.py | 2 + .../SysExit.py | 3 + .../UnboundAugmentedAssignment.py | 5 + .../UnboundConditionalImport.py | 4 + .../UnboundConditionalImportAlias.py | 6 + .../UnboundConditionalImportQualified.py | 6 + .../UnboundDefinedInTryUsedAfterExcept.py | 6 + .../UnboundExceptAs.py | 6 + .../UnboundLoopVariable.py | 3 + .../UnboundNestedComprehension.py | 4 + .../UnboundNonLocal.py | 24 +++ .../UnboundSwapStrUnicode.py | 7 + .../UnboundVariableFunctionCall.py | 7 + .../UseAfterWithAndRaise.py | 7 + .../expected.xml | 58 ------ .../jetbrains/python/PythonAllTestsSuite.java | 1 + .../python/PythonInspectionsTest.java | 10 - .../PyUnboundLocalVariableInspectionTest.java | 181 ++++++++++++++++++ 35 files changed, 432 insertions(+), 68 deletions(-) create mode 100644 python/testData/inspections/PyUnboundLocalVariableInspection/BuiltinAndSelfAttribute.py create mode 100644 python/testData/inspections/PyUnboundLocalVariableInspection/ClassLevelSameName.py create mode 100644 python/testData/inspections/PyUnboundLocalVariableInspection/ControlFlowInAssert.py create mode 100644 python/testData/inspections/PyUnboundLocalVariableInspection/ControlFlowInTryExceptFinally.py create mode 100644 python/testData/inspections/PyUnboundLocalVariableInspection/DecoratorAndParameter.py create mode 100644 python/testData/inspections/PyUnboundLocalVariableInspection/DefaultArgument.py create mode 100644 python/testData/inspections/PyUnboundLocalVariableInspection/DefinedInTryAndExcept.py create mode 100644 python/testData/inspections/PyUnboundLocalVariableInspection/DefinedInTryElse.py create mode 100644 python/testData/inspections/PyUnboundLocalVariableInspection/DefinedInTryUsedAfter.py create mode 100644 python/testData/inspections/PyUnboundLocalVariableInspection/ForBreakElse.py create mode 100644 python/testData/inspections/PyUnboundLocalVariableInspection/ImplicitIfNotNone.py create mode 100644 python/testData/inspections/PyUnboundLocalVariableInspection/InstanceAttributeOutsideClass.py create mode 100644 python/testData/inspections/PyUnboundLocalVariableInspection/InstanceFieldAndGlobal.py create mode 100644 python/testData/inspections/PyUnboundLocalVariableInspection/LocalFunctionAndVariable.py create mode 100644 python/testData/inspections/PyUnboundLocalVariableInspection/OuterFunctionsAndSelfAttributes.py create mode 100644 python/testData/inspections/PyUnboundLocalVariableInspection/ParamAfterTryExcept.py create mode 100644 python/testData/inspections/PyUnboundLocalVariableInspection/Simple.py create mode 100644 python/testData/inspections/PyUnboundLocalVariableInspection/StarImportTopLevel.py create mode 100644 python/testData/inspections/PyUnboundLocalVariableInspection/SysExit.py create mode 100644 python/testData/inspections/PyUnboundLocalVariableInspection/UnboundAugmentedAssignment.py create mode 100644 python/testData/inspections/PyUnboundLocalVariableInspection/UnboundConditionalImport.py create mode 100644 python/testData/inspections/PyUnboundLocalVariableInspection/UnboundConditionalImportAlias.py create mode 100644 python/testData/inspections/PyUnboundLocalVariableInspection/UnboundConditionalImportQualified.py create mode 100644 python/testData/inspections/PyUnboundLocalVariableInspection/UnboundDefinedInTryUsedAfterExcept.py create mode 100644 python/testData/inspections/PyUnboundLocalVariableInspection/UnboundExceptAs.py create mode 100644 python/testData/inspections/PyUnboundLocalVariableInspection/UnboundLoopVariable.py create mode 100644 python/testData/inspections/PyUnboundLocalVariableInspection/UnboundNestedComprehension.py create mode 100644 python/testData/inspections/PyUnboundLocalVariableInspection/UnboundNonLocal.py create mode 100644 python/testData/inspections/PyUnboundLocalVariableInspection/UnboundSwapStrUnicode.py create mode 100644 python/testData/inspections/PyUnboundLocalVariableInspection/UnboundVariableFunctionCall.py create mode 100644 python/testData/inspections/PyUnboundLocalVariableInspection/UseAfterWithAndRaise.py delete mode 100644 python/testData/inspections/PyUnboundLocalVariableInspection/expected.xml create mode 100644 python/testSrc/com/jetbrains/python/inspections/PyUnboundLocalVariableInspectionTest.java diff --git a/python/testData/inspections/PyUnboundLocalVariableInspection/BuiltinAndSelfAttribute.py b/python/testData/inspections/PyUnboundLocalVariableInspection/BuiltinAndSelfAttribute.py new file mode 100644 index 000000000000..692aee71f830 --- /dev/null +++ b/python/testData/inspections/PyUnboundLocalVariableInspection/BuiltinAndSelfAttribute.py @@ -0,0 +1,3 @@ +class C(): + def __init__(self): + self.str = str(1) #pass diff --git a/python/testData/inspections/PyUnboundLocalVariableInspection/ClassLevelSameName.py b/python/testData/inspections/PyUnboundLocalVariableInspection/ClassLevelSameName.py new file mode 100644 index 000000000000..51f0f8eee285 --- /dev/null +++ b/python/testData/inspections/PyUnboundLocalVariableInspection/ClassLevelSameName.py @@ -0,0 +1,9 @@ +local_var = "foo" + +class C: + local_var = local_var #pass + + def foo(self): + print(self.local_var) + +C().foo() diff --git a/python/testData/inspections/PyUnboundLocalVariableInspection/ControlFlowInAssert.py b/python/testData/inspections/PyUnboundLocalVariableInspection/ControlFlowInAssert.py new file mode 100644 index 000000000000..b1cc192e89fb --- /dev/null +++ b/python/testData/inspections/PyUnboundLocalVariableInspection/ControlFlowInAssert.py @@ -0,0 +1,10 @@ +# PY-1138 +from models import ChartRequest +from components.dbutil import DbSession + +def foo(requestId): + with DbSession() as db: + req = db.query(ChartRequest).get(requestId) + assert req is not None, u"Invalid request" + print req + diff --git a/python/testData/inspections/PyUnboundLocalVariableInspection/ControlFlowInTryExceptFinally.py b/python/testData/inspections/PyUnboundLocalVariableInspection/ControlFlowInTryExceptFinally.py new file mode 100644 index 000000000000..40152671fb74 --- /dev/null +++ b/python/testData/inspections/PyUnboundLocalVariableInspection/ControlFlowInTryExceptFinally.py @@ -0,0 +1,20 @@ +def foo1(): + a = 1 + try: + for i in range(10): + pass + except Exception: + pass + finally: + b = a #pass + + +def foo2(): + a = 1 + try: + for i in range(10): + pass + except Exception: + c = a #pass + finally: + b = a #pass diff --git a/python/testData/inspections/PyUnboundLocalVariableInspection/DecoratorAndParameter.py b/python/testData/inspections/PyUnboundLocalVariableInspection/DecoratorAndParameter.py new file mode 100644 index 000000000000..634add70d057 --- /dev/null +++ b/python/testData/inspections/PyUnboundLocalVariableInspection/DecoratorAndParameter.py @@ -0,0 +1,7 @@ +def f(x): + def d(f): + return f + @d #pass + def g(d): + return d + return g(x) diff --git a/python/testData/inspections/PyUnboundLocalVariableInspection/DefaultArgument.py b/python/testData/inspections/PyUnboundLocalVariableInspection/DefaultArgument.py new file mode 100644 index 000000000000..a7843f01f1e1 --- /dev/null +++ b/python/testData/inspections/PyUnboundLocalVariableInspection/DefaultArgument.py @@ -0,0 +1,5 @@ +def f(): + z = 2 + def g(z=z): #pass + return z + return g diff --git a/python/testData/inspections/PyUnboundLocalVariableInspection/DefinedInTryAndExcept.py b/python/testData/inspections/PyUnboundLocalVariableInspection/DefinedInTryAndExcept.py new file mode 100644 index 000000000000..02ba98741f5d --- /dev/null +++ b/python/testData/inspections/PyUnboundLocalVariableInspection/DefinedInTryAndExcept.py @@ -0,0 +1,8 @@ +def f(g): + try: + x = g() + except Exception: + x = g() + finally: + pass + print(x) #pass diff --git a/python/testData/inspections/PyUnboundLocalVariableInspection/DefinedInTryElse.py b/python/testData/inspections/PyUnboundLocalVariableInspection/DefinedInTryElse.py new file mode 100644 index 000000000000..f30273ba7515 --- /dev/null +++ b/python/testData/inspections/PyUnboundLocalVariableInspection/DefinedInTryElse.py @@ -0,0 +1,9 @@ +def f(g): + x = 1 + try: + pass + except Exception: + pass + else: + x = g() + print(x) #pass diff --git a/python/testData/inspections/PyUnboundLocalVariableInspection/DefinedInTryUsedAfter.py b/python/testData/inspections/PyUnboundLocalVariableInspection/DefinedInTryUsedAfter.py new file mode 100644 index 000000000000..415aef387c27 --- /dev/null +++ b/python/testData/inspections/PyUnboundLocalVariableInspection/DefinedInTryUsedAfter.py @@ -0,0 +1,6 @@ +def f(): + try: + result = bool(2) + finally: + pass + return result #pass diff --git a/python/testData/inspections/PyUnboundLocalVariableInspection/ForBreakElse.py b/python/testData/inspections/PyUnboundLocalVariableInspection/ForBreakElse.py new file mode 100644 index 000000000000..d78ceb9499f4 --- /dev/null +++ b/python/testData/inspections/PyUnboundLocalVariableInspection/ForBreakElse.py @@ -0,0 +1,8 @@ +def f(c): + for i in [1, 2, 3]: + if c: + x = 0 + break + else: + x = 1 + return x #pass diff --git a/python/testData/inspections/PyUnboundLocalVariableInspection/ImplicitIfNotNone.py b/python/testData/inspections/PyUnboundLocalVariableInspection/ImplicitIfNotNone.py new file mode 100644 index 000000000000..117517b7b10b --- /dev/null +++ b/python/testData/inspections/PyUnboundLocalVariableInspection/ImplicitIfNotNone.py @@ -0,0 +1,6 @@ +foo = True + + +def bar(): + if foo: #pass + print 1 diff --git a/python/testData/inspections/PyUnboundLocalVariableInspection/InstanceAttributeOutsideClass.py b/python/testData/inspections/PyUnboundLocalVariableInspection/InstanceAttributeOutsideClass.py new file mode 100644 index 000000000000..5fc2a210625a --- /dev/null +++ b/python/testData/inspections/PyUnboundLocalVariableInspection/InstanceAttributeOutsideClass.py @@ -0,0 +1,11 @@ +class C(object): + pass + + +class D(object): + def f(self): + def g(x): + x = C() + x.y = 1 #pass + return x + return g diff --git a/python/testData/inspections/PyUnboundLocalVariableInspection/InstanceFieldAndGlobal.py b/python/testData/inspections/PyUnboundLocalVariableInspection/InstanceFieldAndGlobal.py new file mode 100644 index 000000000000..e4122018fc1e --- /dev/null +++ b/python/testData/inspections/PyUnboundLocalVariableInspection/InstanceFieldAndGlobal.py @@ -0,0 +1,5 @@ +x = 1 + +class C: + def __init__(self): + self.x = x #pass diff --git a/python/testData/inspections/PyUnboundLocalVariableInspection/LocalFunctionAndVariable.py b/python/testData/inspections/PyUnboundLocalVariableInspection/LocalFunctionAndVariable.py new file mode 100644 index 000000000000..8c38281c6710 --- /dev/null +++ b/python/testData/inspections/PyUnboundLocalVariableInspection/LocalFunctionAndVariable.py @@ -0,0 +1,4 @@ +def x(arg): + def foo(): pass + if arg: foo = None + callee(foo) #pass diff --git a/python/testData/inspections/PyUnboundLocalVariableInspection/OuterFunctionsAndSelfAttributes.py b/python/testData/inspections/PyUnboundLocalVariableInspection/OuterFunctionsAndSelfAttributes.py new file mode 100644 index 000000000000..d2cd736c4d30 --- /dev/null +++ b/python/testData/inspections/PyUnboundLocalVariableInspection/OuterFunctionsAndSelfAttributes.py @@ -0,0 +1,13 @@ +def g(): + pass + + +class C: + pass + + +class D: + def m(self): + self.g = g() #pass + self.C = C() #pass + diff --git a/python/testData/inspections/PyUnboundLocalVariableInspection/ParamAfterTryExcept.py b/python/testData/inspections/PyUnboundLocalVariableInspection/ParamAfterTryExcept.py new file mode 100644 index 000000000000..608548faa78b --- /dev/null +++ b/python/testData/inspections/PyUnboundLocalVariableInspection/ParamAfterTryExcept.py @@ -0,0 +1,6 @@ +def f(x): + try: + pass + except Exception: + pass + print(x) #pass diff --git a/python/testData/inspections/PyUnboundLocalVariableInspection/Simple.py b/python/testData/inspections/PyUnboundLocalVariableInspection/Simple.py new file mode 100644 index 000000000000..040d2335ac90 --- /dev/null +++ b/python/testData/inspections/PyUnboundLocalVariableInspection/Simple.py @@ -0,0 +1,30 @@ +a = 1 + +def foo(): + print(a) #fail + a = 21 + print(a) #pass + + +foo() +print(a) + +if bla_bla(): #pass + b = 1 +print(b) #fail +print(b) #pass +c = 1 + +def buzz(): + print(c) #pass + +buzz() + +print BLA_BLA_BLA #pass + +if foo(): + d = 1 +else: + d = 2 + +print(d) #pass diff --git a/python/testData/inspections/PyUnboundLocalVariableInspection/StarImportTopLevel.py b/python/testData/inspections/PyUnboundLocalVariableInspection/StarImportTopLevel.py new file mode 100644 index 000000000000..2def04cfae38 --- /dev/null +++ b/python/testData/inspections/PyUnboundLocalVariableInspection/StarImportTopLevel.py @@ -0,0 +1,2 @@ +from re import * +print(UNICODE) diff --git a/python/testData/inspections/PyUnboundLocalVariableInspection/SysExit.py b/python/testData/inspections/PyUnboundLocalVariableInspection/SysExit.py new file mode 100644 index 000000000000..36513e13a8b1 --- /dev/null +++ b/python/testData/inspections/PyUnboundLocalVariableInspection/SysExit.py @@ -0,0 +1,3 @@ +def f(): + import sys + sys.exit(1) #pass diff --git a/python/testData/inspections/PyUnboundLocalVariableInspection/UnboundAugmentedAssignment.py b/python/testData/inspections/PyUnboundLocalVariableInspection/UnboundAugmentedAssignment.py new file mode 100644 index 000000000000..539cc26f7ee6 --- /dev/null +++ b/python/testData/inspections/PyUnboundLocalVariableInspection/UnboundAugmentedAssignment.py @@ -0,0 +1,5 @@ +def f(c): + if c: + x = 1 + x += 1 #fail + return x diff --git a/python/testData/inspections/PyUnboundLocalVariableInspection/UnboundConditionalImport.py b/python/testData/inspections/PyUnboundLocalVariableInspection/UnboundConditionalImport.py new file mode 100644 index 000000000000..978e0861ab60 --- /dev/null +++ b/python/testData/inspections/PyUnboundLocalVariableInspection/UnboundConditionalImport.py @@ -0,0 +1,4 @@ +def f(c): + if c: + import sys + return sys diff --git a/python/testData/inspections/PyUnboundLocalVariableInspection/UnboundConditionalImportAlias.py b/python/testData/inspections/PyUnboundLocalVariableInspection/UnboundConditionalImportAlias.py new file mode 100644 index 000000000000..d867d1f49287 --- /dev/null +++ b/python/testData/inspections/PyUnboundLocalVariableInspection/UnboundConditionalImportAlias.py @@ -0,0 +1,6 @@ +def f(c, x): + if c: + from re import compile as g + else: + pass + return g(x) #fail diff --git a/python/testData/inspections/PyUnboundLocalVariableInspection/UnboundConditionalImportQualified.py b/python/testData/inspections/PyUnboundLocalVariableInspection/UnboundConditionalImportQualified.py new file mode 100644 index 000000000000..1e40687e3dab --- /dev/null +++ b/python/testData/inspections/PyUnboundLocalVariableInspection/UnboundConditionalImportQualified.py @@ -0,0 +1,6 @@ +def f(c, x): + if c: + import os.path + else: + pass + return os.path.isfile(x) #fail diff --git a/python/testData/inspections/PyUnboundLocalVariableInspection/UnboundDefinedInTryUsedAfterExcept.py b/python/testData/inspections/PyUnboundLocalVariableInspection/UnboundDefinedInTryUsedAfterExcept.py new file mode 100644 index 000000000000..4afc68009bd3 --- /dev/null +++ b/python/testData/inspections/PyUnboundLocalVariableInspection/UnboundDefinedInTryUsedAfterExcept.py @@ -0,0 +1,6 @@ +def a2(): + try: + a = 2 + except Exception: + pass + print(a) #fail diff --git a/python/testData/inspections/PyUnboundLocalVariableInspection/UnboundExceptAs.py b/python/testData/inspections/PyUnboundLocalVariableInspection/UnboundExceptAs.py new file mode 100644 index 000000000000..e9682e0b75b8 --- /dev/null +++ b/python/testData/inspections/PyUnboundLocalVariableInspection/UnboundExceptAs.py @@ -0,0 +1,6 @@ +def f(): + try: + raise KeyError("ms") + except KeyError as e: + print(e) #pass + print(e) #fail diff --git a/python/testData/inspections/PyUnboundLocalVariableInspection/UnboundLoopVariable.py b/python/testData/inspections/PyUnboundLocalVariableInspection/UnboundLoopVariable.py new file mode 100644 index 000000000000..c3bc9d70f3b5 --- /dev/null +++ b/python/testData/inspections/PyUnboundLocalVariableInspection/UnboundLoopVariable.py @@ -0,0 +1,3 @@ +for i, x in enumerate([]): + print(i, x) +print(i) # fail diff --git a/python/testData/inspections/PyUnboundLocalVariableInspection/UnboundNestedComprehension.py b/python/testData/inspections/PyUnboundLocalVariableInspection/UnboundNestedComprehension.py new file mode 100644 index 000000000000..22f0a87065cb --- /dev/null +++ b/python/testData/inspections/PyUnboundLocalVariableInspection/UnboundNestedComprehension.py @@ -0,0 +1,4 @@ +def f(xs): + # vs is unbound + return [(k, v) for v in vs + for k, vs in xs.items()] diff --git a/python/testData/inspections/PyUnboundLocalVariableInspection/UnboundNonLocal.py b/python/testData/inspections/PyUnboundLocalVariableInspection/UnboundNonLocal.py new file mode 100644 index 000000000000..3d1307090707 --- /dev/null +++ b/python/testData/inspections/PyUnboundLocalVariableInspection/UnboundNonLocal.py @@ -0,0 +1,24 @@ +def f1(): + nonlocal x #fail + + +def f2(): + def g(): + nonlocal x #fail + print(x) + + +x = 1 + +def f3(): + nonlocal x #fail + x = 2 + + +def f4(): + x = 0 + def g(): + nonlocal x #pass + x = 2 + return x + return g() diff --git a/python/testData/inspections/PyUnboundLocalVariableInspection/UnboundSwapStrUnicode.py b/python/testData/inspections/PyUnboundLocalVariableInspection/UnboundSwapStrUnicode.py new file mode 100644 index 000000000000..090eb744fbea --- /dev/null +++ b/python/testData/inspections/PyUnboundLocalVariableInspection/UnboundSwapStrUnicode.py @@ -0,0 +1,7 @@ +def f(): + bytes, str = str, unicode #fail + +class C(object): + bytes, str = str, unicode #pass + +bytes, str = str, unicode #pass diff --git a/python/testData/inspections/PyUnboundLocalVariableInspection/UnboundVariableFunctionCall.py b/python/testData/inspections/PyUnboundLocalVariableInspection/UnboundVariableFunctionCall.py new file mode 100644 index 000000000000..6a39f123b805 --- /dev/null +++ b/python/testData/inspections/PyUnboundLocalVariableInspection/UnboundVariableFunctionCall.py @@ -0,0 +1,7 @@ +def f(g, h, x): + if x > 1: + z = g + elif x: + z = h + # local z may be unbound, inspection fails only when z is in function call + return z() #fail diff --git a/python/testData/inspections/PyUnboundLocalVariableInspection/UseAfterWithAndRaise.py b/python/testData/inspections/PyUnboundLocalVariableInspection/UseAfterWithAndRaise.py new file mode 100644 index 000000000000..f49b37e01a5c --- /dev/null +++ b/python/testData/inspections/PyUnboundLocalVariableInspection/UseAfterWithAndRaise.py @@ -0,0 +1,7 @@ +def f(y, c, xs): + if c: + raise Exception() + for x in xs: + with y: + pass + print(x) #pass diff --git a/python/testData/inspections/PyUnboundLocalVariableInspection/expected.xml b/python/testData/inspections/PyUnboundLocalVariableInspection/expected.xml deleted file mode 100644 index 5aaae21724f3..000000000000 --- a/python/testData/inspections/PyUnboundLocalVariableInspection/expected.xml +++ /dev/null @@ -1,58 +0,0 @@ - - - - test.py - 4 - "Local variable 'a' might be referenced before assignment" - - - test.py - 14 - "Name 'b' can be not defined" - - - test.py - 51 - "Name 'i' can be not defined" - - - test.py - 77 - "Local variable 'z' might be referenced before assignment" - - - test.py - 83 - "Local variable 'vs' might be referenced before assignment" - - - test.py - 123 - "Local variable 'sys' might be referenced before assignment" - - - test.py - 132 - "Local variable 'g' might be referenced before assignment" - - - test.py - 141 - "Local variable 'os' might be referenced before assignment" - - - test.py - 148 - "Local variable 'x' might be referenced before assignment" - - - test.py - 192 - "Local variable 'a' might be referenced before assignment" - - - test.py - 220 - "Local variable 'str' might be referenced before assignment" - - \ No newline at end of file diff --git a/python/testSrc/com/jetbrains/python/PythonAllTestsSuite.java b/python/testSrc/com/jetbrains/python/PythonAllTestsSuite.java index 78950a0aa6ab..7439dddfc5fa 100644 --- a/python/testSrc/com/jetbrains/python/PythonAllTestsSuite.java +++ b/python/testSrc/com/jetbrains/python/PythonAllTestsSuite.java @@ -94,6 +94,7 @@ public class PythonAllTestsSuite { PyCompatibilityInspectionTest.class, PyUnresolvedReferencesInspectionTest.class, PyCallingNonCallableInspectionTest.class, + PyUnboundLocalVariableInspectionTest.class, PyUnusedImportTest.class, PyDeprecationTest.class, PythonHighlightingLexerTest.class, diff --git a/python/testSrc/com/jetbrains/python/PythonInspectionsTest.java b/python/testSrc/com/jetbrains/python/PythonInspectionsTest.java index 3d453c1b101e..0ed83ce7872c 100644 --- a/python/testSrc/com/jetbrains/python/PythonInspectionsTest.java +++ b/python/testSrc/com/jetbrains/python/PythonInspectionsTest.java @@ -129,16 +129,6 @@ public class PythonInspectionsTest extends PyTestCase { doTestWithLanguageLevel(getTestName(false), inspection, LanguageLevel.PYTHON24); } - public void testPyUnboundLocalVariableInspection() { - LocalInspectionTool inspection = new PyUnboundLocalVariableInspection(); - doTestWithLanguageLevel(getTestName(false), inspection, LanguageLevel.PYTHON27); - } - - public void testPyUnboundLocalVariableInspectionPy3k() { - LocalInspectionTool inspection = new PyUnboundLocalVariableInspection(); - doTestWithPy3k(getTestName(false), inspection); - } - public void testPyDocstringInspection() { LocalInspectionTool inspection = new PyDocstringInspection(); doTest(getTestName(false), inspection); diff --git a/python/testSrc/com/jetbrains/python/inspections/PyUnboundLocalVariableInspectionTest.java b/python/testSrc/com/jetbrains/python/inspections/PyUnboundLocalVariableInspectionTest.java new file mode 100644 index 000000000000..b46fb6c655fa --- /dev/null +++ b/python/testSrc/com/jetbrains/python/inspections/PyUnboundLocalVariableInspectionTest.java @@ -0,0 +1,181 @@ +package com.jetbrains.python.inspections; + +import com.jetbrains.python.fixtures.PyTestCase; +import com.jetbrains.python.psi.LanguageLevel; + +/** + * @author vlan + */ +public class PyUnboundLocalVariableInspectionTest extends PyTestCase { + private static final String TEST_DIRECTORY = "inspections/PyUnboundLocalVariableInspection/"; + + public void testSimple() { + doTest(); + } + + // PY-1138 + public void testControlFlowInAssert() { + doTest(); + } + + // PY-1176 + public void testLocalFunctionAndVariable() { + doTest(); + } + + // PY-1359 + public void testUnboundLoopVariable() { + doTest(); + } + + // PY-1408 + public void testUnboundExceptAs() { + runWithLanguageLevel(LanguageLevel.PYTHON33, new Runnable() { + @Override + public void run() { + doTest(); + } + }); + } + + // PY-1434 + public void testClassLevelSameName() { + doTest(); + } + + // PY-1435 + public void testInstanceFieldAndGlobal() { + doTest(); + } + + // PY-3343 + public void testUnboundVariableFunctionCall() { + doTest(); + } + + // PY-3407 + public void testUnboundNestedComprehension() { + doTest(); + } + + // PY-3503 + public void testControlFlowInTryExceptFinally() { + doTest(); + } + + // PY-3550 + public void testDefaultArgument() { + doTest(); + } + + // PY-3583 + public void testUnboundConditionalImport() { + doTest(); + } + + // PY-3603 + public void testUnboundNonLocal() { + runWithLanguageLevel(LanguageLevel.PYTHON33, new Runnable() { + @Override + public void run() { + doTest(); + } + }); + } + + // PY-3671 + public void testUnboundConditionalImportAlias() { + doTest(); + } + + // PY-3665 + public void testUnboundConditionalImportQualified() { + doTest(); + } + + // PY-3651 + public void testUnboundAugmentedAssignment() { + doTest(); + } + + // PY-3702 + public void testSysExit() { + doTest(); + } + + // PY-3895 + public void testDecoratorAndParameter() { + doTest(); + } + + // PY-4102 + public void testDefinedInTryUsedAfter() { + doTest(); + } + + // PY-4150 + public void testParamAfterTryExcept() { + doTest(); + } + + // PY-4151 + public void testUnboundDefinedInTryUsedAfterExcept() { + doTest(); + } + + // PY-4152 + public void testDefinedInTryAndExcept() { + doTest(); + } + + // PY-4157 + public void testDefinedInTryElse() { + doTest(); + } + + // PY-4197 + public void testUnboundSwapStrUnicode() { + doTest(); + } + + // PY-4229 + public void testInstanceAttributeOutsideClass() { + doTest(); + } + + // PY-4297 + public void testOuterFunctionsAndSelfAttributes() { + doTest(); + } + + // PY-4623 + public void testBuiltinAndSelfAttribute() { + doTest(); + } + + // PY-4609 + public void testImplicitIfNotNone() { + doTest(); + } + + // PY-4239 + public void testForBreakElse() { + doTest(); + } + + // PY-5592 + public void testStarImportTopLevel() { + doTest(); + } + + // PY-7966 + public void testUseAfterWithAndRaise() { + doTest(); + } + + private void doTest() { + myFixture.configureByFile(TEST_DIRECTORY + getTestName(false) + ".py"); + myFixture.enableInspections(PyUnboundLocalVariableInspection.class); + myFixture.checkHighlighting(true, false, false); + } +} From 65e7a1990045bf3405327e57573aff0aafd47458 Mon Sep 17 00:00:00 2001 From: Andrey Vlasovskikh Date: Fri, 15 Feb 2013 23:03:30 +0400 Subject: [PATCH 5/9] Shorter token type and text comparison in Cython parser (CR-PY-5856) --- python/src/com/jetbrains/python/parsing/Parsing.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/python/src/com/jetbrains/python/parsing/Parsing.java b/python/src/com/jetbrains/python/parsing/Parsing.java index 1eb7b1a8136f..de5c0b14f302 100644 --- a/python/src/com/jetbrains/python/parsing/Parsing.java +++ b/python/src/com/jetbrains/python/parsing/Parsing.java @@ -5,6 +5,7 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.psi.tree.IElementType; import com.jetbrains.python.PyElementTypes; import com.jetbrains.python.psi.PyElementType; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; /** @@ -53,6 +54,10 @@ public class Parsing { return myBuilder.getTokenType() == tokenType; } + protected boolean atToken(@NotNull final IElementType tokenType, @NotNull String tokenText) { + return myBuilder.getTokenType() == tokenType && tokenText.equals(myBuilder.getTokenText()); + } + protected boolean atAnyOfTokens(final IElementType... tokenTypes) { IElementType currentTokenType = myBuilder.getTokenType(); for (IElementType tokenType : tokenTypes) { From 85aa4c864bb5fe19be9bf10c2aae548564a41b1d Mon Sep 17 00:00:00 2001 From: Andrey Vlasovskikh Date: Fri, 15 Feb 2013 23:19:22 +0400 Subject: [PATCH 6/9] Removed obsolete nullable check --- .../python/psi/impl/PyReferenceExpressionImpl.java | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/python/src/com/jetbrains/python/psi/impl/PyReferenceExpressionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyReferenceExpressionImpl.java index 4893d08920df..b0a37d92c3c9 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyReferenceExpressionImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyReferenceExpressionImpl.java @@ -65,15 +65,13 @@ public class PyReferenceExpressionImpl extends PyElementImpl implements PyRefere return PyImportReference.forElement(this, importParent, context); } - if (file != null) { - // Return special reference - final ConsoleCommunication communication = file.getCopyableUserData(PydevConsoleRunner.CONSOLE_KEY); - if (communication != null) { - if (qualifier != null) { - return new PydevConsoleReference(this, communication, qualifier.getText() + "."); - } - return new PydevConsoleReference(this, communication, ""); + // Return special reference + final ConsoleCommunication communication = file.getCopyableUserData(PydevConsoleRunner.CONSOLE_KEY); + if (communication != null) { + if (qualifier != null) { + return new PydevConsoleReference(this, communication, qualifier.getText() + "."); } + return new PydevConsoleReference(this, communication, ""); } if (qualifier != null) { From ae86efae04fa89af2c10a8c0a871f47427a02276 Mon Sep 17 00:00:00 2001 From: Andrey Vlasovskikh Date: Fri, 15 Feb 2013 23:43:30 +0400 Subject: [PATCH 7/9] Moved Cython built-ins check to a separate CythonReference class (CR-PY-5857) --- .../inspections/PyUnresolvedReferencesInspection.java | 8 -------- .../python/psi/impl/PyReferenceExpressionImpl.java | 8 +++++++- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/python/src/com/jetbrains/python/inspections/PyUnresolvedReferencesInspection.java b/python/src/com/jetbrains/python/inspections/PyUnresolvedReferencesInspection.java index 6e72ba6a4ef5..4fd8a4318a83 100644 --- a/python/src/com/jetbrains/python/inspections/PyUnresolvedReferencesInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyUnresolvedReferencesInspection.java @@ -17,8 +17,6 @@ import com.intellij.psi.*; import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.Consumer; -import com.jetbrains.cython.CythonLanguageDialect; -import com.jetbrains.cython.CythonNames; import com.jetbrains.cython.psi.CythonFile; import com.jetbrains.cython.types.CythonBuiltinType; import com.jetbrains.cython.types.CythonType; @@ -423,12 +421,6 @@ public class PyUnresolvedReferencesInspection extends PyInspection { if (PyNames.COMPARISON_OPERATORS.contains(refname)) { return; } - if (CythonLanguageDialect.isInsideCythonFile(element) && - (CythonNames.BASE_C_TYPES.contains(text) || - CythonNames.BASE_CYTHON_TYPES.contains(text) || - CythonNames.BUILTINS.contains(text))) { - return; - } if (refex.getQualifier() != null) { final PyClassTypeImpl object_type = (PyClassTypeImpl)PyBuiltinCache.getInstance(node).getObjectType(); if ((object_type != null) && object_type.getPossibleInstanceMembers().contains(refname)) return; diff --git a/python/src/com/jetbrains/python/psi/impl/PyReferenceExpressionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyReferenceExpressionImpl.java index b0a37d92c3c9..62c950ba96e9 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyReferenceExpressionImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyReferenceExpressionImpl.java @@ -10,6 +10,7 @@ import com.jetbrains.cython.CythonLanguageDialect; import com.jetbrains.cython.psi.CythonCImportElement; import com.jetbrains.cython.psi.CythonFromCImportStatement; import com.jetbrains.cython.psi.CythonImportReference; +import com.jetbrains.cython.psi.CythonReference; import com.jetbrains.python.PyNames; import com.jetbrains.python.PyTokenTypes; import com.jetbrains.python.PythonDialectsTokenSetProvider; @@ -55,7 +56,8 @@ public class PyReferenceExpressionImpl extends PyElementImpl implements PyRefere final PyExpression qualifier = getQualifier(); // Handle import reference - if (CythonLanguageDialect.isInsideCythonFile(this)) { + final boolean inCythonFile = CythonLanguageDialect.isInsideCythonFile(this); + if (inCythonFile) { if (PsiTreeUtil.getParentOfType(this, CythonCImportElement.class, CythonFromCImportStatement.class) != null) { return new CythonImportReference(this, context); } @@ -78,6 +80,10 @@ public class PyReferenceExpressionImpl extends PyElementImpl implements PyRefere return new PyQualifiedReference(this, context); } + if (inCythonFile) { + return new CythonReference(this, context); + } + return new PyReferenceImpl(this, context); } From 756caa374b0b6b671d7ad3f6a547530fccb6bf56 Mon Sep 17 00:00:00 2001 From: Dmitry Trofimov Date: Sat, 16 Feb 2013 21:40:58 +0100 Subject: [PATCH 8/9] Python debugger: set socket timeout. --- .../com/jetbrains/python/debugger/pydev/RemoteDebugger.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/python/pydevSrc/com/jetbrains/python/debugger/pydev/RemoteDebugger.java b/python/pydevSrc/com/jetbrains/python/debugger/pydev/RemoteDebugger.java index 65082a233281..711c08216d9f 100644 --- a/python/pydevSrc/com/jetbrains/python/debugger/pydev/RemoteDebugger.java +++ b/python/pydevSrc/com/jetbrains/python/debugger/pydev/RemoteDebugger.java @@ -36,6 +36,9 @@ public class RemoteDebugger implements ProcessDebugger { private static final SecureRandom ourRandom = new SecureRandom(); + + private static final int CONNECTION_TIMEOUT = 60000; + private final IPyDebugProcess myDebugProcess; private final ServerSocket myServerSocket; private final int myTimeout; @@ -71,6 +74,7 @@ public class RemoteDebugger implements ProcessDebugger { public void waitForConnect() throws Exception { try { //noinspection SocketOpenedButNotSafelyClosed + myServerSocket.setSoTimeout(CONNECTION_TIMEOUT); mySocket = myServerSocket.accept(); myConnected = true; } From dea2b784012c3539a32b76172490d3cc4543593c Mon Sep 17 00:00:00 2001 From: Dmitry Trofimov Date: Sat, 16 Feb 2013 22:20:11 +0100 Subject: [PATCH 9/9] Env tests work with remote python interpreters. --- python/python-tests.iml | 1 + .../python/remote/PythonRemoteInterpreterManager.java | 7 ++----- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/python/python-tests.iml b/python/python-tests.iml index 56cbdc0b8d85..ceff856a0060 100644 --- a/python/python-tests.iml +++ b/python/python-tests.iml @@ -24,6 +24,7 @@ + diff --git a/python/src/com/jetbrains/python/remote/PythonRemoteInterpreterManager.java b/python/src/com/jetbrains/python/remote/PythonRemoteInterpreterManager.java index a10ad75c16a6..b2f2f6cf5ba7 100644 --- a/python/src/com/jetbrains/python/remote/PythonRemoteInterpreterManager.java +++ b/python/src/com/jetbrains/python/remote/PythonRemoteInterpreterManager.java @@ -11,10 +11,7 @@ import com.intellij.openapi.projectRoots.Sdk; import com.intellij.openapi.projectRoots.SdkModificator; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.remotesdk.RemoteCredentials; -import com.intellij.remotesdk.RemoteInterpreterException; -import com.intellij.remotesdk.RemoteSdkData; -import com.intellij.remotesdk.RemoteSshProcess; +import com.intellij.remotesdk.*; import com.intellij.util.NullableConsumer; import com.intellij.util.PathMappingSettings; import com.jetbrains.python.PythonHelpersLocator; @@ -30,7 +27,7 @@ import java.util.List; /** * @author traff */ -public abstract class PythonRemoteInterpreterManager { +public abstract class PythonRemoteInterpreterManager implements RemoteSdkFactory { public final static ExtensionPointName EP_NAME = ExtensionPointName.create("Pythonid.remoteInterpreterManager"); public static final String WEB_DEPLOYMENT_PLUGIN_IS_DISABLED =