(root)/
Python-3.12.0/
Lib/
test/
test_symtable.py
       1  """
       2  Test the API of the symtable module.
       3  """
       4  import symtable
       5  import unittest
       6  
       7  
       8  
       9  TEST_CODE = """
      10  import sys
      11  
      12  glob = 42
      13  some_var = 12
      14  some_non_assigned_global_var = 11
      15  some_assigned_global_var = 11
      16  
      17  class Mine:
      18      instance_var = 24
      19      def a_method(p1, p2):
      20          pass
      21  
      22  def spam(a, b, *var, **kw):
      23      global bar
      24      global some_assigned_global_var
      25      some_assigned_global_var = 12
      26      bar = 47
      27      some_var = 10
      28      x = 23
      29      glob
      30      def internal():
      31          return x
      32      def other_internal():
      33          nonlocal some_var
      34          some_var = 3
      35          return some_var
      36      return internal
      37  
      38  def foo():
      39      pass
      40  
      41  def namespace_test(): pass
      42  def namespace_test(): pass
      43  
      44  type Alias = int
      45  type GenericAlias[T] = list[T]
      46  
      47  def generic_spam[T](a):
      48      pass
      49  
      50  class GenericMine[T: int]:
      51      pass
      52  """
      53  
      54  
      55  def find_block(block, name):
      56      for ch in block.get_children():
      57          if ch.get_name() == name:
      58              return ch
      59  
      60  
      61  class ESC[4;38;5;81mSymtableTest(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
      62  
      63      top = symtable.symtable(TEST_CODE, "?", "exec")
      64      # These correspond to scopes in TEST_CODE
      65      Mine = find_block(top, "Mine")
      66      a_method = find_block(Mine, "a_method")
      67      spam = find_block(top, "spam")
      68      internal = find_block(spam, "internal")
      69      other_internal = find_block(spam, "other_internal")
      70      foo = find_block(top, "foo")
      71      Alias = find_block(top, "Alias")
      72      GenericAlias = find_block(top, "GenericAlias")
      73      GenericAlias_inner = find_block(GenericAlias, "GenericAlias")
      74      generic_spam = find_block(top, "generic_spam")
      75      generic_spam_inner = find_block(generic_spam, "generic_spam")
      76      GenericMine = find_block(top, "GenericMine")
      77      GenericMine_inner = find_block(GenericMine, "GenericMine")
      78      T = find_block(GenericMine, "T")
      79  
      80      def test_type(self):
      81          self.assertEqual(self.top.get_type(), "module")
      82          self.assertEqual(self.Mine.get_type(), "class")
      83          self.assertEqual(self.a_method.get_type(), "function")
      84          self.assertEqual(self.spam.get_type(), "function")
      85          self.assertEqual(self.internal.get_type(), "function")
      86          self.assertEqual(self.foo.get_type(), "function")
      87          self.assertEqual(self.Alias.get_type(), "type alias")
      88          self.assertEqual(self.GenericAlias.get_type(), "type parameter")
      89          self.assertEqual(self.GenericAlias_inner.get_type(), "type alias")
      90          self.assertEqual(self.generic_spam.get_type(), "type parameter")
      91          self.assertEqual(self.generic_spam_inner.get_type(), "function")
      92          self.assertEqual(self.GenericMine.get_type(), "type parameter")
      93          self.assertEqual(self.GenericMine_inner.get_type(), "class")
      94          self.assertEqual(self.T.get_type(), "TypeVar bound")
      95  
      96      def test_id(self):
      97          self.assertGreater(self.top.get_id(), 0)
      98          self.assertGreater(self.Mine.get_id(), 0)
      99          self.assertGreater(self.a_method.get_id(), 0)
     100          self.assertGreater(self.spam.get_id(), 0)
     101          self.assertGreater(self.internal.get_id(), 0)
     102          self.assertGreater(self.foo.get_id(), 0)
     103          self.assertGreater(self.Alias.get_id(), 0)
     104          self.assertGreater(self.GenericAlias.get_id(), 0)
     105          self.assertGreater(self.generic_spam.get_id(), 0)
     106          self.assertGreater(self.GenericMine.get_id(), 0)
     107  
     108      def test_optimized(self):
     109          self.assertFalse(self.top.is_optimized())
     110  
     111          self.assertTrue(self.spam.is_optimized())
     112  
     113      def test_nested(self):
     114          self.assertFalse(self.top.is_nested())
     115          self.assertFalse(self.Mine.is_nested())
     116          self.assertFalse(self.spam.is_nested())
     117          self.assertTrue(self.internal.is_nested())
     118  
     119      def test_children(self):
     120          self.assertTrue(self.top.has_children())
     121          self.assertTrue(self.Mine.has_children())
     122          self.assertFalse(self.foo.has_children())
     123  
     124      def test_lineno(self):
     125          self.assertEqual(self.top.get_lineno(), 0)
     126          self.assertEqual(self.spam.get_lineno(), 14)
     127  
     128      def test_function_info(self):
     129          func = self.spam
     130          self.assertEqual(sorted(func.get_parameters()), ["a", "b", "kw", "var"])
     131          expected = ['a', 'b', 'internal', 'kw', 'other_internal', 'some_var', 'var', 'x']
     132          self.assertEqual(sorted(func.get_locals()), expected)
     133          self.assertEqual(sorted(func.get_globals()), ["bar", "glob", "some_assigned_global_var"])
     134          self.assertEqual(self.internal.get_frees(), ("x",))
     135  
     136      def test_globals(self):
     137          self.assertTrue(self.spam.lookup("glob").is_global())
     138          self.assertFalse(self.spam.lookup("glob").is_declared_global())
     139          self.assertTrue(self.spam.lookup("bar").is_global())
     140          self.assertTrue(self.spam.lookup("bar").is_declared_global())
     141          self.assertFalse(self.internal.lookup("x").is_global())
     142          self.assertFalse(self.Mine.lookup("instance_var").is_global())
     143          self.assertTrue(self.spam.lookup("bar").is_global())
     144          # Module-scope globals are both global and local
     145          self.assertTrue(self.top.lookup("some_non_assigned_global_var").is_global())
     146          self.assertTrue(self.top.lookup("some_assigned_global_var").is_global())
     147  
     148      def test_nonlocal(self):
     149          self.assertFalse(self.spam.lookup("some_var").is_nonlocal())
     150          self.assertTrue(self.other_internal.lookup("some_var").is_nonlocal())
     151          expected = ("some_var",)
     152          self.assertEqual(self.other_internal.get_nonlocals(), expected)
     153  
     154      def test_local(self):
     155          self.assertTrue(self.spam.lookup("x").is_local())
     156          self.assertFalse(self.spam.lookup("bar").is_local())
     157          # Module-scope globals are both global and local
     158          self.assertTrue(self.top.lookup("some_non_assigned_global_var").is_local())
     159          self.assertTrue(self.top.lookup("some_assigned_global_var").is_local())
     160  
     161      def test_free(self):
     162          self.assertTrue(self.internal.lookup("x").is_free())
     163  
     164      def test_referenced(self):
     165          self.assertTrue(self.internal.lookup("x").is_referenced())
     166          self.assertTrue(self.spam.lookup("internal").is_referenced())
     167          self.assertFalse(self.spam.lookup("x").is_referenced())
     168  
     169      def test_parameters(self):
     170          for sym in ("a", "var", "kw"):
     171              self.assertTrue(self.spam.lookup(sym).is_parameter())
     172          self.assertFalse(self.spam.lookup("x").is_parameter())
     173  
     174      def test_symbol_lookup(self):
     175          self.assertEqual(len(self.top.get_identifiers()),
     176                           len(self.top.get_symbols()))
     177  
     178          self.assertRaises(KeyError, self.top.lookup, "not_here")
     179  
     180      def test_namespaces(self):
     181          self.assertTrue(self.top.lookup("Mine").is_namespace())
     182          self.assertTrue(self.Mine.lookup("a_method").is_namespace())
     183          self.assertTrue(self.top.lookup("spam").is_namespace())
     184          self.assertTrue(self.spam.lookup("internal").is_namespace())
     185          self.assertTrue(self.top.lookup("namespace_test").is_namespace())
     186          self.assertFalse(self.spam.lookup("x").is_namespace())
     187  
     188          self.assertTrue(self.top.lookup("spam").get_namespace() is self.spam)
     189          ns_test = self.top.lookup("namespace_test")
     190          self.assertEqual(len(ns_test.get_namespaces()), 2)
     191          self.assertRaises(ValueError, ns_test.get_namespace)
     192  
     193          ns_test_2 = self.top.lookup("glob")
     194          self.assertEqual(len(ns_test_2.get_namespaces()), 0)
     195          self.assertRaises(ValueError, ns_test_2.get_namespace)
     196  
     197      def test_assigned(self):
     198          self.assertTrue(self.spam.lookup("x").is_assigned())
     199          self.assertTrue(self.spam.lookup("bar").is_assigned())
     200          self.assertTrue(self.top.lookup("spam").is_assigned())
     201          self.assertTrue(self.Mine.lookup("a_method").is_assigned())
     202          self.assertFalse(self.internal.lookup("x").is_assigned())
     203  
     204      def test_annotated(self):
     205          st1 = symtable.symtable('def f():\n    x: int\n', 'test', 'exec')
     206          st2 = st1.get_children()[0]
     207          self.assertTrue(st2.lookup('x').is_local())
     208          self.assertTrue(st2.lookup('x').is_annotated())
     209          self.assertFalse(st2.lookup('x').is_global())
     210          st3 = symtable.symtable('def f():\n    x = 1\n', 'test', 'exec')
     211          st4 = st3.get_children()[0]
     212          self.assertTrue(st4.lookup('x').is_local())
     213          self.assertFalse(st4.lookup('x').is_annotated())
     214  
     215          # Test that annotations in the global scope are valid after the
     216          # variable is declared as nonlocal.
     217          st5 = symtable.symtable('global x\nx: int', 'test', 'exec')
     218          self.assertTrue(st5.lookup("x").is_global())
     219  
     220          # Test that annotations for nonlocals are valid after the
     221          # variable is declared as nonlocal.
     222          st6 = symtable.symtable('def g():\n'
     223                                  '    x = 2\n'
     224                                  '    def f():\n'
     225                                  '        nonlocal x\n'
     226                                  '    x: int',
     227                                  'test', 'exec')
     228  
     229      def test_imported(self):
     230          self.assertTrue(self.top.lookup("sys").is_imported())
     231  
     232      def test_name(self):
     233          self.assertEqual(self.top.get_name(), "top")
     234          self.assertEqual(self.spam.get_name(), "spam")
     235          self.assertEqual(self.spam.lookup("x").get_name(), "x")
     236          self.assertEqual(self.Mine.get_name(), "Mine")
     237  
     238      def test_class_info(self):
     239          self.assertEqual(self.Mine.get_methods(), ('a_method',))
     240  
     241      def test_filename_correct(self):
     242          ### Bug tickler: SyntaxError file name correct whether error raised
     243          ### while parsing or building symbol table.
     244          def checkfilename(brokencode, offset):
     245              try:
     246                  symtable.symtable(brokencode, "spam", "exec")
     247              except SyntaxError as e:
     248                  self.assertEqual(e.filename, "spam")
     249                  self.assertEqual(e.lineno, 1)
     250                  self.assertEqual(e.offset, offset)
     251              else:
     252                  self.fail("no SyntaxError for %r" % (brokencode,))
     253          checkfilename("def f(x): foo)(", 14)  # parse-time
     254          checkfilename("def f(x): global x", 11)  # symtable-build-time
     255          symtable.symtable("pass", b"spam", "exec")
     256          with self.assertRaises(TypeError):
     257              symtable.symtable("pass", bytearray(b"spam"), "exec")
     258          with self.assertRaises(TypeError):
     259              symtable.symtable("pass", memoryview(b"spam"), "exec")
     260          with self.assertRaises(TypeError):
     261              symtable.symtable("pass", list(b"spam"), "exec")
     262  
     263      def test_eval(self):
     264          symbols = symtable.symtable("42", "?", "eval")
     265  
     266      def test_single(self):
     267          symbols = symtable.symtable("42", "?", "single")
     268  
     269      def test_exec(self):
     270          symbols = symtable.symtable("def f(x): return x", "?", "exec")
     271  
     272      def test_bytes(self):
     273          top = symtable.symtable(TEST_CODE.encode('utf8'), "?", "exec")
     274          self.assertIsNotNone(find_block(top, "Mine"))
     275  
     276          code = b'# -*- coding: iso8859-15 -*-\nclass \xb4: pass\n'
     277  
     278          top = symtable.symtable(code, "?", "exec")
     279          self.assertIsNotNone(find_block(top, "\u017d"))
     280  
     281      def test_symtable_repr(self):
     282          self.assertEqual(str(self.top), "<SymbolTable for module ?>")
     283          self.assertEqual(str(self.spam), "<Function SymbolTable for spam in ?>")
     284  
     285  
     286  if __name__ == '__main__':
     287      unittest.main()