@@ -8142,6 +8142,95 @@ class B(Generic[T], _EasyStr):
81428142 self .assertEqual (result , check_expected )
81438143 del check_expected
81448144
8145+ def test_evaluate_with_type_params (self ):
8146+ class Gen [T ]:
8147+ alias = int
8148+
8149+ with self .assertRaises (NameError ):
8150+ ForwardRef ("T" ).evaluate ()
8151+ with self .assertRaises (NameError ):
8152+ ForwardRef ("T" ).evaluate (type_params = ())
8153+ with self .assertRaises (NameError ):
8154+ ForwardRef ("T" ).evaluate (owner = int )
8155+
8156+ (T ,) = Gen .__type_params__
8157+ self .assertIs (ForwardRef ("T" ).evaluate (type_params = Gen .__type_params__ ), T )
8158+ self .assertIs (ForwardRef ("T" ).evaluate (owner = Gen ), T )
8159+
8160+ with self .assertRaises (NameError ):
8161+ ForwardRef ("alias" ).evaluate (type_params = Gen .__type_params__ )
8162+ self .assertIs (ForwardRef ("alias" ).evaluate (owner = Gen ), int )
8163+ # If you pass custom locals, we don't look at the owner's locals
8164+ with self .assertRaises (NameError ):
8165+ ForwardRef ("alias" ).evaluate (owner = Gen , locals = {})
8166+ # But if the name exists in the locals, it works
8167+ self .assertIs (
8168+ ForwardRef ("alias" ).evaluate (owner = Gen , locals = {"alias" : str }), str
8169+ )
8170+
8171+ def test_fwdref_with_module (self ):
8172+ self .assertIs (ForwardRef ("Format" , module = "annotationlib" ).evaluate (), Format )
8173+ self .assertIs (
8174+ ForwardRef ("Counter" , module = "collections" ).evaluate (), collections .Counter
8175+ )
8176+ self .assertEqual (
8177+ ForwardRef ("Counter[int]" , module = "collections" ).evaluate (),
8178+ collections .Counter [int ],
8179+ )
8180+
8181+ with self .assertRaises (NameError ):
8182+ # If globals are passed explicitly, we don't look at the module dict
8183+ ForwardRef ("Format" , module = "annotationlib" ).evaluate (globals = {})
8184+
8185+ def test_fwdref_to_builtin (self ):
8186+ self .assertIs (ForwardRef ("int" ).evaluate (), int )
8187+ self .assertIs (ForwardRef ("int" , module = "collections" ).evaluate (), int )
8188+ self .assertIs (ForwardRef ("int" , owner = str ).evaluate (), int )
8189+
8190+ # builtins are still searched with explicit globals
8191+ self .assertIs (ForwardRef ("int" ).evaluate (globals = {}), int )
8192+
8193+ # explicit values in globals have precedence
8194+ obj = object ()
8195+ self .assertIs (ForwardRef ("int" ).evaluate (globals = {"int" : obj }), obj )
8196+
8197+ def test_fwdref_value_is_cached (self ):
8198+ fr = ForwardRef ("hello" )
8199+ with self .assertRaises (NameError ):
8200+ fr .evaluate ()
8201+ self .assertIs (fr .evaluate (globals = {"hello" : str }), str )
8202+ self .assertIs (fr .evaluate (), str )
8203+
8204+ def test_fwdref_with_owner (self ):
8205+ self .assertEqual (
8206+ ForwardRef ("Counter[int]" , owner = collections ).evaluate (),
8207+ collections .Counter [int ],
8208+ )
8209+
8210+ def test_name_lookup_without_eval (self ):
8211+ # test the codepath where we look up simple names directly in the
8212+ # namespaces without going through eval()
8213+ self .assertIs (ForwardRef ("int" ).evaluate (), int )
8214+ self .assertIs (ForwardRef ("int" ).evaluate (locals = {"int" : str }), str )
8215+ self .assertIs (
8216+ ForwardRef ("int" ).evaluate (locals = {"int" : float }, globals = {"int" : str }),
8217+ float ,
8218+ )
8219+ self .assertIs (ForwardRef ("int" ).evaluate (globals = {"int" : str }), str )
8220+ with support .swap_attr (builtins , "int" , dict ):
8221+ self .assertIs (ForwardRef ("int" ).evaluate (), dict )
8222+
8223+ with self .assertRaises (NameError ):
8224+ ForwardRef ("doesntexist" ).evaluate ()
8225+
8226+ def test_fwdref_invalid_syntax (self ):
8227+ fr = ForwardRef ("if" )
8228+ with self .assertRaises (SyntaxError ):
8229+ fr .evaluate ()
8230+ fr = ForwardRef ("1+" )
8231+ with self .assertRaises (SyntaxError ):
8232+ fr .evaluate ()
8233+
81458234
81468235if __name__ == '__main__' :
81478236 main ()
0 commit comments