text: # pyflyby/test_autoimp.py
  
  # License for THIS FILE ONLY: CC0 Public Domain Dedication
  # http://creativecommons.org/publicdomain/zero/1.0/
  
  from __future__ import (absolute_import, division, print_function,
                          with_statement)
  
  import ast
  import os
  import pytest
  from   shutil                   import rmtree
  import sys
  from   tempfile                 import mkdtemp
  from   textwrap                 import dedent
  
  from   six                      import PY2, PY3
  
  from   pyflyby                  import (Filename, ImportDB, auto_eval,
                                          auto_import, find_missing_imports)
  from   pyflyby._autoimp         import (LoadSymbolError, load_symbol,
                                          scan_for_import_issues)
  from   pyflyby._idents          import DottedIdentifier
  from   pyflyby._importstmt      import Import
  from   pyflyby._flags           import CompilerFlags
  
  
  @pytest.fixture
  def tpp(request):
      """
      A temporary directory which is temporarily added to sys.path.
      """
      d = mkdtemp(prefix="pyflyby_test_autoimp_", suffix=".tmp")
      d = Filename(d).real
      def cleanup():
          # Unload temp modules.
          for name, module in sorted(sys.modules.items()):
              if (getattr(module, "__file__", None) or "").startswith(str(d)):
                  del sys.modules[name]
          # Clean up sys.path.
          sys.path.remove(str(d))
          # Clean up directory on disk.
          rmtree(str(d))
      request.addfinalizer(cleanup)
      sys.path.append(str(d))
      return d
  
  
  def writetext(filename, text, mode='w'):
      text = dedent(text)
      filename = Filename(filename)
      with open(str(filename), mode) as f:
          f.write(text)
      return filename
  
  
  def _dilist2strlist(arg):
      assert type(arg) is list
      assert all(type(x) is DottedIdentifier for x in arg)
      return list(map(str, arg))
  
  
  def test_find_missing_imports_basic_1():
      result   = find_missing_imports("os.path.join", namespaces=[{}])
      result   = _dilist2strlist(result)
      expected = ["os.path.join"]
      assert expected == result
  
  
  def test_find_missing_imports_in_namespace_1():
      result   = find_missing_imports("os.path.join", namespaces=[{"os":os}])
      result   = _dilist2strlist(result)
      expected = []
      assert expected == result
  
  
  def test_find_missing_imports_builtins_1():
      result   = find_missing_imports("os, sys, eval", [{"os": os}])
      result   = _dilist2strlist(result)
      expected = ['sys']
      assert expected == result
  
  
  def test_find_missing_imports_undefined_1():
      result   = find_missing_imports("numpy.arange(x) + arange(y)", [{"y": 3}])
      result   = _dilist2strlist(result)
      expected = ['arange', 'numpy.arange', 'x']
      assert expected == result
  
  
  def test_find_missing_imports_in_scope_1():
      result   = find_missing_imports("import numpy; numpy.arange(x) + arange(x)", [{}])
      result   = _dilist2strlist(result)
      expected = ['arange', 'x']
      assert expected == result
  
  
  def test_find_missing_imports_in_scope_2():
      result   = find_missing_imports("from numpy import pi; numpy.pi + pi + x", [{}])
      result   = _dilist2strlist(result)
      expected = ['numpy.pi', 'x']
      assert expected == result
  
  
  def test_find_missing_imports_in_scope_3():
      result   = find_missing_imports("for x in range(3): print(numpy.arange(x))", [{}])
      result   = _dilist2strlist(result)
      expected = ['numpy.arange']
      assert expected == result
  
  
  def test_find_missing_imports_in_scope_funcall_1():
      result   = find_missing_imports("foo1 = func(); foo1.bar + foo2.bar", [{}])
      result   = _dilist2strlist(result)
      expected = ['foo2.bar', 'func']
      assert expected == result
  
  
  def test_find_missing_imports_in_scope_assign_attr_1():
      result   = find_missing_imports("a.b.y = 1; a.b.x, a.b.y, a.b.z", [{}])
      result   = _dilist2strlist(result)
      expected = ['a.b.x', 'a.b.z']
      assert expected == result
  
  
  def test_find_missing_imports_lambda_1():
      result   = find_missing_imports("(lambda x: x*x)(7)", [{}])
      result   = _dilist2strlist(result)
      expected = []
      assert expected == result
  
  
  def test_find_missing_imports_lambda_2():
      result   = find_missing_imports("(lambda x: x*x)(7) + x", [{}])
      result   = _dilist2strlist(result)
      expected = ['x']
      assert expected == result
  
  
  def test_find_missing_imports_lambda_3():
      result   = find_missing_imports("(lambda *a,**k: (a, k))(7, x=1)", [{}])
      result   = _dilist2strlist(result)
      expected = []
      assert expected == result
  
  
  def test_find_missing_imports_list_comprehension_1():
      result   = find_missing_imports("[x+y+z for x,y in [(1,2)]], y", [{}])
      result   = _dilist2strlist(result)
      if PY2:
          expected = ['z']
      else:
          expected = ['y', 'z']
      assert expected == result
  
  
  def test_find_missing_imports_list_comprehension_nested_tuple_1():
      result   = find_missing_imports("[w+x+y+z for x,(y,z) in []]", [{}])
      result   = _dilist2strlist(result)
      expected = ['w']
      assert expected == result
  
  
  def test_find_missing_imports_list_comprehension_nested_tuple_2():
      result   = find_missing_imports(
          "[a+A+b+B+c+C+d+D+e+E+f+F+g+G for a,((b,c),d,[e,f,(g,)]) in []]", [{}])
      result   = _dilist2strlist(result)
      expected = ['A','B','C','D','E','F','G']
      assert expected == result
  
  
  def test_find_missing_imports_generator_expression_1():
      result   = find_missing_imports("(x+y+z for x,y in [(1,2)]), y", [{}])
      result   = _dilist2strlist(result)
      expected = ['y', 'z']
      assert expected == result
  
  
  def test_find_missing_imports_qualified_1():
      result   = find_missing_imports("( ( a . b ) . x ) . y + ( c + d ) . x . y", [{}])
      result   = _dilist2strlist(result)
      expected = ['a.b.x.y', 'c', 'd']
      assert expected == result
  
  
  def test_find_missing_imports_ast_1():
      node = ast.parse("import numpy; numpy.arange(x) + arange(x)")
      result   = find_missing_imports(node, [{}])
      result   = _dilist2strlist(result)
      expected = ['arange', 'x']
      assert expected == result
  
  
  def test_find_missing_imports_print_function_1():
      node = ast.parse(
          "from __future__ import print_function\n"
          "print (42, file=sys.stdout)\n"
      )
      result   = find_missing_imports(node, [{}])
      result   = _dilist2strlist(result)
      expected = ['sys.stdout']
      assert expected == result
  
  
  def test_find_missing_imports_assignment_1():
      code = dedent("""
          from __future__ import print_function
  
          def f():
              x = 1
              print(x, y, z)
              y = 2
      """)
      result   = find_missing_imports(code, [{}])
      result   = _dilist2strlist(result)
      expected = ['y', 'z']
      assert expected == result
  
  
  def test_find_missing_imports_function_body_1():
      code = dedent("""
          x1 = 1
          def func59399065():
              return x1 + x2 + x3
          x3 = 3
      """)
      result   = find_missing_imports(code, [{}])
      result   = _dilist2strlist(result)
      expected = ['x2']
      assert expected == result
  
  
  def test_find_missing_imports_function_paramlist_1():
      code = dedent("""
          X1 = 1
          def func85025862(x1=X1, x2=X2, x3=X3):
              return x1 + x2 + x3
          X3 = 3
      """)
      result   = find_missing_imports(code, [{}])
      result   = _dilist2strlist(result)
      expected = ['X2', 'X3']
      assert expected == result
  
  
  def test_find_missing_imports_function_paramlist_2():
      code = dedent("""
          from somewhere import given, data
  
          @given(data())
          def blargh(data):
              pass
      """)
      result  = find_missing_imports(code, [{}])
      result  = _dilist2strlist(result)
      expected = []
      assert expected == result
  
  def test_find_missing_imports_function_defaults_1():
      code = dedent("""
          e = 1
          def func32466773(a=b, b=c, c=a, d=d, e=e, f=1):
              pass
      """)
      result   = find_missing_imports(code, [{}])
      result   = _dilist2strlist(result)
      expected = ['a', 'b', 'c', 'd']
      assert expected == result
  
  
  def test_find_missing_imports_function_defaults_kwargs_1():
      code = dedent("""
          def func16049151(x=args, y=kwargs, z=y, *args, **kwargs):
              pass
      """)
      result   = find_missing_imports(code, [{}])
      result   = _dilist2strlist(result)
      expected = ['args', 'kwargs', 'y']
      assert expected == result
  
  
  def test_find_missing_imports_function_defaults_kwargs_2():
      code = dedent("""
          args = 1
          kwargs = 2
          def func69790319(x=args, y=kwargs, z=y, *args, **kwargs):
              pass
      """)
      result   = find_missing_imports(code, [{}])
      result   = _dilist2strlist(result)
      expected = ['y']
      assert expected == result
  
  
  def test_find_missing_imports_function_paramlist_local_1():
      code = dedent("""
          x1 = 1
          x2 = 2
          def func77361554(x1, x3, x4):
              pass
          x4 = 4
          x1, x2, x3, x4, x5
      """)
      result   = find_missing_imports(code, [{}])
      result   = _dilist2strlist(result)
      expected = ['x3', 'x5']
      assert expected == result
  
  
  def test_find_missing_imports_function_paramlist_selfref_1():
      code = dedent("""
          f1 = 'x'
          def f2(g1=f1, g2=f2, g3=f3):
              return (g1, g2, g3)
          f3 = 'x'
      """)
      result   = find_missing_imports(code, [{}])
      result   = _dilist2strlist(result)
      expected = ['f2', 'f3']
      assert expected == result
  
  
  def test_find_missing_imports_function_paramlist_lambda_1():
      code = dedent("""
          X1 = 1
          def func85025862(x1=lambda: 1/X1, x2=lambda: 1/X2, x3=lambda: 1/X3):
              return x1() + x2() + x3()
          X3 = 3
      """)
      result   = find_missing_imports(code, [{}])
      result   = _dilist2strlist(result)
      expected = ['X2']
      assert expected == result
  
  
  def test_find_missing_imports_decorator_1():
      code = dedent("""
          deco1 = 'x'
          @deco1
          @deco2
          @deco3
          def func33144383():
              pass
          deco3 = 'x'
      """)
      result   = find_missing_imports(code, [{}])
      result   = _dilist2strlist(result)
      expected = ['deco2', 'deco3']
      assert expected == result
  
  
  def test_find_missing_imports_decorator_selfref_1():
      code = dedent("""
          deco = 'x'
          func1 = 'x'
          @deco(func1, func2, func3)
          def func2():
              pass
          func3 = 'x'
      """)
      result   = find_missing_imports(code, [{}])
      result   = _dilist2strlist(result)
      expected = ['func2', 'func3']
      assert expected == result
  
  
  def test_find_missing_imports_decorator_paramlist_1():
      code = dedent("""
          p2 = 2
          def deco(*args): pass
          @deco(p1, p2, p3)
          def foo74632516():
              pass
          p3 = 3
      """)
      result   = find_missing_imports(code, [{}])
      result   = _dilist2strlist(result)
      expected = ['p1', 'p3']
      assert expected == result
  
  
  def test_find_missing_imports_setattr_1():
      code = dedent("""
          aa = 1
          aa.xx.yy = 1
          bb.xx.yy = 1
      """)
      result   = find_missing_imports(code, [{}])
      result   = _dilist2strlist(result)
      # For now we intentionally don't auto-import 'bb' because that's more
      # likely to be a mistake.
      expected = []
      assert expected == result
  
  
  def test_find_missing_imports_delattr_1():
      code = dedent("""
          foo1 = 1
          del foo1.bar, foo2.bar
      """)
      result   = find_missing_imports(code, [{}])
      result   = _dilist2strlist(result)
      expected = ['foo2']
      assert expected == result
  
  
  def test_find_missing_imports_delitem_lhs_1():
      code = dedent("""
          foo1 = 1
          del foo1[123], foo2[123]
      """)
      result   = find_missing_imports(code, [{}])
      result   = _dilist2strlist(result)
      expected = ['foo2']
      assert expected == result
  
  
  def test_find_missing_imports_delitem_rhs_1():
      code = dedent("""
          foo1 = 1
          bar1 = 1
          del foo1[bar1], foo1[bar2]
      """)
      result   = find_missing_imports(code, [{}])
      result   = _dilist2strlist(result)
      expected = ['bar2']
      assert expected == result
  
  # TODO: unit tests for local, nonlocal
  
  
  def test_find_missing_imports_classdef_1():
      code = dedent("""
          class Mahopac:
              pass
          class Gleneida(Mahopac):
              pass
          Mahopac, Carmel, Gleneida
      """)
      result   = find_missing_imports(code, [{}])
      result   = _dilist2strlist(result)
      expected = ['Carmel']
      assert expected == result
  
  
  def test_find_missing_imports_class_base_1():
      code = dedent("""
          Mill = object
          class Mohansic(Crom, Mill):
              pass
      """)
      result   = find_missing_imports(code, [{}])
      result   = _dilist2strlist(result)
      expected = ['Crom']
      assert expected == result
  
  
  def test_find_missing_imports_class_name_1():
      code = dedent("""
          class Corinne(object):
              pass
          class Bobtail(object):
              class Chippewa(object):
                  pass
              Rockton = Passall, Corinne, Bobtail, Chippewa
      """)
      result   = find_missing_imports(code, [{}])
      result   = _dilist2strlist(result)
      expected = ['Bobtail', 'Passall']
      assert expected == result
  
  
  def test_find_missing_imports_class_members_1():
      code = dedent("""
          class Kenosha(object):
              x = 3
              z = x, y
      """)
      result   = find_missing_imports(code, [{}])
      result   = _dilist2strlist(result)
      expected = ['y']
      assert expected == result
  
  
  def test_find_missing_imports_class_member_vs_function_1():
      code = dedent("""
          class Sidney(object):
              x = 3
              def barracuda(self):
                  return x, y
      """)
      result   = find_missing_imports(code, [{}])
      result   = _dilist2strlist(result)
      expected = ['x', 'y']
      assert expected == result
  
  
  def test_find_missing_imports_class_member_vs_function_2():
      code = dedent("""
          class Wayne: pass
          class Connaught(object):
              class Windsor: pass
              def Mercury(self):
                  return Wayne, Connaught, Windsor
      """)
      result   = find_missing_imports(code, [{}])
      result   = _dilist2strlist(result)
      expected = ['Windsor']
      assert expected == result
  
  
  def test_find_missing_imports_class_member_vs_lambda_1():
      code = dedent("""
          x1 = 1
          class Salsa(object):
              x2 = 2
              x3 = 3
              y = [lambda y3=x3, y4=x4: x1 + x2 + x5 + x6]
          x4 = 4
          x5 = 5
      """)
      result   = find_missing_imports(code, [{}])
      result   = _dilist2strlist(result)
      expected = ['x2', 'x4', 'x6']
      assert expected == result
  
  
  def test_find_missing_imports_class_member_vs_paramlist_1():
      code = dedent("""
          class Drake:
              duck2 = 2
              def quack(self, mallard1=duck1, mallard2=duck2, mallard3=duck3):
                  pass
              duck3 = 3
      """)
      result   = find_missing_imports(code, [{}])
      result   = _dilist2strlist(result)
      expected = ['duck1', 'duck3']
      assert expected == result
  
  
  def test_find_missing_imports_class_member_vs_paramlist_lambda_1():
      code = dedent("""
          class Breakfast:
              def corn1(self):
                  pass
              def cereal(self, maize1=lambda: corn1, maize2=lambda: corn2,
                               maize3=lambda: corn3):
                  return (maize1(), maize2())
              def corn2(self):
                  pass
          def corn3(self):
              pass
      """)
      result   = find_missing_imports(code, [{}])
      result   = _dilist2strlist(result)
      expected = ['corn1', 'corn2']
      assert expected == result
  
  
  def test_find_missing_imports_class_member_vs_paramlist_local_1():
      code = dedent("""
          class Legume:
              x1 = 1
              x2 = 2
              def func13585710(x1, x3, x4):
                  pass
              x4 = 4
              y = x1, x2, x3, x4, x5
      """)
      result   = find_missing_imports(code, [{}])
      result   = _dilist2strlist(result)
      expected = ['x3', 'x5']
      assert expected == result
  
  
  def test_find_missing_imports_class_member_vs_decorator_1():
      code = dedent("""
          def deco(): 1/0
          class Cat:
              def panther1(self):
                  pass
              @deco(panther1, panther2, panther3)
              def growl(self):
                  pass
              def panther2(self):
                  pass
      """)
      result   = find_missing_imports(code, [{}])
      result   = _dilist2strlist(result)
      expected = ['panther2', 'panther3']
      assert expected == result
  
  
  def test_find_missing_imports_inner_class_method_1():
      code = dedent("""
          class Sand(object):
              Dirt = 100
              class Silicon:
                  def f(self):
                      return Sand, Dirt, Silicon, Glass
          class Glass:
              pass
      """)
      result   = find_missing_imports(code, [{}])
      result   = _dilist2strlist(result)
      expected = ['Dirt', 'Silicon']
      assert expected == result
  
  
  def test_find_missing_imports_inner_class_attribute_1():
      code = dedent("""
          x = 100
          class Axel(object):
              a = 100
              class Beth:
                  b = x + a
      """)
      result   = find_missing_imports(code, [{}])
      result   = _dilist2strlist(result)
      expected = ['a']
      assert expected == result
  
  
  def test_find_missing_imports_class_member_function_ref_1():
      code = dedent("""
          class Niska(object):
              def f1(self): pass
              g = f1, f2
      """)
      result   = find_missing_imports(code, [{}])
      result   = _dilist2strlist(result)
      expected = ['f2']
      assert expected == result
  
  
  def test_find_missing_imports_class_member_generator_expression_1():
      # Verify that variables leak out of list comprehensions but not out of
      # generator expressions in Python 2.
      # Verify that both can see members of the same ClassDef.
      code = dedent("""
          class Caleb(object):
              x = []
              g1 = (1 for y1 in x)
              g2 = [1 for y2 in x]
              h = [y1, y2]
      """)
      result   = find_missing_imports(code, [{}])
      result   = _dilist2strlist(result)
      if PY2:
          expected = ['y1']
      else:
          expected = ['y1', 'y2']
      assert expected == result
  
  
  def test_find_missing_imports_latedef_def_1():
      code = dedent("""
          def marble(x):
              return x + y + z
          z = 100
      """)
      result   = find_missing_imports(code, [{}])
      result   = _dilist2strlist(result)
      expected = ['y']
      assert expected == result
  
  
  def test_find_missing_imports_latedef_lambda_1():
      code = dedent("""
          granite = lambda x: x + y + z
          z = 100
      """)
      result   = find_missing_imports(code, [{}])
      result   = _dilist2strlist(result)
      expected = ['y']
      assert expected == result
  
  
  def test_find_missing_imports_latedef_def_def_1():
      code = dedent("""
          def twodot():
              return sterling() + haymaker() + cannon() + twodot()
          def haymaker():
              return 100
      """)
      result   = find_missing_imports(code, [{}])
      result   = _dilist2strlist(result)
      expected = ['cannon', 'sterling']
      assert expected == result
  
  
  def test_find_missing_imports_latedef_innerdef_1():
      code = dedent("""
          def kichawan(w):
              def turkey(x):
                  return v + w + x + y + z
              z = 100
          v = 200
      """)
      result   = find_missing_imports(code, [{}])
      result   = _dilist2strlist(result)
      expected = ['y']
      assert expected == result
  
  
  def test_find_missing_imports_latedef_innerdef_2():
      code = dedent("""
          def maple(w):
              def drumgor(x):
                  return v + w + x + y + z
              z = 100
          def springmere(w):
              def dorchester(x):
                  return v + w + x + y + z
          v = 200
      """)
      result   = find_missing_imports(code, [{}])
      result   = _dilist2strlist(result)
      expected = ['y', 'z']
      assert expected == result
  
  
  def test_find_missing_imports_latedef_classdef_1():
      code = dedent("""
          a = 100
          class Granite:
              x = a, b
              def springs(self):
                  x, y, z
          b = 100
          z = 100
      """)
      result   = find_missing_imports(code, [{}])
      result   = _dilist2strlist(result)
      expected = ['b', 'x', 'y']
      assert expected == result
  
  
  def test_find_missing_imports_latedef_func_class_func_1():
      code = dedent("""
          def Nellie():
              class Shelley:
                  def Norman(self):
                      return Alfred, Sherry, Grover, Kirk
              Sherry = 100
          Kirk = 200
      """)
      result   = find_missing_imports(code, [{}])
      result   = _dilist2strlist(result)
      expected = ['Alfred', 'Grover']
      assert expected == result
  
  
  def test_find_missing_imports_latedef_if_1():
      code = dedent("""
          if 1:
              def cavalier():
                  x, y
          if 1:
              x = 1
      """)
      result   = find_missing_imports(code, [{}])
      result   = _dilist2strlist(result)
      expected = ['y']
      assert expected == result
  
  
  def test_find_missing_imports_class_scope_comprehension_1():
      code = dedent("""
          class Plymouth:
              x = []
              z = list(1 for t in x+y)
      """)
      result   = find_missing_imports(code, [{}])
      result   = _dilist2strlist(result)
      expected = ['y']
      assert expected == result
  
  
  def test_find_missing_imports_global_1():
      code = dedent("""
          def func10663671():
              global x
              x = x + y
          x = 1
      """)
      result   = find_missing_imports(code, [{}])
      result   = _dilist2strlist(result)
      expected = ['y']
      assert expected == result
  
  
  def test_find_missing_imports_complex_1():
      if PY2:
          code = dedent("""
              x = 3+4j+5L+k+u'a'
          """)
      else:
          code = dedent("""
              x = 3+4j+5+k+u'a'
          """)
      result   = find_missing_imports(code, [{}])
      result   = _dilist2strlist(result)
      expected = ['k']
      assert expected == result
  
  
  def test_find_missing_imports_code_1():
      f = lambda: foo.bar(x) + baz(y) # noqa: F821
      result   = find_missing_imports(f.__code__, [{}])
      result   = _dilist2strlist(result)
      expected = ['baz', 'foo.bar', 'x', 'y']
      assert expected == result
  
  
  def test_find_missing_imports_code_args_1():
      def f(x, y, *a, **k):
          return g(x, y, z, a, k) # noqa: F821
      result   = find_missing_imports(f.__code__, [{}])
      result   = _dilist2strlist(result)
      expected = ['g', 'z']
      assert expected == result
  
  
  def test_find_missing_imports_code_use_after_import_1():
      def f():
          import foo
          foo.bar()
      result   = find_missing_imports(f.__code__, [{}])
      result   = _dilist2strlist(result)
      expected = []
      assert expected == result
  
  
  def test_find_missing_imports_code_lambda_scope_1():
      f = lambda x: (lambda: x+y) # noqa: F821
      result   = find_missing_imports(f.__code__, [{}])
      result   = _dilist2strlist(result)
      expected = ['y']
      assert expected == result
  
  
  def test_find_missing_imports_code_conditional_1():
      def f():
          y0 = x0          # noqa: F821
          if c:            # noqa: F821
              y1 = y0 + x1 # noqa: F821
          else:
              y2 = x2 + y0 # noqa: F821
          x3 + y0          # noqa: F821
          y1 + y2
      result   = find_missing_imports(f.__code__, [{}])
      result   = _dilist2strlist(result)
      expected = ['c', 'x0', 'x1', 'x2', 'x3']
      assert expected == result
  
  
  def test_find_missing_imports_code_loop_1():
      def f():
          for i in range(10):
              if i > 0:
                  use(x)     # noqa: F821
                  use(y)     # noqa: F821
              else:
                  x = "hello" # noqa: F841
      result   = find_missing_imports(f.__code__, [{}])
      result   = _dilist2strlist(result)
      expected = ['use', 'y']
      assert expected == result
  
  @pytest.mark.skipif(
      sys.version_info < (3, 8),
      reason="Python 3.8+-only syntax.")
  def test_find_missing_imports_positional_only_args_1():
      code = dedent("""
          def func(x, /, y):
              pass
      """)
      result   = find_missing_imports(code, [{}])
      result   = _dilist2strlist(result)
      expected = []
      assert expected == result
  
  @pytest.mark.skipif(
      PY2,
      reason="Python 3-only syntax.")
  def test_find_missing_imports_keyword_only_args_1():
      code = dedent("""
          def func(*args, kwonly=b):
              a = kwonly
      """)
      result   = find_missing_imports(code, [{}])
      result   = _dilist2strlist(result)
      expected = ['b']
      assert expected == result
  
  @pytest.mark.skipif(
      PY2,
      reason="Python 3-only syntax.")
  def test_find_missing_imports_keyword_only_args_2():
      code = dedent("""
          def func(*args, kwonly):
              a = kwonly
      """)
      result   = find_missing_imports(code, [{}])
      result   = _dilist2strlist(result)
      expected = []
      assert expected == result
  
  
  @pytest.mark.skipif(
      PY2,
      reason="Python 3-only syntax.")
  def test_find_missing_imports_keyword_only_args_3():
      code = dedent("""
          def func(*args, kwonly, kwonly2=b):
              a = kwonly
      """)
      result   = find_missing_imports(code, [{}])
      result   = _dilist2strlist(result)
      expected = ['b']
      assert expected == result
  
  @pytest.mark.skipif(
      PY2,
      reason="Python 3-only syntax.")
  def test_find_missing_imports_annotations_1():
      code = dedent("""
          def func(a: b) -> c:
              d = a
      """)
      result   = find_missing_imports(code, [{}])
      result   = _dilist2strlist(result)
      expected = ['b', 'c']
      assert expected == result
  
  @pytest.mark.skipif(
      PY2,
      reason="Python 3-only syntax.")
  def test_find_missing_imports_annotations_2():
      code = dedent("""
      a: b = c
      """)
      result   = find_missing_imports(code, [{}])
      result   = _dilist2strlist(result)
      expected = ['b', 'c']
      assert expected == result
  
  @pytest.mark.skipif(
      PY2,
      reason="Python 3-only syntax.")
  def test_find_missing_imports_star_assignments_1():
      code = dedent("""
      a, *b = c
      """)
      result   = find_missing_imports(code, [{}])
      result   = _dilist2strlist(result)
      expected = ['c']
      assert expected == result
  
  @pytest.mark.skipif(
      PY2,
      reason="Python 3-only syntax.")
  def test_find_missing_imports_star_expression_1():
      code = dedent("""
      [a, *b]
      """)
      result   = find_missing_imports(code, [{}])
      result   = _dilist2strlist(result)
      expected = ['a', 'b']
      assert expected == result
  
  
  @pytest.mark.skipif(
      PY2,
      reason="Python 3-only syntax.")
  def test_find_missing_imports_star_expression_2():
      code = dedent("""
      {a: 1, **b, **{c: 1}}
      """)
      result   = find_missing_imports(code, [{}])
      result   = _dilist2strlist(result)
      expected = ['a', 'b', 'c']
      assert expected == result
  
  @pytest.mark.skipif(
      PY2,
      reason="Python 3-only syntax.")
  def test_find_missing_imports_star_expression_function_call_1():
      code = dedent("""
      f(a, *b, **c, d=e, **g)
      """)
      result   = find_missing_imports(code, [{}])
      result   = _dilist2strlist(result)
      expected = ['a', 'b', 'c', 'e', 'f', 'g']
      assert expected == result
  
  def test_find_missing_imports_star_expression_function_call_2():
      # Python 2-valid syntax
      code = dedent("""
      f(a, b=c, *d, **e)
      """)
      result   = find_missing_imports(code, [{}])
      result   = _dilist2strlist(result)
      expected = ['a', 'c', 'd', 'e', 'f']
      assert expected == result
  
  @pytest.mark.skipif(
      PY2,
      reason="Python 3-only syntax.")
  def test_find_missing_imports_python_3_metaclass_1():
      code = dedent("""
      class Test(metaclass=TestMeta):
          pass
      """)
      result   = find_missing_imports(code, [{}])
      result   = _dilist2strlist(result)
      expected = ['TestMeta']
      assert expected == result
  
  
  @pytest.mark.skipif(
      PY2,
      reason="Python 3-only syntax.")
  def test_find_missing_imports_f_string_1():
      code = dedent("""
      a = 1
      f'{a + 1} {b + 1}'
      """)
      result   = find_missing_imports(code, [{}])
      result   = _dilist2strlist(result)
      expected = ['b']
      assert expected == result
  
  @pytest.mark.skipif(
      PY2,
      reason="Python 3-only syntax.")
  def test_find_missing_imports_f_string_2():
      code = dedent("""
      a = 1
      f'{a!s} {b!r}'
      """)
      result   = find_missing_imports(code, [{}])
      result   = _dilist2strlist(result)
      expected = ['b']
      assert expected == result
  
  @pytest.mark.skipif(
      PY2,
      reason="Python 3-only syntax.")
  def test_find_missing_imports_f_string_3():
      # Recursive format spec
      code = dedent("""
      f'{a:{b}!s}'
      """)
      result   = find_missing_imports(code, [{}])
      result   = _dilist2strlist(result)
      expected = ['a', 'b']
      assert expected == result
  
  def test_find_missing_imports_bytes_1():
      code = dedent("""
          a = b'b'
      """)
      result = find_missing_imports(code, [{}])
      result = _dilist2strlist(result)
      expected = []
      assert expected == result
  
  def test_find_missing_imports_true_false_none_1():
      # These nodes changed in Python 3, make sure they are handled correctly
      code = dedent("""
      (True, False, None)
      """)
      result = find_missing_imports(code, [{}])
      result = _dilist2strlist(result)
      expected = []
      assert expected == result
  
  
  @pytest.mark.skipif(
      PY2,
      reason="Python 3-only syntax.")
  def test_find_missing_imports_matmul_1():
      code = dedent("""
      a@b
      """)
      result   = find_missing_imports(code, [{}])
      result   = _dilist2strlist(result)
      expected = ['a', 'b']
      assert expected == result
  
  @pytest.mark.skipif(
      PY2,
      reason="Python 3-only syntax.")
  def test_find_missing_imports_async_await_1():
      code = dedent("""
      async def f():
          async with a as b, c as d:
              async for i in e:
                  g = await h()
      """)
      result   = find_missing_imports(code, [{}])
      result   = _dilist2strlist(result)
      expected = ['a', 'c', 'e', 'h']
      assert expected == result
  
  @pytest.mark.skipif(
      PY2,
      reason="Python 3-only syntax.")
  def test_find_missing_imports_async_comprehension_1():
      code = dedent("""
      async def f():
          [i async for i in range(2)]
      """)
      result   = find_missing_imports(code, [{}])
      result   = _dilist2strlist(result)
      expected = []
      assert expected == result
  
  
  @pytest.mark.skipif(
      PY2,
      reason="Python 3-only syntax.")
  def test_find_missing_imports_yield_from_1():
      code = dedent("""
      def f():
          yield from g()
      """)
      result   = find_missing_imports(code, [{}])
      result   = _dilist2strlist(result)
      expected = ['g']
      assert expected == result
  
  
  @pytest.mark.skipif(PY2, reason="Python 3-only syntax.")
  def test_find_missing_imports_not_async_def():
      code = dedent(
          """
      async def f():
          pass
      f()
      """
      )
      result = find_missing_imports(code, [{}])
      expected = []
      assert expected == result
  
  
  def test_find_missing_imports_nested_with_1():
      # Handled differently in the ast in Python 2 and 3
      code = dedent("""
      with a as b, c as d:
          pass
      """)
      result   = find_missing_imports(code, [{}])
      result   = _dilist2strlist(result)
      expected = ['a', 'c']
      assert expected == result
  
  def test_find_missing_imports_exception_1():
      code = dedent("""
      try:
          a = 1
      except:
          pass
      """)
      result = find_missing_imports(code, [{}])
      result = _dilist2strlist(result)
      expected = []
      assert expected == result
  
  def test_find_missing_imports_exception_2():
      code = dedent("""
      try:
          a = 1
      except SomeException:
          pass
      """)
      result = find_missing_imports(code, [{}])
      result = _dilist2strlist(result)
      expected = ['SomeException']
      assert expected == result
  
  def test_find_missing_imports_exception_3():
      code = dedent("""
      try:
          a = 1
      except SomeException as e:
          pass
      """)
      result = find_missing_imports(code, [{}])
      result = _dilist2strlist(result)
      expected = ['SomeException']
      assert expected == result
  
  # Only Python 3.8 includes type comments in the ast, so we only support this
  # there (see issue #31).
  @pytest.mark.skipif(
      sys.version_info < (3, 8),
      reason="Python 3.8+-only support.")
  def test_scan_for_import_issues_type_comment_1():
      code = dedent("""
      from typing import Sequence
      def foo(strings  # type: Sequence[str]
              ):
          pass
      """)
      missing, unused = scan_for_import_issues(code)
      assert unused == []
      assert missing == []
  
  # Python 3.8 uses the correct line number for multiline strings (the first
  # line), making _annotate_ast_startpos irrelevant. Otherwise, the logic for
  # getting this right is too hard. See issue #12.
  @pytest.mark.skipif(
      sys.version_info < (3, 8),
      reason="Python 3.8+-only support.")
  def test_scan_for_import_issues_multiline_string_1():
      code = dedent('''
      x = (
          """
          a
          """
          # blah
          "z"
      )
      ''')
      missing, unused = scan_for_import_issues(code)
      assert unused == []
      assert missing == []
  
  def test_scan_for_import_issues_dictcomp_missing_1():
      code = dedent("""
          y1 = y2 = 1234
          {(x1,y1,z1): (x2,y2,z2) for x1,x2 in []}
      """)
      missing, unused = scan_for_import_issues(code)
      assert unused == []
      assert missing == [(3, DottedIdentifier('z1')), (3, DottedIdentifier('z2'))]
  
  
  def test_scan_for_import_issues_dictcomp_unused_1():
      code = dedent("""
          import x1, x2, x3
          {123:x3 for x1,x2 in []}
      """)
      missing, unused = scan_for_import_issues(code)
      assert missing == []
      assert unused == [(2, Import('import x1')), (2, Import('import x2'))]
  
  
  def test_scan_for_import_issues_setcomp_missing_1():
      code = dedent("""
          y1 = 1234
          {(x1,y1,z1) for x1,x2 in []}
      """)
      missing, unused = scan_for_import_issues(code)
      assert unused == []
      assert missing == [(3, DottedIdentifier('z1'))]
  
  
  def test_scan_for_import_issues_setcomp_unused_1():
      code = dedent("""
          import x1, x2
          {x2 for x1 in []}
      """)
      missing, unused = scan_for_import_issues(code)
      assert missing == []
      assert unused == [(2, Import('import x1'))]
  
  
  def test_scan_for_import_issues_class_subclass_imported_class_1():
      code = dedent("""
          from m1 import C1
          class C1(C1): pass
      """)
      missing, unused = scan_for_import_issues(code)
      assert missing == []
      assert unused == []
  
  
  # This is currently buggy.
  # The problem is that we postpone the check for C1.base = m1.C1, and by the
  # time we check it, we've already replaced the thing in the scope.
  @pytest.mark.xfail
  def test_scan_for_import_issues_class_subclass_imported_class_in_func_1():
      code = dedent("""
          def f1():
              from m1 import C1
              class C1(C1): pass
      """)
      missing, unused = scan_for_import_issues(code)
      assert missing == []
      assert unused == []
  
  
  def test_scan_for_import_issues_use_then_del_in_func_1():
      code = dedent("""
          def f1():
              x1 = 1
              x1
              del x1
      """)
      missing, unused = scan_for_import_issues(code)
      assert missing == []
      assert unused == []
  
  
  def test_scan_for_import_issues_use_then_del_in_func_2():
      code = dedent("""
          def f1():
              x1 = 123
              print(x1); print(x2)
              del x1
      """)
      missing, unused = scan_for_import_issues(code)
      assert missing == [(4, DottedIdentifier('x2'))]
      assert unused == []
  
  
  def test_scan_for_import_issues_del_in_func_then_use_1():
      code = dedent("""
          def f1():
              x1 = 123
              del x1
              print(x1); print(x2)
      """)
      missing, unused = scan_for_import_issues(code)
      assert missing == [(5, DottedIdentifier('x1')), (5, DottedIdentifier('x2'))]
      assert unused == []
  
  
  def test_scan_for_import_issues_brace_identifiers_1():
      code = dedent("""
          import x1, x2, x3
          def f():
              '''{x1} {x3}'''
      """)
      missing, unused = scan_for_import_issues(code, parse_docstrings=True)
      assert missing == []
      assert unused == [(2, Import('import x2'))]
  
  
  def test_scan_for_import_issues_brace_identifiers_bad_1():
      code = dedent("""
          import x1, x2, x3
          def f():
              '''{x1} {x3} {if}'''
      """)
      missing, unused = scan_for_import_issues(code, parse_docstrings=True)
      assert missing == []
      assert unused == [(2, Import('import x2'))]
  
  
  def test_scan_for_import_issues_star_import_1():
      code = dedent("""
          import x1, y1
          x1, x2
          from m2 import *
          x3
      """)
      missing, unused = scan_for_import_issues(code, parse_docstrings=True)
      assert missing == [(3, DottedIdentifier('x2'))]
      assert unused == [(2, Import('import y1'))]
  
  
  def test_scan_for_import_issues_star_import_deferred_1():
      code = dedent("""
          import x1, y1
          def f1():
              x1, x2
          from m2 import *
          def f1():
              x3
      """)
      missing, unused = scan_for_import_issues(code, parse_docstrings=True)
      assert missing == []
      assert unused == [(2, Import('import y1'))]
  
  
  def test_scan_for_import_issues_star_import_local_1():
      code = dedent("""
          import x1, y1
          def f1():
              from m2 import *
              x2
          def f2():
              x3
          x1, x4
      """)
      missing, unused = scan_for_import_issues(code, parse_docstrings=True)
      assert missing == [(7, DottedIdentifier('x3')), (8, DottedIdentifier('x4'))]
      assert unused == [(2, Import('import y1'))]
  
  
  def test_scan_for_import_issues_comprehension_subscript_1():
      code = dedent("""
          x = []
          [123 for x[0] in []]
      """)
      missing, unused = scan_for_import_issues(code, parse_docstrings=True)
      assert missing == []
      assert unused == []
  
  
  def test_scan_for_import_issues_comprehension_subscript_missing_1():
      code = dedent("""
          [123 for x[0] in []]
      """)
      missing, unused = scan_for_import_issues(code, parse_docstrings=True)
      assert missing == [(2, DottedIdentifier('x'))]
      assert unused == []
  
  
  def test_scan_for_import_issues_comprehension_subscript_complex_1():
      code = dedent("""
          dd = []
          [(aa,bb) for (bb, cc[0], dd[0]) in []]
      """)
      missing, unused = scan_for_import_issues(code, parse_docstrings=True)
      assert missing == [(3, DottedIdentifier('aa')),
                         (3, DottedIdentifier('cc'))]
      assert unused == []
  
  
  def test_scan_for_import_issues_comprehension_attribute_1():
      code = dedent("""
          xx = []
          [123 for xx.yy in []]
      """)
      missing, unused = scan_for_import_issues(code, parse_docstrings=True)
      assert missing == []
      assert unused == []
  
  
  @pytest.mark.xfail
  def test_scan_for_import_issues_comprehension_attribute_missing_1():
      code = dedent("""
          [123 for xx.yy in []]
      """)
      missing, unused = scan_for_import_issues(code, parse_docstrings=True)
      assert missing == [(3, DottedIdentifier('xx'))]
      assert unused == []
  
  
  @pytest.mark.xfail
  def test_scan_for_import_issues_comprehension_attribute_complex_1():
      code = dedent("""
          dd = []
          [(aa,bb) for (bb, cc.cx, dd.dx) in []]
      """)
      missing, unused = scan_for_import_issues(code, parse_docstrings=True)
      assert missing == [(3, DottedIdentifier('aa')),
                         (3, DottedIdentifier('cc.cx'))]
      assert unused == []
  
  
  def test_scan_for_import_issues_comprehension_attribute_subscript_1():
      code = dedent("""
          xx = []
          [123 for xx.yy[0] in []]
      """)
      missing, unused = scan_for_import_issues(code, parse_docstrings=True)
      assert missing == []
      assert unused == []
  
  
  def test_scan_for_import_issues_comprehension_attribute_subscript_missing_1():
      code = dedent("""
          [123 for xx.yy[0] in []]
      """)
      missing, unused = scan_for_import_issues(code, parse_docstrings=True)
      assert missing == [(2, DottedIdentifier('xx.yy'))]
      assert unused == []
  
  
  def test_scan_for_import_issues_comprehension_subscript_attribute_1():
      code = dedent("""
          xx = []
          [123 for xx[0].yy in []]
      """)
      missing, unused = scan_for_import_issues(code, parse_docstrings=True)
      assert missing == []
      assert unused == []
  
  
  def test_scan_for_import_issues_comprehension_subscript_attribute_missing_1():
      code = dedent("""
          [123 for xx[0].yy in []]
      """)
      missing, unused = scan_for_import_issues(code, parse_docstrings=True)
      assert missing == [(2, DottedIdentifier('xx'))]
      assert unused == []
  
  
  def test_scan_for_import_issues_generator_comprehension_subscript_attribute_1():
      code = dedent("""
          xx = []
          (123 for xx[0].yy in [])
      """)
      missing, unused = scan_for_import_issues(code, parse_docstrings=True)
      assert missing == []
      assert unused == []
  
  
  def test_scan_for_import_issues_set_comprehension_subscript_attribute_1():
      code = dedent("""
          xx = []
          {123 for xx[0].yy in []}
      """)
      missing, unused = scan_for_import_issues(code, parse_docstrings=True)
      assert missing == []
      assert unused == []
  
  
  def test_scan_for_import_issues_dict_comprehension_subscript_attribute_1():
      code = dedent("""
          xx = []
          {123:456 for xx[0].yy in []}
      """)
      missing, unused = scan_for_import_issues(code, parse_docstrings=True)
      assert missing == []
      assert unused == []
  
  
  def test_scan_for_import_issues_setattr_1():
      code = dedent("""
          import aa, cc
          aa.xx.yy = 1
          bb.xx.yy = 1
      """)
      missing, unused = scan_for_import_issues(code)
      assert missing == [(4, DottedIdentifier('bb.xx.yy'))]
      # 'cc' should be marked as an unused-import, but 'aa' should be considered
      # used.  (This was buggy before 201907.)
      assert unused == [(2, Import('import cc'))]
  
  
  def test_scan_for_import_issues_setattr_in_func_1():
      code = dedent("""
          import aa, cc
          def f():
              aa.xx.yy = 1
              bb.xx.yy = 1
      """)
      missing, unused = scan_for_import_issues(code)
      assert missing == [(5, DottedIdentifier('bb.xx.yy'))]
      # 'cc' should be marked as an unused-import, but 'aa' should be considered
      # used.  (This was buggy before 201907.)
      assert unused == [(2, Import('import cc'))]
  
  def test_setattr_is_not_unused():
      code = dedent("""
          from a import b
          def f():
              b.xx.yy = 1
  
      """)
      missing, unused = scan_for_import_issues(code)
      # b should be considered used
      assert missing == []
      assert unused == []
  
  
  def test_load_symbol_1():
      assert load_symbol("os.path.join", {"os": os}) is os.path.join
  
  
  def test_load_symbol_2():
      assert load_symbol("os.path.join.__name__", {"os": os}) == "join"
  
  
  def test_load_symbol_missing_1():
      with pytest.raises(LoadSymbolError):
          load_symbol("os.path.join.asdfasdf", {"os": os})
  
  
  def test_load_symbol_missing_2():
      with pytest.raises(LoadSymbolError):
          load_symbol("os.path.join", {})
  
  
  def load_symbol_eval_1():
      assert 'a/b' == load_symbol("os.path.join('a','b')", {"os": os})
      assert '/'   == load_symbol("os.path.join('a','b')[1]", {"os": os})
      assert 'A'   == load_symbol("os.path.join('a','b')[0].upper()", {"os": os})
  
  
  def load_symbol_eval_2(capsys):
      assert '/' == load_symbol("(os.path.sep[0])", {}, autoimport=True,
                                allow_eval=True)
      out, _ = capsys.readouterr()
      expected = dedent("""
          [PYFLYBY] import os
      """).lstrip()
      assert expected == out
  
  
  def load_symbol_no_eval_1():
      with pytest.raises(LoadSymbolError):
          load_symbol("os.path.join('a','b')", {"os": os})
      with pytest.raises(LoadSymbolError):
          load_symbol("os.path.join('a','b')[1]", {"os": os})
      with pytest.raises(LoadSymbolError):
          load_symbol("os.path.join('a','b')[0].upper", {"os": os})
  
  
  def load_symbol_wrap_exc_1():
      class Foo89503828(object):
          def __getattr__(self, k):
              1/0
      ns = [{"foo": Foo89503828()}]
      try:
          load_symbol("foo.bar", ns)
      except LoadSymbolError as e:
          assert type(e.__cause__) == ZeroDivisionError
      else:
          assert False
  
  
  def load_symbol_wrap_exc_eval_1():
      def foo31617859():
          1/0
      ns = [{"foo": foo31617859()}]
      try:
          load_symbol("foo()", ns, auto_eval=True)
      except LoadSymbolError as e:
          assert type(e.__cause__) == ZeroDivisionError
      else:
          assert False
  
  
  def load_symbol_wrap_exc_eval_getattr_1():
      class Foo15356301(object):
          def __getattr__(self, k):
              1/0
      ns = [{"foo": Foo15356301()}]
      try:
          load_symbol("foo.bar", ns, auto_eval=True)
      except LoadSymbolError as e:
          assert type(e.__cause__) == ZeroDivisionError
      else:
          assert False
  
  
  def test_auto_eval_1():
      result = auto_eval("b64decode('aGVsbG8=')")
      assert result == b'hello'
  
  
  def test_auto_eval_locals_import_1():
      mylocals = {}
      result = auto_eval("b64decode('aGVsbG8=')", locals=mylocals)
      assert result == b'hello'
      assert mylocals["b64decode"] is __import__("base64").b64decode
  
  
  def test_auto_eval_globals_import_1():
      myglobals = {}
      result = auto_eval("b64decode('aGVsbG8=')", globals=myglobals)
      assert result == b'hello'
      assert myglobals["b64decode"] is __import__("base64").b64decode
  
  
  def test_auto_eval_custom_locals_1():
      result = auto_eval("b64decode('aGVsbG8=')",
                                     locals=dict(b64decode=lambda x: "blah"))
      assert result == 'blah'
  
  
  def test_auto_eval_custom_globals_1():
      result = auto_eval("b64decode('aGVsbG8=')",
                                     globals=dict(b64decode=lambda x: "blah"))
      assert result == 'blah'
  
  
  def test_auto_eval_exec_1():
      mylocals = dict(x=[])
      auto_eval("if True: x.append(b64decode('aGVsbG8='))",
                locals=mylocals)
      assert mylocals['x'] == [b'hello']
      assert mylocals["b64decode"] is __import__("base64").b64decode
  
  
  def test_auto_eval_no_auto_flags_ps_flagps_1(capsys):
      if PY2:
          auto_eval("print 3.00", flags=None, auto_flags=False)
          out, _ = capsys.readouterr()
          assert out == "3.0\n"
      else:
          auto_eval("print(3.00)", flags=CompilerFlags.from_int(0), auto_flags=False)
          out, _ = capsys.readouterr()
          assert out == "3.0\n"
  
  def test_auto_eval_no_auto_flags_ps_flag_pf1():
      with pytest.raises(SyntaxError):
          auto_eval("print 3.00", flags="print_function", auto_flags=False)
  
  
  @pytest.mark.skipif(
      PY3,
      reason="print function is not invalid syntax in Python 3.")
  def test_auto_eval_no_auto_flags_pf_flagps_1():
      with pytest.raises(SyntaxError):
          auto_eval("print(3.00, file=sys.stdout)", flags=None, auto_flags=False)
  
  
  def test_auto_eval_no_auto_flags_pf_flag_pf1(capsys):
      auto_eval("print(3.00, file=sys.stdout)",
                flags="print_function", auto_flags=False)
      out, _ = capsys.readouterr()
      assert out == "[PYFLYBY] import sys\n3.0\n"
  
  
  def test_auto_eval_auto_flags_ps_flagps_1(capsys):
      if PY2:
          auto_eval("print 3.00", flags=CompilerFlags.from_int(0), auto_flags=True)
          out, _ = capsys.readouterr()
          assert out == "3.0\n"
      else:
          with pytest.raises(SyntaxError):
              auto_eval("print 3.00", flags=CompilerFlags.from_int(0), auto_flags=True)
  
  @pytest.mark.skipif(
      PY3,
      reason="print not as a function cannot be valid syntax in Python 3.")
  def test_auto_eval_auto_flags_ps_flag_pf1(capsys):
      auto_eval("print 3.00", flags=CompilerFlags("print_function"), auto_flags=True)
      out, _ = capsys.readouterr()
      assert out == "3.0\n"
  
  
  def test_auto_eval_auto_flags_pf_flagps_1(capsys):
      auto_eval("print(3.00, file=sys.stdout)", flags=CompilerFlags.from_int(0), auto_flags=True)
      out, _ = capsys.readouterr()
      assert out == "[PYFLYBY] import sys\n3.0\n"
  
  
  def test_auto_eval_auto_flags_pf_flag_pf1(capsys):
      auto_eval("print(3.00, file=sys.stdout)",
                flags=CompilerFlags("print_function"), auto_flags=True)
      out, _ = capsys.readouterr()
      assert out == "[PYFLYBY] import sys\n3.0\n"
  
  
  def test_auto_eval_proxy_module_1(tpp, capsys):
      os.mkdir("%s/tornado83183065"%tpp)
      writetext(tpp/"tornado83183065/__init__.py", """
          import sys
          twister = 54170888
          class P:
              def __getattr__(self, K):
                  k = K.lower()
                  if k == K:
                      raise AttributeError
                  else:
                      return getattr(self, k)
          p = P()
          p.__dict__ = globals()
          p._m = sys.modules[__name__]
          sys.modules[__name__] = p
      """)
      writetext(tpp/"tornado83183065/hurricane.py", """
          cyclone = 79943637
      """)
      # Verify that we can auto-import a sub-module of a proxy module.
      result = auto_eval("tornado83183065.hurricane.cyclone")
      out, _ = capsys.readouterr()
      expected = dedent("""
          [PYFLYBY] import tornado83183065
          [PYFLYBY] import tornado83183065.hurricane
      """).lstrip()
      assert out == expected
      assert result == 79943637
      # Verify that the proxy module can do its magic stuff.
      result = auto_eval("tornado83183065.TWISTER")
      out, _ = capsys.readouterr()
      assert out == "[PYFLYBY] import tornado83183065\n"
      assert result == 54170888
      # Verify that the proxy module can do its magic stuff with a submodule
      # that's already imported.
      result = auto_eval("tornado83183065.HURRICANE.cyclone")
      out, _ = capsys.readouterr()
      assert out == "[PYFLYBY] import tornado83183065\n"
      assert result == 79943637
  
  
  def test_auto_import_1(capsys):
      auto_import("sys.asdfasdf", [{}])
      out, _ = capsys.readouterr()
      expected = dedent("""
          [PYFLYBY] import sys
      """).lstrip()
      assert expected == out
  
  
  def test_auto_import_multi_1(capsys):
      auto_import("sys.asdfasdf + os.asdfasdf", [{}])
      out, _ = capsys.readouterr()
      expected = dedent("""
          [PYFLYBY] import os
          [PYFLYBY] import sys
      """).lstrip()
      assert expected == out
  
  
  def test_auto_import_nothing_1(capsys):
      auto_import("sys.asdfasdf", [{"sys":sys}])
      out, _ = capsys.readouterr()
      assert out == ""
  
  
  def test_auto_import_some_1(capsys):
      auto_import("sys.asdfasdf + os.asdfasdf", [{"sys":sys}])
      out, _ = capsys.readouterr()
      expected = dedent("""
          [PYFLYBY] import os
      """).lstrip()
      assert expected == out
  
  
  def test_auto_import_custom_1(tpp, capsys):
      writetext(tpp/"trampoline77069527.py", """
          print('hello  world')
      """)
      auto_import("trampoline77069527.asdfasdf", [{}])
      out, _ = capsys.readouterr()
      expected = dedent("""
          [PYFLYBY] import trampoline77069527
          hello  world
      """).lstrip()
      assert expected == out
  
  
  def test_auto_import_custom_in_pkg_1(tpp, capsys):
      os.mkdir(str(tpp/"truck56331367"))
      writetext(tpp/"truck56331367/__init__.py", "")
      writetext(tpp/"truck56331367/tractor.py", """
          print('hello  there')
      """)
      auto_import("truck56331367.tractor", [{}])
      out, _ = capsys.readouterr()
      expected = dedent("""
          [PYFLYBY] import truck56331367
          [PYFLYBY] import truck56331367.tractor
          hello  there
      """).lstrip()
      assert expected == out
  
  
  def test_auto_import_unknown_1(capsys):
      # Verify that if we try to access something that doesn't appear to be a
      # module, we don't attempt to import it (or at least don't log any visible
      # errors for it).
      auto_import("electron91631346.asdfasdf", [{}])
      out, _ = capsys.readouterr()
      assert out == ""
  
  
  def test_auto_import_unknown_but_in_db1(tpp, capsys):
      # Verify that if we try to access something that's in the known-imports
      # database, but it doesn't actually exist, we get a visible error for it.
      db = ImportDB('import photon70447198')
      auto_import("photon70447198.asdfasdf", [{}], db=db)
      out, _ = capsys.readouterr()
      if PY2:
          expected = dedent("""
              [PYFLYBY] import photon70447198
              [PYFLYBY] Error attempting to 'import photon70447198': ImportError: No module named photon70447198
              Traceback (most recent call last):
          """).lstrip()
      else:
          expected = dedent("""
              [PYFLYBY] import photon70447198
              [PYFLYBY] Error attempting to 'import photon70447198': ModuleNotFoundError: No module named 'photon70447198'
              Traceback (most recent call last):
          """).lstrip()
  
      assert out.startswith(expected)
  
  
  def test_auto_import_fake_importerror_1(tpp, capsys):
      writetext(tpp/"proton24412521.py", """
          raise ImportError("No module named proton24412521")
      """)
      auto_import("proton24412521.asdfasdf", [{}])
      out, _ = capsys.readouterr()
      expected = dedent("""
          [PYFLYBY] import proton24412521
          [PYFLYBY] Error attempting to 'import proton24412521': ImportError: No module named proton24412521
          Traceback (most recent call last):
      """).lstrip()
      assert out.startswith(expected)
  
  
  def test_auto_import_indirect_importerror_1(tpp, capsys):
      writetext(tpp/"neutron46291483.py", """
          import baryon96446873
      """)
      auto_import("neutron46291483.asdfasdf", [{}])
      out, _ = capsys.readouterr()
      if PY2:
          expected = dedent("""
              [PYFLYBY] import neutron46291483
              [PYFLYBY] Error attempting to 'import neutron46291483': ImportError: No module named baryon96446873
              Traceback (most recent call last):
          """).lstrip()
      else:
          expected = dedent("""
              [PYFLYBY] import neutron46291483
              [PYFLYBY] Error attempting to 'import neutron46291483': ModuleNotFoundError: No module named 'baryon96446873'
              Traceback (most recent call last):
          """).lstrip()
  
      assert out.startswith(expected)
  
  
  def test_auto_import_nameerror_1(tpp, capsys):
      writetext(tpp/"lepton69688541.py", """
          foo
      """)
      auto_import("lepton69688541.asdfasdf", [{}])
      out, _ = capsys.readouterr()
      expected = dedent("""
          [PYFLYBY] import lepton69688541
          [PYFLYBY] Error attempting to 'import lepton69688541': NameError: name 'foo' is not defined
          Traceback (most recent call last):
      """).lstrip()
      assert out.startswith(expected)
  
  
  def test_post_import_hook_incomplete_import():
      db = ImportDB('import glob')
      expected = Import('import glob')
      def test_hook(val):
          assert val == expected
      auto_import("glob.glob('*')", [{}], db=db, post_import_hook=test_hook)
  
  
  def test_post_import_hook_alias_import():
      db = ImportDB('import numpy as np')
      expected = Import('import numpy as np')
      def test_hook(val):
          assert val == expected
      auto_import("np", [{}], db=db, post_import_hook=test_hook)
  
  
  def test_post_import_hook_from_statement():
      db = ImportDB('from numpy import compat')
      expected = Import('from numpy import compat')
      def test_hook(val):
          assert val == expected
      auto_import("compat", [{}], db=db, post_import_hook=test_hook)
  
  
  def test_post_import_hook_fullname():
      db = ImportDB('import numpy.compat')
      expected = Import('import numpy.compat')
      def test_hook(val):
          assert val == expected
      auto_import("numpy.compat", [{}], db=db, post_import_hook=test_hook)
  