44from pydetector import detector
55from traceback import format_exc
66from python_driver .version import __version__
7- from typing import (Any , IO , NewType , Tuple , cast , List , Iterator , Dict )
7+ from typing import (Any , IO , NewType , Tuple , cast , List , Iterator , Dict , Optional )
88
99# typing.AnyStr is bugged on this version of MyPy, so...:
1010AnyStr = Any
@@ -30,6 +30,14 @@ class RequestCheckException(Exception):
3030 """
3131 pass
3232
33+ class EmptyCodeException (Exception ):
34+ """
35+ Exception produced when the input code is empty. This should
36+ generate an error (because we can't parse anything) but not
37+ a fatal one (e. g. empty __init__.py files)
38+ """
39+ pass
40+
3341
3442def asstr (txt : AnyStr ) -> str :
3543 """
@@ -67,7 +75,7 @@ def _tostr_request(self, request: RawRequest) -> Request:
6775 """
6876 pass
6977
70- def _check_input_request (self , request : RawRequest ) -> Tuple [str , str ]:
78+ def _parse_input_request (self , request : RawRequest ) -> Tuple [str , str ]:
7179 """
7280 Check the incoming request package and validate that the 'content' and
7381 'language' keys are not missing and that 'language' and 'language_version'
@@ -77,13 +85,13 @@ def _check_input_request(self, request: RawRequest) -> Tuple[str, str]:
7785 :param request: The incoming request, already deserialized.
7886
7987 .. raises::
80- RequestCheckException if the request failed to validate .
88+ EmptyCodeException if the code was empty .
8189 """
8290 str_request = self ._tostr_request (request )
8391 code = asstr (str_request .get ('content' , '' ))
8492
8593 if not code :
86- raise RequestCheckException ('Bad input message, missing content' )
94+ raise EmptyCodeException ('Bad input message, missing content' )
8795
8896 return code , asstr (str_request .get ('filepath' , '' ))
8997
@@ -99,7 +107,8 @@ def _send_response(self, response: Response) -> None:
99107 """
100108 pass
101109
102- def _return_error (self , filepath : AnyStr = '' , status : AnyStr = 'error' ) -> None :
110+ def _return_error (self , filepath : AnyStr = '' , status : AnyStr = 'error' ,
111+ ast : Optional [Dict [Any , Any ]] = None ) -> None :
103112 """
104113 Build and send to stdout and error response. Also log
105114 the errors to the python_driver.log.
@@ -109,11 +118,24 @@ def _return_error(self, filepath: AnyStr='', status: AnyStr='error') -> None:
109118 :param status: error type, 'error' or 'fatal'
110119 """
111120
121+ if status == 'fatal' :
122+ ret_ast = None
123+ elif ast :
124+ ret_ast = ast
125+ else :
126+ # Empty modules are still modules
127+ ret_ast = {"PY3AST" : {
128+ "ast_type" : "Module" ,
129+ "lineno" : 1 ,
130+ "col_offset" : 1 ,
131+ }}
132+
112133 logging .error ('Filepath: {}, Errors: {}' .format (filepath , self .errors ))
113134 response = Response ({
114135 'status' : status ,
115136 'errors' : self .errors ,
116137 'driver' : 'python23:%s' % __version__ ,
138+ 'ast' : ret_ast ,
117139 })
118140 if filepath :
119141 response ['filepath' ] = filepath
@@ -134,7 +156,7 @@ def process_request(self, request: RawRequest) -> None:
134156 self .errors = []
135157
136158 try :
137- code , filepath = self ._check_input_request (request )
159+ code , filepath = self ._parse_input_request (request )
138160
139161 # We want the code detection to be fast and we prefer Python3 AST so using
140162 # the stop_on_ok_ast will avoid running a Python2 subprocess to check the
@@ -168,6 +190,10 @@ def process_request(self, request: RawRequest) -> None:
168190
169191 self ._send_response (response )
170192
193+ except EmptyCodeException :
194+ self .errors .append ('Code field empty' )
195+ self ._return_error (filepath , status = 'error' , ast = ast )
196+
171197 except :
172198 status = 'fatal' if ast is None else 'error'
173199 self .errors .append (format_exc ())
0 commit comments