11import ast
22import dis
33import os
4+ import random
45import sys
6+ import tokenize
57import unittest
68import warnings
79import weakref
@@ -25,6 +27,9 @@ def to_tuple(t):
2527 result .append (to_tuple (getattr (t , f )))
2628 return tuple (result )
2729
30+ STDLIB = os .path .dirname (ast .__file__ )
31+ STDLIB_FILES = [fn for fn in os .listdir (STDLIB ) if fn .endswith (".py" )]
32+ STDLIB_FILES .extend (["test/test_grammar.py" , "test/test_unpack_ex.py" ])
2833
2934# These tests are compiled through "exec"
3035# There should be at least one test per statement
@@ -654,6 +659,110 @@ def test_ast_asdl_signature(self):
654659 expressions [0 ] = f"expr = { ast .expr .__subclasses__ ()[0 ].__doc__ } "
655660 self .assertCountEqual (ast .expr .__doc__ .split ("\n " ), expressions )
656661
662+ self .assertTrue (ast .compare (ast .parse ("x = 10" ), ast .parse ("x = 10" )))
663+ self .assertFalse (ast .compare (ast .parse ("x = 10" ), ast .parse ("" )))
664+ self .assertFalse (ast .compare (ast .parse ("x = 10" ), ast .parse ("x" )))
665+ self .assertFalse (
666+ ast .compare (ast .parse ("x = 10;y = 20" ), ast .parse ("class C:pass" ))
667+ )
668+
669+ def test_compare_literals (self ):
670+ constants = (
671+ - 20 ,
672+ 20 ,
673+ 20.0 ,
674+ 1 ,
675+ 1.0 ,
676+ True ,
677+ 0 ,
678+ False ,
679+ frozenset (),
680+ tuple (),
681+ "ABCD" ,
682+ "abcd" ,
683+ "中文字" ,
684+ 1e1000 ,
685+ - 1e1000 ,
686+ )
687+ for next_index , constant in enumerate (constants [:- 1 ], 1 ):
688+ next_constant = constants [next_index ]
689+ with self .subTest (literal = constant , next_literal = next_constant ):
690+ self .assertTrue (
691+ ast .compare (ast .Constant (constant ), ast .Constant (constant ))
692+ )
693+ self .assertFalse (
694+ ast .compare (
695+ ast .Constant (constant ), ast .Constant (next_constant )
696+ )
697+ )
698+
699+ same_looking_literal_cases = [
700+ {1 , 1.0 , True , 1 + 0j },
701+ {0 , 0.0 , False , 0 + 0j },
702+ ]
703+ for same_looking_literals in same_looking_literal_cases :
704+ for literal in same_looking_literals :
705+ for same_looking_literal in same_looking_literals - {literal }:
706+ self .assertFalse (
707+ ast .compare (
708+ ast .Constant (literal ),
709+ ast .Constant (same_looking_literal ),
710+ )
711+ )
712+
713+ def test_compare_fieldless (self ):
714+ self .assertTrue (ast .compare (ast .Add (), ast .Add ()))
715+ self .assertFalse (ast .compare (ast .Sub (), ast .Add ()))
716+ self .assertFalse (ast .compare (ast .Sub (), ast .Constant ()))
717+
718+ def test_compare_stdlib (self ):
719+ if support .is_resource_enabled ("cpu" ):
720+ files = STDLIB_FILES
721+ else :
722+ files = random .sample (STDLIB_FILES , 10 )
723+
724+ for module in files :
725+ with self .subTest (module ):
726+ fn = os .path .join (STDLIB , module )
727+ with tokenize .open (fn ) as fp :
728+ source = fp .read ()
729+ a = ast .parse (source , fn )
730+ b = ast .parse (source , fn )
731+ self .assertTrue (
732+ ast .compare (a , b ), f"{ ast .dump (a )} != { ast .dump (b )} "
733+ )
734+
735+ def test_compare_tests (self ):
736+ for mode , sources in (
737+ ("exec" , exec_tests ),
738+ ("eval" , eval_tests ),
739+ ("single" , single_tests ),
740+ ):
741+ for source in sources :
742+ a = ast .parse (source , mode = mode )
743+ b = ast .parse (source , mode = mode )
744+ self .assertTrue (
745+ ast .compare (a , b ), f"{ ast .dump (a )} != { ast .dump (b )} "
746+ )
747+
748+ def test_compare_options (self ):
749+ def parse (a , b ):
750+ return ast .parse (a ), ast .parse (b )
751+
752+ a , b = parse ("2 + 2" , "2+2" )
753+ self .assertTrue (ast .compare (a , b , compare_attributes = False ))
754+ self .assertFalse (ast .compare (a , b , compare_attributes = True ))
755+
756+ a , b = parse ("1" , "1.0" )
757+ self .assertTrue (ast .compare (a , b , compare_types = False ))
758+ self .assertFalse (ast .compare (a , b , compare_types = True ))
759+
760+ a , b = parse ("1" , "2" )
761+ self .assertTrue (ast .compare (a , b , compare_fields = False , compare_attributes = False ))
762+ self .assertTrue (ast .compare (a , b , compare_fields = False , compare_attributes = True ))
763+ self .assertFalse (ast .compare (a , b , compare_fields = True , compare_attributes = False ))
764+ self .assertFalse (ast .compare (a , b , compare_fields = True , compare_attributes = True ))
765+
657766
658767class ASTHelpers_Test (unittest .TestCase ):
659768 maxDiff = None
@@ -1369,12 +1478,9 @@ def test_nameconstant(self):
13691478 self .expr (ast .NameConstant (4 ))
13701479
13711480 def test_stdlib_validates (self ):
1372- stdlib = os .path .dirname (ast .__file__ )
1373- tests = [fn for fn in os .listdir (stdlib ) if fn .endswith (".py" )]
1374- tests .extend (["test/test_grammar.py" , "test/test_unpack_ex.py" ])
1375- for module in tests :
1481+ for module in STDLIB_FILES :
13761482 with self .subTest (module ):
1377- fn = os .path .join (stdlib , module )
1483+ fn = os .path .join (STDLIB , module )
13781484 with open (fn , "r" , encoding = "utf-8" ) as fp :
13791485 source = fp .read ()
13801486 mod = ast .parse (source , fn )
0 commit comments