def DebugInfo(): LOGGER.info('Received debug info request') request_data = RequestWrap(request.json) has_clang_support = ycm_core.HasClangSupport() clang_version = ycm_core.ClangVersion() if has_clang_support else None filepath = request_data['filepath'] try: extra_conf_path = extra_conf_store.ModuleFileForSourceFile(filepath) is_loaded = bool(extra_conf_path) except UnknownExtraConf as error: extra_conf_path = error.extra_conf_file is_loaded = False response = { 'python': { 'executable': sys.executable, 'version': platform.python_version() }, 'clang': { 'has_support': has_clang_support, 'version': clang_version }, 'extra_conf': { 'path': extra_conf_path, 'is_loaded': is_loaded }, 'completer': None } try: response['completer'] = _GetCompleterForRequestData( request_data).DebugInfo(request_data) except Exception: LOGGER.exception('Error retrieving completer debug info') return _JsonResponse(response)
def LanguageServerCompleter_ExtraConf_NoExtraConf_test( app ): filepath = PathToTestFile( 'extra_confs', 'foo' ) completer = MockCompleter() request_data = RequestWrap( BuildRequest( filepath = filepath, filetype = 'ycmtest', working_dir = PathToTestFile(), contents = '' ) ) assert_that( {}, equal_to( completer._settings.get( 'ls', {} ) ) ) completer.OnFileReadyToParse( request_data ) assert_that( {}, equal_to( completer._settings.get( 'ls', {} ) ) ) # Simulate receipt of response and initialization complete initialize_response = { 'result': { 'capabilities': {} } } completer._HandleInitializeInPollThread( initialize_response ) assert_that( {}, equal_to( completer._settings.get( 'ls', {} ) ) ) # We use the client working directory assert_that( PathToTestFile(), equal_to( completer._project_directory ) )
def GetSignatureHelp(): LOGGER.info('Received signature help request') request_data = RequestWrap(request.json) if not _server_state.FiletypeCompletionUsable(request_data['filetypes'], silent=True): return _JsonResponse(BuildSignatureHelpResponse(None)) errors = None signature_info = None try: filetype_completer = _server_state.GetFiletypeCompleter( request_data['filetypes']) signature_info = filetype_completer.ComputeSignatures(request_data) except Exception as exception: LOGGER.exception('Exception from semantic completer during sig help') errors = [BuildExceptionResponse(exception, traceback.format_exc())] # No fallback for signature help. The general completer is unlikely to be able # to offer anything of for that here. return _JsonResponse( BuildSignatureHelpResponse(signature_info, errors=errors))
def LanguageServerCompleter_GetCompletions_List_test(): completer = MockCompleter() request_data = RequestWrap(BuildRequest()) completion_response = {'result': [{'label': 'test'}]} resolve_responses = [ { 'result': { 'label': 'test' } }, ] with patch.object(completer, 'ServerIsReady', return_value=True): with patch.object(completer.GetConnection(), 'GetResponse', side_effect=[completion_response] + resolve_responses): assert_that( completer.ComputeCandidatesInner(request_data, 1), contains(has_items(has_entries({'insertion_text': 'test'})), False))
def LanguageServerCompleter_Initialise_Shutdown_test(): completer = MockCompleter() request_data = RequestWrap(BuildRequest()) with patch.object(completer.GetConnection(), 'ReadData', side_effect=lsc.LanguageServerConnectionStopped): assert_that(completer.ServerIsReady(), equal_to(False)) completer.SendInitialize( request_data, completer._GetSettingsFromExtraConf(request_data)) with patch.object(completer, '_HandleInitializeInPollThread') as handler: completer.GetConnection().run() handler.assert_not_called() assert_that(completer._initialize_event.is_set(), equal_to(False)) assert_that(completer.ServerIsReady(), equal_to(False)) with patch.object(completer, 'ServerIsHealthy', return_value=False): assert_that(completer.ServerIsReady(), equal_to(False))
def GetCompletions(): _logger.info('Received completion request') request_data = RequestWrap(request.json) (do_filetype_completion, forced_filetype_completion) = ( _server_state.ShouldUseFiletypeCompleter(request_data)) _logger.debug('Using filetype completion: %s', do_filetype_completion) errors = None completions = None if do_filetype_completion: try: completions = (_server_state.GetFiletypeCompleter( request_data['filetypes']).ComputeCandidates(request_data)) except Exception as exception: if forced_filetype_completion: # user explicitly asked for semantic completion, so just pass the error # back raise else: # store the error to be returned with results from the identifier # completer stack = traceback.format_exc() _logger.error( 'Exception from semantic completer (using general): ' + "".join(stack)) errors = [BuildExceptionResponse(exception, stack)] if not completions and not forced_filetype_completion: completions = (_server_state.GetGeneralCompleter().ComputeCandidates( request_data)) return _JsonResponse( BuildCompletionResponse(completions if completions else [], request_data['start_column'], errors=errors))
def GetCompletions(): LOGGER.info('Received completion request') request_data = RequestWrap(request.json) do_filetype_completion = _server_state.ShouldUseFiletypeCompleter( request_data) LOGGER.debug('Using filetype completion: %s', do_filetype_completion) errors = None completions = None if do_filetype_completion: try: completions = (_server_state.GetFiletypeCompleter( request_data['filetypes']).ComputeCandidates(request_data)) except Exception as exception: if request_data['force_semantic']: # user explicitly asked for semantic completion, so just pass the error # back raise # store the error to be returned with results from the identifier # completer LOGGER.exception( 'Exception from semantic completer (using general)') stack = traceback.format_exc() errors = [BuildExceptionResponse(exception, stack)] if not completions and not request_data['force_semantic']: completions = _server_state.GetGeneralCompleter().ComputeCandidates( request_data) return _JsonResponse(BuildCompletionResponse( completions if completions else [], request_data['start_column'], errors=errors), file_encoding=request_data['file_encoding'])
def LanguageServerCompleter_GetCompletions_UnsupportedKinds_test( app ): completer = MockCompleter() request_data = RequestWrap( BuildRequest() ) completion_response = { 'result': [ { 'label': 'test', 'kind': len( lsp.ITEM_KIND ) + 1 } ] } resolve_responses = [ { 'result': { 'label': 'test' } }, ] with patch.object( completer, '_is_completion_provider', True ): with patch.object( completer.GetConnection(), 'GetResponse', side_effect = [ completion_response ] + resolve_responses ): assert_that( completer.ComputeCandidatesInner( request_data, 1 ), contains_exactly( has_items( all_of( has_entry( 'insertion_text', 'test' ), is_not( has_key( 'kind' ) ) ) ), False ) )
def LineValue_MiddleLine_test(): eq_( 'zoo', RequestWrap( PrepareJson( line_num = 2, contents = 'goo\nzoo\nbar' ) )[ 'line_value' ] )
def GetCompletions_RejectInvalid_test(): if utils.OnWindows(): filepath = 'C:\\test.test' else: filepath = '/test.test' contents = 'line1.\nline2.\nline3.' request_data = RequestWrap( BuildRequest( filetype = 'ycmtest', filepath = filepath, contents = contents, line_num = 1, column_num = 7 ) ) text_edit = { 'newText': 'blah', 'range': { 'start': { 'line': 0, 'character': 6 }, 'end': { 'line': 0, 'character': 6 }, } } assert_that( lsc._GetCompletionItemStartCodepointOrReject( text_edit, request_data ), equal_to( 7 ) ) text_edit = { 'newText': 'blah', 'range': { 'start': { 'line': 0, 'character': 6 }, 'end': { 'line': 1, 'character': 6 }, } } assert_that( calling( lsc._GetCompletionItemStartCodepointOrReject ).with_args( text_edit, request_data ), raises( lsc.IncompatibleCompletionException ) ) text_edit = { 'newText': 'blah', 'range': { 'start': { 'line': 0, 'character': 20 }, 'end': { 'line': 0, 'character': 20 }, } } assert_that( lsc._GetCompletionItemStartCodepointOrReject( text_edit, request_data ), equal_to( 7 ) ) text_edit = { 'newText': 'blah', 'range': { 'start': { 'line': 0, 'character': 6 }, 'end': { 'line': 0, 'character': 5 }, } } assert_that( lsc._GetCompletionItemStartCodepointOrReject( text_edit, request_data ), equal_to( 7 ) )
def WorkspaceEditToFixIt_test(): if utils.OnWindows(): filepath = 'C:\\test.test' uri = 'file:///c:/test.test' else: filepath = '/test.test' uri = 'file:/test.test' contents = 'line1\nline2\nline3' request_data = RequestWrap( BuildRequest( filetype = 'ycmtest', filepath = filepath, contents = contents ) ) # Null response to textDocument/codeActions is valid assert_that( lsc.WorkspaceEditToFixIt( request_data, None ), equal_to( None ) ) # Empty WorkspaceEdit is not explicitly forbidden assert_that( lsc.WorkspaceEditToFixIt( request_data, {} ), equal_to( None ) ) # We don't support versioned documentChanges workspace_edit = { 'documentChanges': [ { 'textDocument': { 'version': 1, 'uri': uri }, 'edits': [ { 'newText': 'blah', 'range': { 'start': { 'line': 0, 'character': 5 }, 'end': { 'line': 0, 'character': 5 }, } } ] } ] } response = responses.BuildFixItResponse( [ lsc.WorkspaceEditToFixIt( request_data, workspace_edit, 'test' ) ] ) print( f'Response: { response }' ) assert_that( response, has_entries( { 'fixits': contains_exactly( has_entries( { 'text': 'test', 'chunks': contains_exactly( ChunkMatcher( 'blah', LocationMatcher( filepath, 1, 6 ), LocationMatcher( filepath, 1, 6 ) ) ) } ) ) } ) ) workspace_edit = { 'changes': { uri: [ { 'newText': 'blah', 'range': { 'start': { 'line': 0, 'character': 5 }, 'end': { 'line': 0, 'character': 5 }, } }, ] } } response = responses.BuildFixItResponse( [ lsc.WorkspaceEditToFixIt( request_data, workspace_edit, 'test' ) ] ) print( f'Response: { response }' ) print( f'Type Response: { type( response ) }' ) assert_that( response, has_entries( { 'fixits': contains_exactly( has_entries( { 'text': 'test', 'chunks': contains_exactly( ChunkMatcher( 'blah', LocationMatcher( filepath, 1, 6 ), LocationMatcher( filepath, 1, 6 ) ) ) } ) ) } ) )
def Query_StopsAtParen_test(): eq_( 'bar', RequestWrap( PrepareJson( column_num = 8, contents = 'foo(bar' ) )[ 'query' ] )
def LanguageServerCompleter_GoTo_test( app ): if utils.OnWindows(): filepath = 'C:\\test.test' uri = 'file:///c:/test.test' else: filepath = '/test.test' uri = 'file:/test.test' contents = 'line1\nline2\nline3' completer = MockCompleter() # LSP server supports all code navigation features. completer._server_capabilities = { 'definitionProvider': True, 'declarationProvider': True, 'typeDefinitionProvider': True, 'implementationProvider': True, 'referencesProvider': True } request_data = RequestWrap( BuildRequest( filetype = 'ycmtest', filepath = filepath, contents = contents, line_num = 2, column_num = 3 ) ) @patch.object( completer, '_ServerIsInitialized', return_value = True ) def Test( responses, command, exception, throws, *args ): with patch.object( completer.GetConnection(), 'GetResponse', side_effect = responses ): if throws: assert_that( calling( completer.OnUserCommand ).with_args( [ command ], request_data ), raises( exception ) ) else: result = completer.OnUserCommand( [ command ], request_data ) print( f'Result: { result }' ) assert_that( result, exception ) location = { 'uri': uri, 'range': { 'start': { 'line': 0, 'character': 0 }, 'end': { 'line': 0, 'character': 0 }, } } goto_response = has_entries( { 'filepath': filepath, 'column_num': 1, 'line_num': 1, 'description': 'line1' } ) cases = [ ( [ { 'result': None } ], 'GoToDefinition', RuntimeError, True ), ( [ { 'result': location } ], 'GoToDeclaration', goto_response, False ), ( [ { 'result': {} } ], 'GoToType', RuntimeError, True ), ( [ { 'result': [] } ], 'GoToImplementation', RuntimeError, True ), ( [ { 'result': [ location ] } ], 'GoToReferences', goto_response, False ), ( [ { 'result': [ location, location ] } ], 'GoToReferences', contains_exactly( goto_response, goto_response ), False ), ] for response, goto_handlers, exception, throws in cases: Test( response, goto_handlers, exception, throws ) # All requests return an invalid URI. with patch( 'ycmd.completers.language_server.language_server_protocol.UriToFilePath', side_effect = lsp.InvalidUriException ): Test( [ { 'result': { 'uri': uri, 'range': { 'start': { 'line': 0, 'character': 0 }, 'end': { 'line': 0, 'character': 0 } } } } ], 'GoTo', LocationMatcher( '', 1, 1 ), False ) with patch( 'ycmd.completers.completer_utils.GetFileContents', side_effect = IOError ): Test( [ { 'result': { 'uri': uri, 'range': { 'start': { 'line': 0, 'character': 0 }, 'end': { 'line': 0, 'character': 0 } } } } ], 'GoToDefinition', LocationMatcher( filepath, 1, 1 ), False ) # Both requests return the location where the cursor is. Test( [ { 'result': { 'uri': uri, 'range': { 'start': { 'line': 1, 'character': 0 }, 'end': { 'line': 1, 'character': 4 } } } }, { 'result': { 'uri': uri, 'range': { 'start': { 'line': 1, 'character': 0 }, 'end': { 'line': 1, 'character': 4 }, } } } ], 'GoTo', LocationMatcher( filepath, 2, 1 ), False ) # First request returns two locations. Test( [ { 'result': [ { 'uri': uri, 'range': { 'start': { 'line': 0, 'character': 0 }, 'end': { 'line': 0, 'character': 4 } } }, { 'uri': uri, 'range': { 'start': { 'line': 1, 'character': 0 }, 'end': { 'line': 1, 'character': 4 }, } } ], } ], 'GoTo', contains_exactly( LocationMatcher( filepath, 1, 1 ), LocationMatcher( filepath, 2, 1 ) ), False ) # First request returns the location where the cursor is and second request # returns a different URI. if utils.OnWindows(): other_filepath = 'C:\\another.test' other_uri = 'file:///c:/another.test' else: other_filepath = '/another.test' other_uri = 'file:/another.test' Test( [ { 'result': { 'uri': uri, 'range': { 'start': { 'line': 1, 'character': 0 }, 'end': { 'line': 1, 'character': 4 } } } }, { 'result': { 'uri': other_uri, 'range': { 'start': { 'line': 1, 'character': 0 }, 'end': { 'line': 1, 'character': 4 }, } } } ], 'GoTo', LocationMatcher( other_filepath, 2, 1 ), False ) # First request returns a location before the cursor. Test( [ { 'result': { 'uri': uri, 'range': { 'start': { 'line': 0, 'character': 1 }, 'end': { 'line': 1, 'character': 1 } } } } ], 'GoTo', LocationMatcher( filepath, 1, 2 ), False ) # First request returns a location after the cursor. Test( [ { 'result': { 'uri': uri, 'range': { 'start': { 'line': 1, 'character': 3 }, 'end': { 'line': 2, 'character': 3 } } } } ], 'GoTo', LocationMatcher( filepath, 2, 4 ), False )
def LanguageServerCompleter_Diagnostics_Code_test( app ): completer = MockCompleter() filepath = os.path.realpath( '/foo.cpp' ) uri = lsp.FilePathToUri( filepath ) request_data = RequestWrap( BuildRequest( line_num = 1, column_num = 1, filepath = filepath, contents = '' ) ) notification = { 'jsonrpc': '2.0', 'method': 'textDocument/publishDiagnostics', 'params': { 'uri': uri, 'diagnostics': [ { 'range': { 'start': { 'line': 3, 'character': 10 }, 'end': { 'line': 3, 'character': 11 } }, 'severity': 1, 'message': 'First error', 'code': 'random_error' }, { 'range': { 'start': { 'line': 3, 'character': 10 }, 'end': { 'line': 3, 'character': 11 } }, 'severity': 1, 'message': 'Second error', 'code': 8 }, { 'range': { 'start': { 'line': 3, 'character': 10 }, 'end': { 'line': 3, 'character': 11 } }, 'severity': 1, 'message': 'Third error', 'code': '8' } ] } } completer.GetConnection()._notifications.put( notification ) completer.HandleNotificationInPollThread( notification ) with patch.object( completer, 'ServerIsReady', return_value = True ): completer.OnFileReadyToParse( request_data ) # Simulate receipt of response and initialization complete initialize_response = { 'result': { 'capabilities': {} } } completer._HandleInitializeInPollThread( initialize_response ) diagnostics = contains_exactly( has_entries( { 'kind': equal_to( 'ERROR' ), 'location': LocationMatcher( filepath, 4, 11 ), 'location_extent': RangeMatcher( filepath, ( 4, 11 ), ( 4, 12 ) ), 'ranges': contains_exactly( RangeMatcher( filepath, ( 4, 11 ), ( 4, 12 ) ) ), 'text': equal_to( 'First error [random_error]' ), 'fixit_available': False } ), has_entries( { 'kind': equal_to( 'ERROR' ), 'location': LocationMatcher( filepath, 4, 11 ), 'location_extent': RangeMatcher( filepath, ( 4, 11 ), ( 4, 12 ) ), 'ranges': contains_exactly( RangeMatcher( filepath, ( 4, 11 ), ( 4, 12 ) ) ), 'text': equal_to( 'Second error [8]' ), 'fixit_available': False } ), has_entries( { 'kind': equal_to( 'ERROR' ), 'location': LocationMatcher( filepath, 4, 11 ), 'location_extent': RangeMatcher( filepath, ( 4, 11 ), ( 4, 12 ) ), 'ranges': contains_exactly( RangeMatcher( filepath, ( 4, 11 ), ( 4, 12 ) ) ), 'text': equal_to( 'Third error [8]' ), 'fixit_available': False } ) ) assert_that( completer.OnFileReadyToParse( request_data ), diagnostics ) assert_that( completer.PollForMessages( request_data ), contains_exactly( has_entries( { 'diagnostics': diagnostics, 'filepath': filepath } ) ) )
def LanguageServerCompleter_PollForMessages_ServerNotStarted_test( app ): server = MockCompleter() request_data = RequestWrap( BuildRequest() ) assert_that( server.PollForMessages( request_data ), equal_to( True ) )
def Query_UnicodeSinglecharExclusive_test(): eq_( '', RequestWrap( PrepareJson( column_num = 5, contents = 'abc.ø' ) )[ 'query' ] )
def Query_InWhiteSpace_test(): eq_( '', RequestWrap( PrepareJson( column_num = 8, contents = 'foo ' ) )[ 'query' ] )
def DefinedSubcommands(): _logger.info( 'Received defined subcommands request' ) completer = _GetCompleterForRequestData( RequestWrap( request.json ) ) return _JsonResponse( completer.DefinedSubcommands() )
def LoadExtraConfFile(): _logger.info( 'Received extra conf load request' ) request_data = RequestWrap( request.json, validate = False ) extra_conf_store.Load( request_data[ 'filepath' ], force = True )
def LanguageServerCompleter_GetCompletions_CompleteOnCurrentColumn_test( app ): completer = MockCompleter() completer._resolve_completion_items = False a_response = { 'result': { 'items': [ { 'label': 'aba' }, { 'label': 'aab' }, { 'label': 'aaa' } ], 'isIncomplete': True } } aa_response = { 'result': { 'items': [ { 'label': 'aab' }, { 'label': 'aaa' } ], 'isIncomplete': False } } aaa_response = { 'result': { 'items': [ { 'label': 'aaa' } ], 'isIncomplete': False } } ab_response = { 'result': { 'items': [ { 'label': 'abb' }, { 'label': 'aba' } ], 'isIncomplete': False } } with patch.object( completer, '_is_completion_provider', True ): # User starts by typing the character "a". request_data = RequestWrap( BuildRequest( column_num = 2, contents = 'a', force_semantic = True ) ) with patch.object( completer.GetConnection(), 'GetResponse', return_value = a_response ) as response: assert_that( completer.ComputeCandidates( request_data ), contains_exactly( has_entry( 'insertion_text', 'aaa' ), has_entry( 'insertion_text', 'aab' ), has_entry( 'insertion_text', 'aba' ) ) ) # Nothing cached yet. assert_that( response.call_count, equal_to( 1 ) ) # User types again the character "a". request_data = RequestWrap( BuildRequest( column_num = 3, contents = 'aa', force_semantic = True ) ) with patch.object( completer.GetConnection(), 'GetResponse', return_value = aa_response ) as response: assert_that( completer.ComputeCandidates( request_data ), contains_exactly( has_entry( 'insertion_text', 'aaa' ), has_entry( 'insertion_text', 'aab' ) ) ) # The server returned an incomplete list of completions the first time so # a new completion request should have been sent. assert_that( response.call_count, equal_to( 1 ) ) # User types the character "a" a third time. request_data = RequestWrap( BuildRequest( column_num = 4, contents = 'aaa', force_semantic = True ) ) with patch.object( completer.GetConnection(), 'GetResponse', return_value = aaa_response ) as response: assert_that( completer.ComputeCandidates( request_data ), contains_exactly( has_entry( 'insertion_text', 'aaa' ) ) ) # The server returned a complete list of completions the second time and # the new query is a prefix of the cached one ("aa" is a prefix of "aaa") # so the cache should be used. assert_that( response.call_count, equal_to( 0 ) ) # User deletes the third character. request_data = RequestWrap( BuildRequest( column_num = 3, contents = 'aa', force_semantic = True ) ) with patch.object( completer.GetConnection(), 'GetResponse', return_value = aa_response ) as response: assert_that( completer.ComputeCandidates( request_data ), contains_exactly( has_entry( 'insertion_text', 'aaa' ), has_entry( 'insertion_text', 'aab' ) ) ) # The new query is still a prefix of the cached one ("aa" is a prefix of # "aa") so the cache should again be used. assert_that( response.call_count, equal_to( 0 ) ) # User deletes the second character. request_data = RequestWrap( BuildRequest( column_num = 2, contents = 'a', force_semantic = True ) ) with patch.object( completer.GetConnection(), 'GetResponse', return_value = a_response ) as response: assert_that( completer.ComputeCandidates( request_data ), contains_exactly( has_entry( 'insertion_text', 'aaa' ), has_entry( 'insertion_text', 'aab' ), has_entry( 'insertion_text', 'aba' ) ) ) # The new query is not anymore a prefix of the cached one ("aa" is not a # prefix of "a") so the cache is invalidated and a new request is sent. assert_that( response.call_count, equal_to( 1 ) ) # Finally, user inserts the "b" character. request_data = RequestWrap( BuildRequest( column_num = 3, contents = 'ab', force_semantic = True ) ) with patch.object( completer.GetConnection(), 'GetResponse', return_value = ab_response ) as response: assert_that( completer.ComputeCandidates( request_data ), contains_exactly( has_entry( 'insertion_text', 'aba' ), has_entry( 'insertion_text', 'abb' ) ) ) # Last response was incomplete so the cache should not be used. assert_that( response.call_count, equal_to( 1 ) )
def LineValue_LastLine_test(): eq_( 'zoo', RequestWrap( PrepareJson( line_num = 3, contents = 'goo\nbar\nzoo' ) )[ 'line_value' ] )
def LineValue_OneLine_test(): eq_( 'zoo', RequestWrap( PrepareJson( line_num = 1, contents = 'zoo' ) )[ 'line_value' ] )
def Test( line, col, prefix ): eq_( prefix, RequestWrap( PrepareJson( line_num = 1, contents = line, column_num = col ) )[ 'prefix' ] )
def Calculated_SetMethod_test(): assert_that( calling( RequestWrap( PrepareJson() ).__setitem__ ).with_args( 'line_value', '' ), raises( ValueError, 'Key "line_value" is read-only' ) )
def FiletypeCompletionAvailable(): _logger.info( 'Received filetype completion available request' ) return _JsonResponse( _server_state.FiletypeCompletionAvailable( RequestWrap( request.json )[ 'filetypes' ] ) )
def FiletypeCompletionAvailable(): LOGGER.info('Received filetype completion available request') return _JsonResponse( SERVER_STATE.FiletypeCompletionAvailable( RequestWrap(request.json)['filetypes']))
def GetDetailedDiagnostic(): _logger.info( 'Received detailed diagnostic request' ) request_data = RequestWrap( request.json ) completer = _GetCompleterForRequestData( request_data ) return _JsonResponse( completer.GetDetailedDiagnostic( request_data ) )
def RequestWrapForColumnAndContents(column_num, contents): return RequestWrap(BuildRequest(column_num=column_num, contents=contents))
def IgnoreExtraConfFile(): _logger.info( 'Received extra conf ignore request' ) request_data = RequestWrap( request.json, validate = False ) extra_conf_store.Disable( request_data[ 'filepath' ] )
def BuildRequestWrap( contents, column_num, line_num = 1 ): return RequestWrap( BuildRequest( column_num = column_num, line_num = line_num, contents = contents ) )