11from __future__ import annotations
22
3+ import logging
34import traceback
45from contextlib import redirect_stderr
56from contextlib import redirect_stdout
1213
1314from asgiref .sync import sync_to_async
1415
16+ logger = logging .getLogger (__name__ )
17+
1518
1619class DjangoShell :
1720 def __init__ (self ):
21+ logger .debug ("Initializing %s" , self .__class__ .__name__ )
22+
1823 from django import setup
1924 from django .apps import apps
2025
2126 if not apps .ready : # pragma: no cover
27+ logger .info ("Django not initialized, running django.setup()" )
28+
2229 setup ()
2330
31+ logger .debug ("Django setup completed" )
32+ else :
33+ logger .debug ("Django already initialized, skipping setup" )
34+
2435 self .globals : dict [str , Any ] = {}
2536 self .history : list [Result ] = []
2637
38+ logger .info ("Shell initialized successfully" )
39+
2740 def reset (self ):
41+ logger .info ("Shell reset - clearing globals and history" )
42+
2843 self .globals = {}
2944 self .history = []
3045
@@ -51,20 +66,44 @@ def _execute(self, code: str, timeout: int | None = None) -> Result:
5166 Note: This synchronous method contains the actual execution logic.
5267 Use `execute()` for async contexts or `_execute()` for sync/testing.
5368 """
69+ code_preview = (code [:100 ] + "..." if len (code ) > 100 else code ).replace (
70+ "\n " , "\\ n"
71+ )
72+ logger .info ("Executing code: %s" , code_preview )
73+
5474 stdout = StringIO ()
5575 stderr = StringIO ()
5676
5777 with redirect_stdout (stdout ), redirect_stderr (stderr ):
5878 try :
5979 code , setup , code_type = parse_code (code )
6080
81+ logger .debug (
82+ "Execution type: %s, has setup: %s" , code_type , bool (setup )
83+ )
84+ logger .debug (
85+ "Code to execute: %s" ,
86+ code [:200 ] + "..." if len (code ) > 200 else code ,
87+ )
88+
6189 # Execute setup, if any (only applicable to expressions)
6290 if setup :
91+ logger .debug (
92+ "Setup code: %s" ,
93+ setup [:200 ] + "..." if len (setup ) > 200 else setup ,
94+ )
95+
6396 exec (setup , self .globals )
6497
6598 match code_type :
6699 case "expression" :
67100 value = eval (code , self .globals )
101+
102+ logger .debug (
103+ "Expression executed successfully, result type: %s" ,
104+ type (value ).__name__ ,
105+ )
106+
68107 return self .save_result (
69108 ExpressionResult (
70109 code = code ,
@@ -75,6 +114,9 @@ def _execute(self, code: str, timeout: int | None = None) -> Result:
75114 )
76115 case "statement" :
77116 exec (code , self .globals )
117+
118+ logger .debug ("Statement executed successfully" )
119+
78120 return self .save_result (
79121 StatementResult (
80122 code = code ,
@@ -84,6 +126,13 @@ def _execute(self, code: str, timeout: int | None = None) -> Result:
84126 )
85127
86128 except Exception as e :
129+ logger .error (
130+ "Exception during code execution: %s - Code: %s" ,
131+ f"{ type (e ).__name__ } : { e } " ,
132+ code_preview ,
133+ )
134+ logger .debug ("Full traceback for error:" , exc_info = True )
135+
87136 return self .save_result (
88137 ErrorResult (
89138 code = code ,
@@ -136,6 +185,21 @@ class ExpressionResult:
136185 stderr : str
137186 timestamp : datetime = field (default_factory = datetime .now )
138187
188+ def __post_init__ (self ):
189+ logger .debug (
190+ "%s created - value type: %s" ,
191+ self .__class__ .__name__ ,
192+ type (self .value ).__name__ ,
193+ )
194+ logger .debug ("%s.value: %s" , self .__class__ .__name__ , repr (self .value )[:200 ])
195+ if self .stdout :
196+ logger .debug ("%s.stdout: %s" , self .__class__ .__name__ , self .stdout [:200 ])
197+ if self .stderr :
198+ logger .debug ("%s.stderr: %s" , self .__class__ .__name__ , self .stderr [:200 ])
199+ logger .debug (
200+ "%s output (for LLM): %s" , self .__class__ .__name__ , self .output [:500 ]
201+ )
202+
139203 @property
140204 def output (self ) -> str :
141205 value = repr (self .value )
@@ -170,6 +234,16 @@ class StatementResult:
170234 stderr : str
171235 timestamp : datetime = field (default_factory = datetime .now )
172236
237+ def __post_init__ (self ):
238+ logger .debug ("%s created" , self .__class__ .__name__ )
239+ if self .stdout :
240+ logger .debug ("%s.stdout: %s" , self .__class__ .__name__ , self .stdout [:200 ])
241+ if self .stderr :
242+ logger .debug ("%s.stderr: %s" , self .__class__ .__name__ , self .stderr [:200 ])
243+ logger .debug (
244+ "%s output (for LLM): %s" , self .__class__ .__name__ , self .output [:500 ]
245+ )
246+
173247 @property
174248 def output (self ) -> str :
175249 return self .stdout or "OK"
@@ -183,11 +257,27 @@ class ErrorResult:
183257 stderr : str
184258 timestamp : datetime = field (default_factory = datetime .now )
185259
260+ def __post_init__ (self ):
261+ logger .debug (
262+ "%s created - exception type: %s" ,
263+ self .__class__ .__name__ ,
264+ type (self .exception ).__name__ ,
265+ )
266+ logger .debug ("%s.message: %s" , self .__class__ .__name__ , str (self .exception ))
267+ if self .stdout :
268+ logger .debug ("%s.stdout: %s" , self .__class__ .__name__ , self .stdout [:200 ])
269+ if self .stderr :
270+ logger .debug ("%s.stderr: %s" , self .__class__ .__name__ , self .stderr [:200 ])
271+ logger .debug (
272+ "%s output (filtered for LLM): %s" ,
273+ self .__class__ .__name__ ,
274+ self .output [:500 ],
275+ )
276+
186277 @property
187278 def output (self ) -> str :
188279 error_type = self .exception .__class__ .__name__
189280
190- # Format the stored exception's traceback
191281 tb_str = "" .join (
192282 traceback .format_exception (
193283 type (self .exception ), self .exception , self .exception .__traceback__
0 commit comments