@@ -72,51 +72,64 @@ def set_result(x: object):
72
72
nonlocal ui_result
73
73
ui_result = cast (Tag , x )
74
74
75
+ prev_displayhook = sys .displayhook
75
76
sys .displayhook = set_result
76
77
77
- reset_top_level_recall_context_manager ()
78
- get_top_level_recall_context_manager ().__enter__ ()
79
-
80
- file_path = str (file .resolve ())
78
+ try :
79
+ reset_top_level_recall_context_manager ()
80
+ get_top_level_recall_context_manager ().__enter__ ()
81
+
82
+ file_path = str (file .resolve ())
83
+
84
+ var_context : dict [str , object ] = {
85
+ "__file__" : file_path ,
86
+ display_decorator_func_name : _display_decorator_function_def ,
87
+ }
88
+
89
+ # Execute each top-level node in the AST
90
+ for node in tree .body :
91
+ if isinstance (node , (ast .FunctionDef , ast .AsyncFunctionDef )):
92
+ exec (
93
+ compile (ast .Module ([node ], type_ignores = []), file_path , "exec" ),
94
+ var_context ,
95
+ var_context ,
96
+ )
97
+ else :
98
+ exec (
99
+ compile (
100
+ ast .Interactive ([node ], type_ignores = []), file_path , "single"
101
+ ),
102
+ var_context ,
103
+ var_context ,
104
+ )
105
+
106
+ # When we called the function to get the top level recall context manager, we didn't
107
+ # store the result in a variable and re-use that variable here. That is intentional,
108
+ # because during the evaluation of the app code,
109
+ # replace_top_level_recall_context_manager() may have been called, which swaps
110
+ # out the context manager, and it's the new one that we need to exit here.
111
+ get_top_level_recall_context_manager ().__exit__ (None , None , None )
112
+
113
+ # If we're running as an Express app but there's also a top-level item named app
114
+ # which is a shiny.App object, the user probably made a mistake.
115
+ if "app" in var_context and isinstance (var_context ["app" ], App ):
116
+ raise RuntimeError (
117
+ "This looks like a Shiny Express app because it imports shiny.express, "
118
+ "but it also looks like a Shiny Classic app because it has a variable named "
119
+ "`app` which is a shiny.App object. Remove either the shiny.express import, "
120
+ "or the app=App()."
121
+ )
81
122
82
- var_context : dict [str , object ] = {
83
- "__file__" : file_path ,
84
- display_decorator_func_name : _display_decorator_function_def ,
85
- }
123
+ return ui_result
86
124
87
- # Execute each top-level node in the AST
88
- for node in tree .body :
89
- if isinstance (node , (ast .FunctionDef , ast .AsyncFunctionDef )):
90
- exec (
91
- compile (ast .Module ([node ], type_ignores = []), file_path , "exec" ),
92
- var_context ,
93
- var_context ,
94
- )
95
- else :
96
- exec (
97
- compile (ast .Interactive ([node ], type_ignores = []), file_path , "single" ),
98
- var_context ,
99
- var_context ,
100
- )
125
+ except AttributeError as e :
126
+ # Need to catch AttributeError and convert to a different type of error, because
127
+ # uvicorn specifically catches AttributeErrors and prints an error message that
128
+ # is helpful for normal ASGI apps, but misleading in the case of Shiny Express.
129
+ raise RuntimeError (e ) from e
101
130
102
- # When we called the function to get the top level recall context manager, we didn't
103
- # store the result in a variable and re-use that variable here. That is intentional,
104
- # because during the evaluation of the app code,
105
- # replace_top_level_recall_context_manager() may have been called, which swaps
106
- # out the context manager, and it's the new one that we need to exit here.
107
- get_top_level_recall_context_manager ().__exit__ (None , None , None )
108
-
109
- # If we're running as an Express app but there's also a top-level item named app
110
- # which is a shiny.App object, the user probably made a mistake.
111
- if "app" in var_context and isinstance (var_context ["app" ], App ):
112
- raise RuntimeError (
113
- "This looks like a Shiny Express app because it imports shiny.express, "
114
- "but it also looks like a Shiny Classic app because it has a variable named "
115
- "`app` which is a shiny.App object. Remove either the shiny.express import, "
116
- "or the app=App()."
117
- )
118
-
119
- return ui_result
131
+ finally :
132
+ sys .displayhook = prev_displayhook
120
133
121
134
122
135
_top_level_recall_context_manager : RecallContextManager [Tag ]
0 commit comments