| -- Test cases for import returned by the native parser using a side channel |
| -- In particular, test import flags related to reachability and priority when ordering SCCs |
| |
| [case testNoImport] |
| # No imports |
| print() |
| [out] |
| |
| [case testSimpleImport] |
| import foo |
| [out] |
| 1: import foo |
| |
| [case testMultipleImports] |
| import foo |
| import bar |
| import baz |
| [out] |
| 1: import foo |
| 2: import bar |
| 3: import baz |
| |
| [case testImportAs] |
| import foo as f |
| import bar as b |
| [out] |
| 1: import foo as f |
| 2: import bar as b |
| |
| [case testFromImport] |
| from foo import bar |
| [out] |
| 1: from foo import bar |
| |
| [case testFromImportMultiple] |
| from foo import bar, baz, qux |
| [out] |
| 1: from foo import bar, baz, qux |
| |
| [case testFromImportAs] |
| from foo import bar as b, baz as z |
| [out] |
| 1: from foo import bar as b, baz as z |
| |
| [case testRelativeImport] |
| from . import foo |
| from .. import bar |
| from ...baz import qux |
| [out] |
| 1: from . import foo |
| 2: from .. import bar |
| 3: from ...baz import qux |
| |
| [case testNonTopLevelImport] |
| def f(): |
| import foo |
| from bar import baz |
| [out] |
| 2: import foo [not top_level] |
| 3: from bar import baz [not top_level] |
| |
| [case testImportInClass] |
| class Foo: |
| import bar |
| [out] |
| 2: import bar |
| [case testUnreachableImportPY2] |
| # Imports in unreachable blocks should not appear |
| if PY2: |
| import unreachable_module |
| import reachable_module |
| [out] |
| 4: import reachable_module |
| |
| [case testReachableImportPY3] |
| # Imports in reachable if PY3 blocks should appear |
| if PY3: |
| import reachable_module |
| [out] |
| 3: import reachable_module |
| |
| [case testUnreachableElseBlock] |
| # Imports in unreachable else block should not appear |
| if PY3: |
| import reachable |
| else: |
| import unreachable |
| [out] |
| 3: import reachable |
| |
| [case testMixedReachableUnreachable] |
| # Mix of reachable and unreachable imports |
| import before |
| if PY2: |
| import unreachable_in_if |
| else: |
| import reachable_in_else |
| import after |
| [out] |
| 2: import before |
| 6: import reachable_in_else |
| 7: import after |
| |
| [case testNestedUnreachable] |
| # Nested unreachable blocks |
| if PY2: |
| import outer_unreachable |
| if True: |
| import inner_unreachable |
| import reachable |
| [out] |
| 6: import reachable |
| |
| [case testUnreachableWithTopLevel] |
| # Unreachable imports together with top_level flag handling |
| def f(): |
| if PY2: |
| import unreachable_func |
| import reachable_func |
| if PY2: |
| import unreachable_top |
| import reachable_top |
| [out] |
| 5: import reachable_func [not top_level] |
| 8: import reachable_top |
| |
| [case testVersionCheckUnreachable] |
| # sys.version_info check makes else unreachable |
| import sys |
| if sys.version_info >= (3, 8): |
| import reachable_version_check |
| else: |
| import unreachable_old_version |
| [out] |
| 2: import sys |
| 4: import reachable_version_check |
| |
| [case testMultipeBranchesUnreachable] |
| if PY2: |
| import unreachable_if |
| elif PY2: |
| import unreachable_elif |
| else: |
| import reachable_else |
| [out] |
| 6: import reachable_else |
| |
| [case testMypyOnlyImport] |
| # Imports in TYPE_CHECKING blocks are mypy_only |
| from typing import TYPE_CHECKING |
| if TYPE_CHECKING: |
| import mypy_only_module |
| import regular_module |
| [out] |
| 2: from typing import TYPE_CHECKING |
| 4: import mypy_only_module [mypy_only] |
| 5: import regular_module |
| |
| [case testMypyNameAlias] |
| # MYPY is also recognized as mypy_only |
| if MYPY: |
| import only_for_mypy |
| import for_everyone |
| [out] |
| 3: import only_for_mypy [mypy_only] |
| 4: import for_everyone |
| |
| [case testMypyOnlyElseBranch] |
| # Else branch of TYPE_CHECKING is unreachable (runtime-only, not analyzed by mypy) |
| from typing import TYPE_CHECKING |
| if TYPE_CHECKING: |
| import for_mypy |
| else: |
| import for_runtime |
| [out] |
| 2: from typing import TYPE_CHECKING |
| 4: import for_mypy [mypy_only] |
| |
| [case testNestedMypyOnly] |
| # Nested blocks inside TYPE_CHECKING are also mypy_only |
| from typing import TYPE_CHECKING |
| if TYPE_CHECKING: |
| if True: |
| import deeply_nested |
| import also_mypy_only |
| [out] |
| 2: from typing import TYPE_CHECKING |
| 5: import deeply_nested [mypy_only] |
| 6: import also_mypy_only [mypy_only] |
| |
| [case testMypyOnlyInFunction] |
| # Mypy-only imports in functions |
| from typing import TYPE_CHECKING |
| def f(): |
| if TYPE_CHECKING: |
| import mypy_func_import |
| import regular_func_import |
| [out] |
| 2: from typing import TYPE_CHECKING |
| 5: import mypy_func_import [not top_level, mypy_only] |
| 6: import regular_func_import [not top_level] |
| |
| [case testMypyOnlyElifBranch] |
| # Elif after TYPE_CHECKING is unreachable (runtime-only) |
| from typing import TYPE_CHECKING |
| if TYPE_CHECKING: |
| import for_mypy |
| elif True: |
| import for_runtime_elif |
| [out] |
| 2: from typing import TYPE_CHECKING |
| 4: import for_mypy [mypy_only] |
| |
| [case testNotMypyFalseBranch] |
| # Not TYPE_CHECKING makes body unreachable, else is mypy_only |
| from typing import TYPE_CHECKING |
| if not TYPE_CHECKING: |
| import runtime_only |
| else: |
| import mypy_only |
| [out] |
| 2: from typing import TYPE_CHECKING |
| 6: import mypy_only [mypy_only] |
| |
| [case testMixedMypyOnlyAndUnreachable] |
| # Combination of mypy_only and unreachable |
| from typing import TYPE_CHECKING |
| if PY2: |
| import unreachable_py2 |
| if TYPE_CHECKING: |
| import mypy_only_import |
| if PY3: |
| import always_reachable |
| [out] |
| 2: from typing import TYPE_CHECKING |
| 6: import mypy_only_import [mypy_only] |
| 8: import always_reachable |
| |
| [case testTypingExtensionsTypeChecking] |
| # typing_extensions.TYPE_CHECKING is also recognized |
| from typing_extensions import TYPE_CHECKING |
| if TYPE_CHECKING: |
| import mypy_import |
| [out] |
| 2: from typing_extensions import TYPE_CHECKING |
| 4: import mypy_import [mypy_only] |
| |
| [case testUnknownCondition] |
| # Unknown conditions - all branches reachable |
| if x: |
| import in_if |
| else: |
| import in_else |
| [out] |
| 3: import in_if |
| 5: import in_else |
| |
| [case testUnknownConditionWithElif] |
| # Unknown conditions with elif |
| if unknown_var: |
| import first |
| elif another_var: |
| import second |
| else: |
| import third |
| [out] |
| 3: import first |
| 5: import second |
| 7: import third |
| |
| [case testMixedKnownUnknown] |
| # Mix of known and unknown conditions |
| if TYPE_CHECKING: |
| import mypy_only |
| if some_var: |
| import maybe_reachable |
| if PY2: |
| import unreachable |
| [out] |
| 3: import mypy_only [mypy_only] |
| 5: import maybe_reachable |
| |
| [case testNestedUnknownInMypyOnly] |
| # Unknown condition nested in mypy-only block |
| from typing import TYPE_CHECKING |
| if TYPE_CHECKING: |
| if condition: |
| import nested_mypy |
| import also_mypy |
| [out] |
| 2: from typing import TYPE_CHECKING |
| 5: import nested_mypy [mypy_only] |
| 6: import also_mypy [mypy_only] |
| |
| [case testUnknownAfterMypyTrue] |
| # Unknown elif after TYPE_CHECKING is unreachable |
| from typing import TYPE_CHECKING |
| if TYPE_CHECKING: |
| import for_mypy |
| elif x: |
| import unreachable_elif |
| [out] |
| 2: from typing import TYPE_CHECKING |
| 4: import for_mypy [mypy_only] |
| |
| [case testStarImport] |
| from foo import * |
| [out] |
| 1: from foo import * |
| |
| [case testStarImportInFunction] |
| def f(): |
| from foo import * |
| [out] |
| 2: from foo import * [not top_level] |
| |
| [case testMypyOnlyStarImport] |
| from typing import TYPE_CHECKING |
| if TYPE_CHECKING: |
| from mypy_types import * |
| from regular import * |
| [out] |
| 1: from typing import TYPE_CHECKING |
| 3: from mypy_types import * [mypy_only] |
| 4: from regular import * |
| |
| [case testUnreachableStarImport] |
| if PY2: |
| from unreachable import * |
| from reachable import * |
| [out] |
| 3: from reachable import * |
| |
| [case testNotPY2] |
| # not PY2 should be always true |
| if not PY2: |
| import always_reachable |
| [out] |
| 3: import always_reachable |
| |
| [case testNotPY3] |
| # not PY3 should be always false |
| if not PY3: |
| import unreachable |
| import reachable |
| [out] |
| 4: import reachable |
| |
| [case testNotPY3Else] |
| # not PY3 else branch should be reachable |
| if not PY3: |
| import unreachable_if |
| else: |
| import reachable_else |
| [out] |
| 5: import reachable_else |
| |
| [case testBoolAndAlwaysTrueWithMypyTrue] |
| # PY3 and TYPE_CHECKING - both true, result is mypy_true |
| from typing import TYPE_CHECKING |
| if PY3 and TYPE_CHECKING: |
| import mypy_only_import |
| [out] |
| 2: from typing import TYPE_CHECKING |
| 4: import mypy_only_import [mypy_only] |
| |
| [case testBoolAndAlwaysTrueWithUnknown] |
| # PY3 and unknown - result is unknown, both branches reachable |
| if PY3 and some_var: |
| import maybe_reachable |
| else: |
| import also_maybe_reachable |
| [out] |
| 3: import maybe_reachable |
| 5: import also_maybe_reachable |
| |
| [case testBoolAndAlwaysFalseWithAnything] |
| # PY2 and anything - result is always false |
| if PY2 and some_var: |
| import unreachable |
| import reachable |
| [out] |
| 4: import reachable |
| |
| [case testBoolAndMypyFalseWithAlwaysTrue] |
| # not TYPE_CHECKING and PY3 - result is mypy_false, else is mypy_only |
| from typing import TYPE_CHECKING |
| if not TYPE_CHECKING and PY3: |
| import runtime_only |
| else: |
| import mypy_only_import |
| [out] |
| 2: from typing import TYPE_CHECKING |
| 6: import mypy_only_import [mypy_only] |
| |
| [case testBoolAndMypyTrueOnly] |
| # MYPY and TYPE_CHECKING - both mypy_true, result is mypy_true |
| from typing import TYPE_CHECKING |
| if MYPY and TYPE_CHECKING: |
| import mypy_only_import |
| [out] |
| 2: from typing import TYPE_CHECKING |
| 4: import mypy_only_import [mypy_only] |
| |
| [case testBoolOrAlwaysTrueWithAnything] |
| # PY3 or anything - result is always true |
| if PY3 or some_var: |
| import always_reachable |
| else: |
| import unreachable_else |
| [out] |
| 3: import always_reachable |
| |
| [case testBoolOrMypyTrueWithAlwaysFalse] |
| # TYPE_CHECKING or PY2 - result is mypy_true |
| from typing import TYPE_CHECKING |
| if TYPE_CHECKING or PY2: |
| import mypy_only_import |
| [out] |
| 2: from typing import TYPE_CHECKING |
| 4: import mypy_only_import [mypy_only] |
| |
| [case testBoolOrMypyFalseOnly] |
| # not MYPY or not TYPE_CHECKING - all mypy_false, result is mypy_false, else is mypy_only |
| from typing import TYPE_CHECKING |
| if not MYPY or not TYPE_CHECKING: |
| import runtime_only |
| else: |
| import mypy_only_import |
| [out] |
| 2: from typing import TYPE_CHECKING |
| 6: import mypy_only_import [mypy_only] |
| |
| [case testBoolOrAlwaysFalseWithUnknown] |
| # PY2 or unknown - result is unknown, both branches reachable |
| if PY2 or some_var: |
| import maybe_reachable |
| else: |
| import also_maybe_reachable |
| [out] |
| 3: import maybe_reachable |
| 5: import also_maybe_reachable |
| |
| [case testBoolOrAllFalse] |
| # PY2 or not TYPE_CHECKING - all false values, result is always_false, else is unreachable |
| from typing import TYPE_CHECKING |
| if PY2 or not TYPE_CHECKING: |
| import runtime_only |
| else: |
| import mypy_only_import |
| [out] |
| 2: from typing import TYPE_CHECKING |
| 6: import mypy_only_import |
| |
| [case testBoolComplexAndOr] |
| # Complex: (PY3 and TYPE_CHECKING) or PY2 - evaluates to mypy_true |
| from typing import TYPE_CHECKING |
| if (PY3 and TYPE_CHECKING) or PY2: |
| import mypy_only_import |
| [out] |
| 2: from typing import TYPE_CHECKING |
| 4: import mypy_only_import [mypy_only] |
| |
| [case testBoolMultipleOr] |
| # Multiple or: PY2 or PY2 or TYPE_CHECKING - result is mypy_true |
| from typing import TYPE_CHECKING |
| if PY2 or PY2 or TYPE_CHECKING: |
| import mypy_only_import |
| [out] |
| 2: from typing import TYPE_CHECKING |
| 4: import mypy_only_import [mypy_only] |
| |
| [case testBoolMultipleAnd] |
| # Multiple and: PY3 and PY3 and PY3 - result is always_true |
| if PY3 and PY3 and PY3: |
| import always_reachable |
| else: |
| import unreachable_else |
| [out] |
| 3: import always_reachable |
| |
| [case testVersionInfoIndexMajor] |
| # sys.version_info[0] == 3 should be always true for Python 3.10 |
| import sys |
| if sys.version_info[0] == 3: |
| import reachable_py3 |
| else: |
| import unreachable_not_py3 |
| [out] |
| 2: import sys |
| 4: import reachable_py3 |
| |
| [case testVersionInfoIndexMajorNotEqual] |
| # sys.version_info[0] == 2 should be always false for Python 3.10 |
| import sys |
| if sys.version_info[0] == 2: |
| import unreachable_py2 |
| import reachable |
| [out] |
| 2: import sys |
| 5: import reachable |
| |
| [case testVersionInfoIndexMinor] |
| # sys.version_info[1] >= 10 should be always true for Python 3.10 |
| import sys |
| if sys.version_info[1] >= 10: |
| import reachable_310_plus |
| else: |
| import unreachable_pre_310 |
| [out] |
| 2: import sys |
| 4: import reachable_310_plus |
| |
| [case testVersionInfoIndexMinorLess] |
| # sys.version_info[1] < 10 should be always false for Python 3.10 |
| import sys |
| if sys.version_info[1] < 10: |
| import unreachable_pre_310 |
| import reachable |
| [out] |
| 2: import sys |
| 5: import reachable |
| |
| [case testVersionInfoIndexMinorGreater] |
| # sys.version_info[1] > 9 should be always true for Python 3.10 |
| import sys |
| if sys.version_info[1] > 9: |
| import reachable_310_plus |
| [out] |
| 2: import sys |
| 4: import reachable_310_plus |
| |
| [case testVersionInfoIndexLessOrEqual] |
| # sys.version_info[0] <= 3 should be always true for Python 3.10 |
| import sys |
| if sys.version_info[0] <= 3: |
| import reachable_py3_or_less |
| [out] |
| 2: import sys |
| 4: import reachable_py3_or_less |
| |
| [case testVersionInfoIndexNotEqual] |
| # sys.version_info[0] != 2 should be always true for Python 3.10 |
| import sys |
| if sys.version_info[0] != 2: |
| import reachable_not_py2 |
| [out] |
| 2: import sys |
| 4: import reachable_not_py2 |
| |
| [case testVersionInfoSliceExplicit] |
| # sys.version_info[:2] >= (3, 10) should be always true for Python 3.10 |
| import sys |
| if sys.version_info[:2] >= (3, 10): |
| import reachable_310_plus |
| else: |
| import unreachable_pre_310 |
| [out] |
| 2: import sys |
| 4: import reachable_310_plus |
| |
| [case testVersionInfoSliceExplicitBothBounds] |
| # sys.version_info[0:2] >= (3, 10) should be always true for Python 3.10 |
| import sys |
| if sys.version_info[0:2] >= (3, 10): |
| import reachable_310_plus |
| [out] |
| 2: import sys |
| 4: import reachable_310_plus |
| |
| [case testVersionInfoSliceExplicitLess] |
| # sys.version_info[:2] < (3, 10) should be always false for Python 3.10 |
| import sys |
| if sys.version_info[:2] < (3, 10): |
| import unreachable_pre_310 |
| import reachable |
| [out] |
| 2: import sys |
| 5: import reachable |
| |
| [case testVersionInfoSliceSingleElement] |
| # sys.version_info[:1] >= (3,) should be always true for Python 3.10 |
| import sys |
| if sys.version_info[:1] >= (3,): |
| import reachable_py3 |
| [out] |
| 2: import sys |
| 4: import reachable_py3 |
| |
| [case testVersionInfoSliceSingleElementLess] |
| # sys.version_info[:1] < (3,) should be always false for Python 3.10 |
| import sys |
| if sys.version_info[:1] < (3,): |
| import unreachable_py2 |
| import reachable |
| [out] |
| 2: import sys |
| 5: import reachable |
| |
| [case testVersionInfoReversedOperands] |
| # (3, 8) <= sys.version_info should be always true for Python 3.10 |
| import sys |
| if (3, 8) <= sys.version_info: |
| import reachable_38_plus |
| [out] |
| 2: import sys |
| 4: import reachable_38_plus |
| |
| [case testVersionInfoReversedGreater] |
| # (3, 11) > sys.version_info should be always true for Python 3.10 |
| import sys |
| if (3, 11) > sys.version_info: |
| import reachable_pre_311 |
| [out] |
| 2: import sys |
| 4: import reachable_pre_311 |
| |
| [case testVersionInfoReversedEquals] |
| # (3, 10) == sys.version_info should be always true for Python 3.10 |
| import sys |
| if (3, 10) == sys.version_info: |
| import reachable_exactly_310 |
| [out] |
| 2: import sys |
| 4: import reachable_exactly_310 |
| |
| [case testVersionInfoEquals] |
| # sys.version_info == (3, 10) should be always true for Python 3.10 |
| import sys |
| if sys.version_info == (3, 10): |
| import reachable_exactly_310 |
| else: |
| import unreachable_not_310 |
| [out] |
| 2: import sys |
| 4: import reachable_exactly_310 |
| |
| [case testVersionInfoNotEquals] |
| # sys.version_info != (3, 11) should be always true for Python 3.10 |
| import sys |
| if sys.version_info != (3, 11): |
| import reachable_not_311 |
| [out] |
| 2: import sys |
| 4: import reachable_not_311 |
| |
| [case testVersionInfoNotEqualsExact] |
| # sys.version_info != (3, 10) should be always false for Python 3.10 |
| import sys |
| if sys.version_info != (3, 10): |
| import unreachable_not_310 |
| import reachable |
| [out] |
| 2: import sys |
| 5: import reachable |
| |
| [case testVersionInfoSliceMinorOnly] |
| # sys.version_info[1:2] >= (10,) should be always true for Python 3.10 |
| import sys |
| if sys.version_info[1:2] >= (10,): |
| import reachable_minor_10_plus |
| [out] |
| 2: import sys |
| 4: import reachable_minor_10_plus |
| |
| [case testAttributeTypeChecking] |
| # typing.TYPE_CHECKING should be recognized as mypy_true |
| import typing |
| if typing.TYPE_CHECKING: |
| import mypy_only_import |
| [out] |
| 2: import typing |
| 4: import mypy_only_import [mypy_only] |
| |
| [case testAttributeMYPY] |
| # foo.MYPY should be recognized as mypy_true |
| import foo |
| if foo.MYPY: |
| import mypy_only_import |
| [out] |
| 2: import foo |
| 4: import mypy_only_import [mypy_only] |
| |
| [case testAttributePY2] |
| # bar.PY2 should be recognized as always_false |
| import bar |
| if bar.PY2: |
| import unreachable |
| import reachable |
| [out] |
| 2: import bar |
| 5: import reachable |
| |
| [case testAttributePY3] |
| # baz.PY3 should be recognized as always_true |
| import baz |
| if baz.PY3: |
| import always_reachable |
| [out] |
| 2: import baz |
| 4: import always_reachable |
| |
| [case testVersionInfoWithBoolAnd] |
| # Combining version check with TYPE_CHECKING using and |
| import sys |
| from typing import TYPE_CHECKING |
| if sys.version_info >= (3, 8) and TYPE_CHECKING: |
| import mypy_only_import |
| [out] |
| 2: import sys |
| 3: from typing import TYPE_CHECKING |
| 5: import mypy_only_import [mypy_only] |
| |
| [case testVersionInfoWithBoolOr] |
| # Combining version check with PY2 using or - should be always_true |
| import sys |
| if sys.version_info >= (3, 8) or PY2: |
| import always_reachable |
| else: |
| import unreachable_else |
| [out] |
| 2: import sys |
| 4: import always_reachable |
| |
| [case testComplexBoolVersionMypyUnknown] |
| # Complex: (MYPY or unknown) evaluates to MYPY_TRUE, and version_info >= (3,8) is ALWAYS_TRUE |
| # ALWAYS_TRUE and MYPY_TRUE evaluates to MYPY_TRUE |
| import sys |
| if sys.version_info >= (3, 8) and (MYPY or unknown_var): |
| import mypy_only_import |
| [out] |
| 3: import sys |
| 5: import mypy_only_import [mypy_only] |