diff --git a/src/ptvsd/_vendored/pydevd/_pydev_bundle/pydev_log.py b/src/ptvsd/_vendored/pydevd/_pydev_bundle/pydev_log.py index 844e06cfc..abfb1b141 100644 --- a/src/ptvsd/_vendored/pydevd/_pydev_bundle/pydev_log.py +++ b/src/ptvsd/_vendored/pydevd/_pydev_bundle/pydev_log.py @@ -93,7 +93,14 @@ def exception(msg='', *args): def error_once(msg, *args): - message = msg % args + try: + if args: + message = msg % args + else: + message = str(msg) + except: + message = '%s - %s' % (msg, args) + if message not in WARN_ONCE_MAP: WARN_ONCE_MAP[message] = True critical(message) diff --git a/src/ptvsd/_vendored/pydevd/_pydevd_bundle/_debug_adapter/__main__pydevd_gen_debug_adapter_protocol.py b/src/ptvsd/_vendored/pydevd/_pydevd_bundle/_debug_adapter/__main__pydevd_gen_debug_adapter_protocol.py index 9139bc290..042478e6d 100644 --- a/src/ptvsd/_vendored/pydevd/_pydevd_bundle/_debug_adapter/__main__pydevd_gen_debug_adapter_protocol.py +++ b/src/ptvsd/_vendored/pydevd/_pydevd_bundle/_debug_adapter/__main__pydevd_gen_debug_adapter_protocol.py @@ -132,6 +132,9 @@ def create_classes_to_generate_structure(json_schema_data): properties.update(definition.get('properties', {})) required.update(_OrderedSet(definition.get('required', _OrderedSet()))) + if isinstance(description, (list, tuple)): + description = '\n'.join(description) + class_to_generatees[name] = dict( name=name, properties=properties, @@ -279,6 +282,10 @@ def update_class_to_generate_to_json(class_to_generate): namespace = dict(prop_name=prop_name, noqa=_get_noqa_for_var(prop_name)) to_dict_body.append(' %(prop_name)s = self.%(prop_name)s%(noqa)s' % namespace) + if prop.get('type') == 'array': + to_dict_body.append(' if %(prop_name)s and hasattr(%(prop_name)s[0], "to_dict"):' % namespace) + to_dict_body.append(' %(prop_name)s = [x.to_dict() for x in %(prop_name)s]' % namespace) + if translate_prop_names: to_dict_body.append(' if update_ids_to_dap:') for prop_name in translate_prop_names: @@ -412,6 +419,9 @@ def update_class_to_generate_init(class_to_generate): prop_type = prop['type'] prop_description = prop.get('description', '') + if isinstance(prop_description, (list, tuple)): + prop_description = '\n '.join(prop_description) + docstring.append(':param %(prop_type)s %(prop_name)s: %(prop_description)s' % dict( prop_type=prop_type, prop_name=prop_name, prop_description=prop_description)) diff --git a/src/ptvsd/_vendored/pydevd/_pydevd_bundle/_debug_adapter/debugProtocolCustom.json b/src/ptvsd/_vendored/pydevd/_pydevd_bundle/_debug_adapter/debugProtocolCustom.json index fc3e35e4d..4b84d51f4 100644 --- a/src/ptvsd/_vendored/pydevd/_pydevd_bundle/_debug_adapter/debugProtocolCustom.json +++ b/src/ptvsd/_vendored/pydevd/_pydevd_bundle/_debug_adapter/debugProtocolCustom.json @@ -23,42 +23,128 @@ "required": [ "command", "arguments" ] }] }, + "SetDebuggerPropertyArguments": { "type": "object", "description": "Arguments for 'setDebuggerProperty' request.", "properties": { "ideOS": { - "type": [ "string" ], + "type": "string", "description": "OS where the ide is running. Supported values [Windows, Linux]" }, "dontTraceStartPatterns": { - "type": [ "array" ], - "description": "Patterns to match with the start of the file paths. Matching paths will be added to a list of file where trace is ignored." + "type": "array", + "description": "Patterns to match with the start of the file paths. Matching paths will be added to a list of file where trace is ignored.", + "items": { + "type": "string" + } }, "dontTraceEndPatterns": { - "type": [ "array" ], - "description": "Patterns to match with the end of the file paths. Matching paths will be added to a list of file where trace is ignored." + "type": "array", + "description": "Patterns to match with the end of the file paths. Matching paths will be added to a list of file where trace is ignored.", + "items": { + "type": "string" + } }, "skipSuspendOnBreakpointException": { - "type": [ "array" ], - "description": "List of exceptions that should be skipped when doing condition evaluations." + "type": "array", + "description": "List of exceptions that should be skipped when doing condition evaluations.", + "items": { + "type": "string" + } }, "skipPrintBreakpointException": { - "type": [ "array" ], - "description": "List of exceptions that should skip printing to stderr when doing condition evaluations." + "type": "array", + "description": "List of exceptions that should skip printing to stderr when doing condition evaluations.", + "items": { + "type": "string" + } }, "multiThreadsSingleNotification": { - "type": [ "boolean" ], - "description": "If false then a notification is generated for each thread event. If true a single event is gnenerated, and all threads follow that behavior." + "type": "boolean", + "description": "If false then a notification is generated for each thread event. If true a single event is generated, and all threads follow that behavior." } } }, + "SetDebuggerPropertyResponse": { "allOf": [ { "$ref": "#/definitions/Response" }, { "type": "object", "description": "Response to 'setDebuggerProperty' request. This is just an acknowledgement, so no body field is required." }] - } + }, + - } + + "SetPydevdSourceMapRequest": { + "allOf": [ { "$ref": "#/definitions/Request" }, { + "type": "object", + "description": [ + "Sets multiple PydevdSourceMap for a single source and clears all previous PydevdSourceMap in that source.", + "i.e.: Maps paths and lines in a 1:N mapping (use case: map a single file in the IDE to multiple IPython cells).", + "To clear all PydevdSourceMap for a source, specify an empty array.", + "Interaction with breakpoints: When a new mapping is sent, breakpoints that match the source (or previously matched a source) are reapplied.", + "Interaction with launch pathMapping: both mappings are independent. This mapping is applied after the launch pathMapping." + ], + "properties": { + "command": { + "type": "string", + "enum": [ "setPydevdSourceMap" ] + }, + "arguments": { + "$ref": "#/definitions/SetPydevdSourceMapArguments" + } + }, + "required": [ "command", "arguments" ] + }] + }, + "SetPydevdSourceMapArguments": { + "type": "object", + "description": "Arguments for 'setPydevdSourceMap' request.", + "properties": { + "source": { + "$ref": "#/definitions/Source", + "description": "The source location of the PydevdSourceMap; 'source.path' must be specified (e.g.: for an ipython notebook this could be something as /home/notebook/note.py)." + }, + "pydevdSourceMaps": { + "type": "array", + "items": { + "$ref": "#/definitions/PydevdSourceMap" + }, + "description": "The PydevdSourceMaps to be set to the given source (provide an empty array to clear the source mappings for a given path)." + } + }, + "required": [ "source", "pydevdSourceMap" ] + }, + "SetPydevdSourceMapResponse": { + "allOf": [ { "$ref": "#/definitions/Response" }, { + "type": "object", + "description": "Response to 'setPydevdSourceMap' request. This is just an acknowledgement, so no body field is required." + }] + }, + + "PydevdSourceMap": { + "type": "object", + "description": "Information that allows mapping a local line to a remote source/line.", + "properties": { + "line": { + "type": "integer", + "description": "The local line to which the mapping should map to (e.g.: for an ipython notebook this would be the first line of the cell in the file)." + }, + "endLine": { + "type": "integer", + "description": "The end line." + }, + "runtimeSource": { + "$ref": "#/definitions/Source", + "description": "The path that the user has remotely -- 'source.path' must be specified (e.g.: for an ipython notebook this could be something as '')" + }, + "runtimeLine": { + "type": "integer", + "description": "The remote line to which the mapping should map to (e.g.: for an ipython notebook this would be always 1 as it'd map the start of the cell)." + } + }, + "required": ["line", "endLine", "runtimeSource", "runtimeLine"] + } + } } \ No newline at end of file diff --git a/src/ptvsd/_vendored/pydevd/_pydevd_bundle/_debug_adapter/pydevd_schema.py b/src/ptvsd/_vendored/pydevd/_pydevd_bundle/_debug_adapter/pydevd_schema.py index cc8089f8c..c4d0f5574 100644 --- a/src/ptvsd/_vendored/pydevd/_pydevd_bundle/_debug_adapter/pydevd_schema.py +++ b/src/ptvsd/_vendored/pydevd/_pydevd_bundle/_debug_adapter/pydevd_schema.py @@ -1595,6 +1595,8 @@ def __init__(self, cwd, args, kind=None, title=None, env=None, update_ids_from_d def to_dict(self, update_ids_to_dap=False): # noqa (update_ids_to_dap may be unused) cwd = self.cwd args = self.args + if args and hasattr(args[0], "to_dict"): + args = [x.to_dict() for x in args] kind = self.kind title = self.title env = self.env @@ -3360,7 +3362,11 @@ def __init__(self, source, breakpoints=None, lines=None, sourceModified=None, up def to_dict(self, update_ids_to_dap=False): # noqa (update_ids_to_dap may be unused) source = self.source breakpoints = self.breakpoints + if breakpoints and hasattr(breakpoints[0], "to_dict"): + breakpoints = [x.to_dict() for x in breakpoints] lines = self.lines + if lines and hasattr(lines[0], "to_dict"): + lines = [x.to_dict() for x in lines] sourceModified = self.sourceModified dct = { 'source': source.to_dict(update_ids_to_dap=update_ids_to_dap), @@ -3589,6 +3595,8 @@ def __init__(self, breakpoints, update_ids_from_dap=False, **kwargs): # noqa (u def to_dict(self, update_ids_to_dap=False): # noqa (update_ids_to_dap may be unused) breakpoints = self.breakpoints + if breakpoints and hasattr(breakpoints[0], "to_dict"): + breakpoints = [x.to_dict() for x in breakpoints] dct = { 'breakpoints': [FunctionBreakpoint.update_dict_ids_to_dap(o) for o in breakpoints] if (update_ids_to_dap and breakpoints) else breakpoints, } @@ -3809,7 +3817,11 @@ def __init__(self, filters, exceptionOptions=None, update_ids_from_dap=False, ** def to_dict(self, update_ids_to_dap=False): # noqa (update_ids_to_dap may be unused) filters = self.filters + if filters and hasattr(filters[0], "to_dict"): + filters = [x.to_dict() for x in filters] exceptionOptions = self.exceptionOptions + if exceptionOptions and hasattr(exceptionOptions[0], "to_dict"): + exceptionOptions = [x.to_dict() for x in exceptionOptions] dct = { 'filters': filters, } @@ -4264,6 +4276,8 @@ def __init__(self, breakpoints, update_ids_from_dap=False, **kwargs): # noqa (u def to_dict(self, update_ids_to_dap=False): # noqa (update_ids_to_dap may be unused) breakpoints = self.breakpoints + if breakpoints and hasattr(breakpoints[0], "to_dict"): + breakpoints = [x.to_dict() for x in breakpoints] dct = { 'breakpoints': [DataBreakpoint.update_dict_ids_to_dap(o) for o in breakpoints] if (update_ids_to_dap and breakpoints) else breakpoints, } @@ -7834,6 +7848,8 @@ def __init__(self, threadIds=None, update_ids_from_dap=False, **kwargs): # noqa def to_dict(self, update_ids_to_dap=False): # noqa (update_ids_to_dap may be unused) threadIds = self.threadIds + if threadIds and hasattr(threadIds[0], "to_dict"): + threadIds = [x.to_dict() for x in threadIds] dct = { } if threadIds is not None: @@ -10034,6 +10050,8 @@ def to_dict(self, update_ids_to_dap=False): # noqa (update_ids_to_dap may be un supportsHitConditionalBreakpoints = self.supportsHitConditionalBreakpoints supportsEvaluateForHovers = self.supportsEvaluateForHovers exceptionBreakpointFilters = self.exceptionBreakpointFilters + if exceptionBreakpointFilters and hasattr(exceptionBreakpointFilters[0], "to_dict"): + exceptionBreakpointFilters = [x.to_dict() for x in exceptionBreakpointFilters] supportsStepBack = self.supportsStepBack supportsSetVariable = self.supportsSetVariable supportsRestartFrame = self.supportsRestartFrame @@ -10042,7 +10060,11 @@ def to_dict(self, update_ids_to_dap=False): # noqa (update_ids_to_dap may be un supportsCompletionsRequest = self.supportsCompletionsRequest supportsModulesRequest = self.supportsModulesRequest additionalModuleColumns = self.additionalModuleColumns + if additionalModuleColumns and hasattr(additionalModuleColumns[0], "to_dict"): + additionalModuleColumns = [x.to_dict() for x in additionalModuleColumns] supportedChecksumAlgorithms = self.supportedChecksumAlgorithms + if supportedChecksumAlgorithms and hasattr(supportedChecksumAlgorithms[0], "to_dict"): + supportedChecksumAlgorithms = [x.to_dict() for x in supportedChecksumAlgorithms] supportsRestartRequest = self.supportsRestartRequest supportsExceptionOptions = self.supportsExceptionOptions supportsValueFormattingOptions = self.supportsValueFormattingOptions @@ -10516,6 +10538,8 @@ def __init__(self, columns, update_ids_from_dap=False, **kwargs): # noqa (updat def to_dict(self, update_ids_to_dap=False): # noqa (update_ids_to_dap may be unused) columns = self.columns + if columns and hasattr(columns[0], "to_dict"): + columns = [x.to_dict() for x in columns] dct = { 'columns': [ColumnDescriptor.update_dict_ids_to_dap(o) for o in columns] if (update_ids_to_dap and columns) else columns, } @@ -10684,8 +10708,12 @@ def to_dict(self, update_ids_to_dap=False): # noqa (update_ids_to_dap may be un presentationHint = self.presentationHint origin = self.origin sources = self.sources + if sources and hasattr(sources[0], "to_dict"): + sources = [x.to_dict() for x in sources] adapterData = self.adapterData checksums = self.checksums + if checksums and hasattr(checksums[0], "to_dict"): + checksums = [x.to_dict() for x in checksums] dct = { } if name is not None: @@ -11206,6 +11234,8 @@ def __init__(self, kind=None, attributes=None, visibility=None, update_ids_from_ def to_dict(self, update_ids_to_dap=False): # noqa (update_ids_to_dap may be unused) kind = self.kind attributes = self.attributes + if attributes and hasattr(attributes[0], "to_dict"): + attributes = [x.to_dict() for x in attributes] visibility = self.visibility dct = { } @@ -12046,6 +12076,8 @@ def __init__(self, breakMode, path=None, update_ids_from_dap=False, **kwargs): def to_dict(self, update_ids_to_dap=False): # noqa (update_ids_to_dap may be unused) breakMode = self.breakMode path = self.path + if path and hasattr(path[0], "to_dict"): + path = [x.to_dict() for x in path] dct = { 'breakMode': breakMode, } @@ -12137,6 +12169,8 @@ def __init__(self, names, negate=None, update_ids_from_dap=False, **kwargs): # def to_dict(self, update_ids_to_dap=False): # noqa (update_ids_to_dap may be unused) names = self.names + if names and hasattr(names[0], "to_dict"): + names = [x.to_dict() for x in names] negate = self.negate dct = { 'names': names, @@ -12216,6 +12250,8 @@ def to_dict(self, update_ids_to_dap=False): # noqa (update_ids_to_dap may be un evaluateName = self.evaluateName stackTrace = self.stackTrace innerException = self.innerException + if innerException and hasattr(innerException[0], "to_dict"): + innerException = [x.to_dict() for x in innerException] dct = { } if message is not None: @@ -12310,40 +12346,40 @@ class SetDebuggerPropertyArguments(BaseSchema): __props__ = { "ideOS": { - "type": [ - "string" - ], + "type": "string", "description": "OS where the ide is running. Supported values [Windows, Linux]" }, "dontTraceStartPatterns": { - "type": [ - "array" - ], - "description": "Patterns to match with the start of the file paths. Matching paths will be added to a list of file where trace is ignored." + "type": "array", + "description": "Patterns to match with the start of the file paths. Matching paths will be added to a list of file where trace is ignored.", + "items": { + "type": "string" + } }, "dontTraceEndPatterns": { - "type": [ - "array" - ], - "description": "Patterns to match with the end of the file paths. Matching paths will be added to a list of file where trace is ignored." + "type": "array", + "description": "Patterns to match with the end of the file paths. Matching paths will be added to a list of file where trace is ignored.", + "items": { + "type": "string" + } }, "skipSuspendOnBreakpointException": { - "type": [ - "array" - ], - "description": "List of exceptions that should be skipped when doing condition evaluations." + "type": "array", + "description": "List of exceptions that should be skipped when doing condition evaluations.", + "items": { + "type": "string" + } }, "skipPrintBreakpointException": { - "type": [ - "array" - ], - "description": "List of exceptions that should skip printing to stderr when doing condition evaluations." + "type": "array", + "description": "List of exceptions that should skip printing to stderr when doing condition evaluations.", + "items": { + "type": "string" + } }, "multiThreadsSingleNotification": { - "type": [ - "boolean" - ], - "description": "If false then a notification is generated for each thread event. If true a single event is gnenerated, and all threads follow that behavior." + "type": "boolean", + "description": "If false then a notification is generated for each thread event. If true a single event is generated, and all threads follow that behavior." } } __refs__ = set() @@ -12352,12 +12388,12 @@ class SetDebuggerPropertyArguments(BaseSchema): def __init__(self, ideOS=None, dontTraceStartPatterns=None, dontTraceEndPatterns=None, skipSuspendOnBreakpointException=None, skipPrintBreakpointException=None, multiThreadsSingleNotification=None, update_ids_from_dap=False, **kwargs): # noqa (update_ids_from_dap may be unused) """ - :param ['string'] ideOS: OS where the ide is running. Supported values [Windows, Linux] - :param ['array'] dontTraceStartPatterns: Patterns to match with the start of the file paths. Matching paths will be added to a list of file where trace is ignored. - :param ['array'] dontTraceEndPatterns: Patterns to match with the end of the file paths. Matching paths will be added to a list of file where trace is ignored. - :param ['array'] skipSuspendOnBreakpointException: List of exceptions that should be skipped when doing condition evaluations. - :param ['array'] skipPrintBreakpointException: List of exceptions that should skip printing to stderr when doing condition evaluations. - :param ['boolean'] multiThreadsSingleNotification: If false then a notification is generated for each thread event. If true a single event is gnenerated, and all threads follow that behavior. + :param string ideOS: OS where the ide is running. Supported values [Windows, Linux] + :param array dontTraceStartPatterns: Patterns to match with the start of the file paths. Matching paths will be added to a list of file where trace is ignored. + :param array dontTraceEndPatterns: Patterns to match with the end of the file paths. Matching paths will be added to a list of file where trace is ignored. + :param array skipSuspendOnBreakpointException: List of exceptions that should be skipped when doing condition evaluations. + :param array skipPrintBreakpointException: List of exceptions that should skip printing to stderr when doing condition evaluations. + :param boolean multiThreadsSingleNotification: If false then a notification is generated for each thread event. If true a single event is generated, and all threads follow that behavior. """ self.ideOS = ideOS self.dontTraceStartPatterns = dontTraceStartPatterns @@ -12371,9 +12407,17 @@ def __init__(self, ideOS=None, dontTraceStartPatterns=None, dontTraceEndPatterns def to_dict(self, update_ids_to_dap=False): # noqa (update_ids_to_dap may be unused) ideOS = self.ideOS dontTraceStartPatterns = self.dontTraceStartPatterns + if dontTraceStartPatterns and hasattr(dontTraceStartPatterns[0], "to_dict"): + dontTraceStartPatterns = [x.to_dict() for x in dontTraceStartPatterns] dontTraceEndPatterns = self.dontTraceEndPatterns + if dontTraceEndPatterns and hasattr(dontTraceEndPatterns[0], "to_dict"): + dontTraceEndPatterns = [x.to_dict() for x in dontTraceEndPatterns] skipSuspendOnBreakpointException = self.skipSuspendOnBreakpointException + if skipSuspendOnBreakpointException and hasattr(skipSuspendOnBreakpointException[0], "to_dict"): + skipSuspendOnBreakpointException = [x.to_dict() for x in skipSuspendOnBreakpointException] skipPrintBreakpointException = self.skipPrintBreakpointException + if skipPrintBreakpointException and hasattr(skipPrintBreakpointException[0], "to_dict"): + skipPrintBreakpointException = [x.to_dict() for x in skipPrintBreakpointException] multiThreadsSingleNotification = self.multiThreadsSingleNotification dct = { } @@ -12490,6 +12534,298 @@ def to_dict(self, update_ids_to_dap=False): # noqa (update_ids_to_dap may be un return dct +@register_request('setPydevdSourceMap') +@register +class SetPydevdSourceMapRequest(BaseSchema): + """ + Sets multiple PydevdSourceMap for a single source and clears all previous PydevdSourceMap in that + source. + + i.e.: Maps paths and lines in a 1:N mapping (use case: map a single file in the IDE to multiple + IPython cells). + + To clear all PydevdSourceMap for a source, specify an empty array. + + Interaction with breakpoints: When a new mapping is sent, breakpoints that match the source (or + previously matched a source) are reapplied. + + Interaction with launch pathMapping: both mappings are independent. This mapping is applied after + the launch pathMapping. + + Note: automatically generated code. Do not edit manually. + """ + + __props__ = { + "seq": { + "type": "integer", + "description": "Sequence number." + }, + "type": { + "type": "string", + "enum": [ + "request" + ] + }, + "command": { + "type": "string", + "enum": [ + "setPydevdSourceMap" + ] + }, + "arguments": { + "type": "SetPydevdSourceMapArguments" + } + } + __refs__ = set(['arguments']) + + __slots__ = list(__props__.keys()) + ['kwargs'] + + def __init__(self, arguments, seq=-1, update_ids_from_dap=False, **kwargs): # noqa (update_ids_from_dap may be unused) + """ + :param string type: + :param string command: + :param SetPydevdSourceMapArguments arguments: + :param integer seq: Sequence number. + """ + self.type = 'request' + self.command = 'setPydevdSourceMap' + if arguments is None: + self.arguments = SetPydevdSourceMapArguments() + else: + self.arguments = SetPydevdSourceMapArguments(update_ids_from_dap=update_ids_from_dap, **arguments) if arguments.__class__ != SetPydevdSourceMapArguments else arguments + self.seq = seq + self.kwargs = kwargs + + + def to_dict(self, update_ids_to_dap=False): # noqa (update_ids_to_dap may be unused) + type = self.type # noqa (assign to builtin) + command = self.command + arguments = self.arguments + seq = self.seq + dct = { + 'type': type, + 'command': command, + 'arguments': arguments.to_dict(update_ids_to_dap=update_ids_to_dap), + 'seq': seq, + } + dct.update(self.kwargs) + return dct + + +@register +class SetPydevdSourceMapArguments(BaseSchema): + """ + Arguments for 'setPydevdSourceMap' request. + + Note: automatically generated code. Do not edit manually. + """ + + __props__ = { + "source": { + "description": "The source location of the PydevdSourceMap; 'source.path' must be specified (e.g.: for an ipython notebook this could be something as /home/notebook/note.py).", + "type": "Source" + }, + "pydevdSourceMaps": { + "type": "array", + "items": { + "$ref": "#/definitions/PydevdSourceMap" + }, + "description": "The PydevdSourceMaps to be set to the given source (provide an empty array to clear the source mappings for a given path)." + } + } + __refs__ = set(['source']) + + __slots__ = list(__props__.keys()) + ['kwargs'] + + def __init__(self, source, pydevdSourceMaps=None, update_ids_from_dap=False, **kwargs): # noqa (update_ids_from_dap may be unused) + """ + :param Source source: The source location of the PydevdSourceMap; 'source.path' must be specified (e.g.: for an ipython notebook this could be something as /home/notebook/note.py). + :param array pydevdSourceMaps: The PydevdSourceMaps to be set to the given source (provide an empty array to clear the source mappings for a given path). + """ + if source is None: + self.source = Source() + else: + self.source = Source(update_ids_from_dap=update_ids_from_dap, **source) if source.__class__ != Source else source + self.pydevdSourceMaps = pydevdSourceMaps + if update_ids_from_dap and self.pydevdSourceMaps: + for o in self.pydevdSourceMaps: + PydevdSourceMap.update_dict_ids_from_dap(o) + self.kwargs = kwargs + + + def to_dict(self, update_ids_to_dap=False): # noqa (update_ids_to_dap may be unused) + source = self.source + pydevdSourceMaps = self.pydevdSourceMaps + if pydevdSourceMaps and hasattr(pydevdSourceMaps[0], "to_dict"): + pydevdSourceMaps = [x.to_dict() for x in pydevdSourceMaps] + dct = { + 'source': source.to_dict(update_ids_to_dap=update_ids_to_dap), + } + if pydevdSourceMaps is not None: + dct['pydevdSourceMaps'] = [PydevdSourceMap.update_dict_ids_to_dap(o) for o in pydevdSourceMaps] if (update_ids_to_dap and pydevdSourceMaps) else pydevdSourceMaps + dct.update(self.kwargs) + return dct + + +@register_response('setPydevdSourceMap') +@register +class SetPydevdSourceMapResponse(BaseSchema): + """ + Response to 'setPydevdSourceMap' request. This is just an acknowledgement, so no body field is + required. + + Note: automatically generated code. Do not edit manually. + """ + + __props__ = { + "seq": { + "type": "integer", + "description": "Sequence number." + }, + "type": { + "type": "string", + "enum": [ + "response" + ] + }, + "request_seq": { + "type": "integer", + "description": "Sequence number of the corresponding request." + }, + "success": { + "type": "boolean", + "description": "Outcome of the request." + }, + "command": { + "type": "string", + "description": "The command requested." + }, + "message": { + "type": "string", + "description": "Contains error message if success == false." + }, + "body": { + "type": [ + "array", + "boolean", + "integer", + "null", + "number", + "object", + "string" + ], + "description": "Contains request result if success is true and optional error details if success is false." + } + } + __refs__ = set() + + __slots__ = list(__props__.keys()) + ['kwargs'] + + def __init__(self, request_seq, success, command, seq=-1, message=None, body=None, update_ids_from_dap=False, **kwargs): # noqa (update_ids_from_dap may be unused) + """ + :param string type: + :param integer request_seq: Sequence number of the corresponding request. + :param boolean success: Outcome of the request. + :param string command: The command requested. + :param integer seq: Sequence number. + :param string message: Contains error message if success == false. + :param ['array', 'boolean', 'integer', 'null', 'number', 'object', 'string'] body: Contains request result if success is true and optional error details if success is false. + """ + self.type = 'response' + self.request_seq = request_seq + self.success = success + self.command = command + self.seq = seq + self.message = message + self.body = body + self.kwargs = kwargs + + + def to_dict(self, update_ids_to_dap=False): # noqa (update_ids_to_dap may be unused) + type = self.type # noqa (assign to builtin) + request_seq = self.request_seq + success = self.success + command = self.command + seq = self.seq + message = self.message + body = self.body + dct = { + 'type': type, + 'request_seq': request_seq, + 'success': success, + 'command': command, + 'seq': seq, + } + if message is not None: + dct['message'] = message + if body is not None: + dct['body'] = body + dct.update(self.kwargs) + return dct + + +@register +class PydevdSourceMap(BaseSchema): + """ + Information that allows mapping a local line to a remote source/line. + + Note: automatically generated code. Do not edit manually. + """ + + __props__ = { + "line": { + "type": "integer", + "description": "The local line to which the mapping should map to (e.g.: for an ipython notebook this would be the first line of the cell in the file)." + }, + "endLine": { + "type": "integer", + "description": "The end line." + }, + "runtimeSource": { + "description": "The path that the user has remotely -- 'source.path' must be specified (e.g.: for an ipython notebook this could be something as '')", + "type": "Source" + }, + "runtimeLine": { + "type": "integer", + "description": "The remote line to which the mapping should map to (e.g.: for an ipython notebook this would be always 1 as it'd map the start of the cell)." + } + } + __refs__ = set(['runtimeSource']) + + __slots__ = list(__props__.keys()) + ['kwargs'] + + def __init__(self, line, endLine, runtimeSource, runtimeLine, update_ids_from_dap=False, **kwargs): # noqa (update_ids_from_dap may be unused) + """ + :param integer line: The local line to which the mapping should map to (e.g.: for an ipython notebook this would be the first line of the cell in the file). + :param integer endLine: The end line. + :param Source runtimeSource: The path that the user has remotely -- 'source.path' must be specified (e.g.: for an ipython notebook this could be something as '') + :param integer runtimeLine: The remote line to which the mapping should map to (e.g.: for an ipython notebook this would be always 1 as it'd map the start of the cell). + """ + self.line = line + self.endLine = endLine + if runtimeSource is None: + self.runtimeSource = Source() + else: + self.runtimeSource = Source(update_ids_from_dap=update_ids_from_dap, **runtimeSource) if runtimeSource.__class__ != Source else runtimeSource + self.runtimeLine = runtimeLine + self.kwargs = kwargs + + + def to_dict(self, update_ids_to_dap=False): # noqa (update_ids_to_dap may be unused) + line = self.line + endLine = self.endLine + runtimeSource = self.runtimeSource + runtimeLine = self.runtimeLine + dct = { + 'line': line, + 'endLine': endLine, + 'runtimeSource': runtimeSource.to_dict(update_ids_to_dap=update_ids_to_dap), + 'runtimeLine': runtimeLine, + } + dct.update(self.kwargs) + return dct + + @register class ErrorResponseBody(BaseSchema): """ @@ -13337,6 +13673,8 @@ def __init__(self, breakpoints, update_ids_from_dap=False, **kwargs): # noqa (u def to_dict(self, update_ids_to_dap=False): # noqa (update_ids_to_dap may be unused) breakpoints = self.breakpoints + if breakpoints and hasattr(breakpoints[0], "to_dict"): + breakpoints = [x.to_dict() for x in breakpoints] dct = { 'breakpoints': [Breakpoint.update_dict_ids_to_dap(o) for o in breakpoints] if (update_ids_to_dap and breakpoints) else breakpoints, } @@ -13378,6 +13716,8 @@ def __init__(self, breakpoints, update_ids_from_dap=False, **kwargs): # noqa (u def to_dict(self, update_ids_to_dap=False): # noqa (update_ids_to_dap may be unused) breakpoints = self.breakpoints + if breakpoints and hasattr(breakpoints[0], "to_dict"): + breakpoints = [x.to_dict() for x in breakpoints] dct = { 'breakpoints': [Breakpoint.update_dict_ids_to_dap(o) for o in breakpoints] if (update_ids_to_dap and breakpoints) else breakpoints, } @@ -13442,6 +13782,8 @@ def to_dict(self, update_ids_to_dap=False): # noqa (update_ids_to_dap may be un dataId = self.dataId description = self.description accessTypes = self.accessTypes + if accessTypes and hasattr(accessTypes[0], "to_dict"): + accessTypes = [x.to_dict() for x in accessTypes] canPersist = self.canPersist dct = { 'dataId': dataId, @@ -13489,6 +13831,8 @@ def __init__(self, breakpoints, update_ids_from_dap=False, **kwargs): # noqa (u def to_dict(self, update_ids_to_dap=False): # noqa (update_ids_to_dap may be unused) breakpoints = self.breakpoints + if breakpoints and hasattr(breakpoints[0], "to_dict"): + breakpoints = [x.to_dict() for x in breakpoints] dct = { 'breakpoints': [Breakpoint.update_dict_ids_to_dap(o) for o in breakpoints] if (update_ids_to_dap and breakpoints) else breakpoints, } @@ -13573,6 +13917,8 @@ def __init__(self, stackFrames, totalFrames=None, update_ids_from_dap=False, **k def to_dict(self, update_ids_to_dap=False): # noqa (update_ids_to_dap may be unused) stackFrames = self.stackFrames + if stackFrames and hasattr(stackFrames[0], "to_dict"): + stackFrames = [x.to_dict() for x in stackFrames] totalFrames = self.totalFrames dct = { 'stackFrames': [StackFrame.update_dict_ids_to_dap(o) for o in stackFrames] if (update_ids_to_dap and stackFrames) else stackFrames, @@ -13617,6 +13963,8 @@ def __init__(self, scopes, update_ids_from_dap=False, **kwargs): # noqa (update def to_dict(self, update_ids_to_dap=False): # noqa (update_ids_to_dap may be unused) scopes = self.scopes + if scopes and hasattr(scopes[0], "to_dict"): + scopes = [x.to_dict() for x in scopes] dct = { 'scopes': [Scope.update_dict_ids_to_dap(o) for o in scopes] if (update_ids_to_dap and scopes) else scopes, } @@ -13658,6 +14006,8 @@ def __init__(self, variables, update_ids_from_dap=False, **kwargs): # noqa (upd def to_dict(self, update_ids_to_dap=False): # noqa (update_ids_to_dap may be unused) variables = self.variables + if variables and hasattr(variables[0], "to_dict"): + variables = [x.to_dict() for x in variables] dct = { 'variables': [Variable.update_dict_ids_to_dap(o) for o in variables] if (update_ids_to_dap and variables) else variables, } @@ -13833,6 +14183,8 @@ def __init__(self, threads, update_ids_from_dap=False, **kwargs): # noqa (updat def to_dict(self, update_ids_to_dap=False): # noqa (update_ids_to_dap may be unused) threads = self.threads + if threads and hasattr(threads[0], "to_dict"): + threads = [x.to_dict() for x in threads] dct = { 'threads': [Thread.update_dict_ids_to_dap(o) for o in threads] if (update_ids_to_dap and threads) else threads, } @@ -13880,6 +14232,8 @@ def __init__(self, modules, totalModules=None, update_ids_from_dap=False, **kwar def to_dict(self, update_ids_to_dap=False): # noqa (update_ids_to_dap may be unused) modules = self.modules + if modules and hasattr(modules[0], "to_dict"): + modules = [x.to_dict() for x in modules] totalModules = self.totalModules dct = { 'modules': [Module.update_dict_ids_to_dap(o) for o in modules] if (update_ids_to_dap and modules) else modules, @@ -13924,6 +14278,8 @@ def __init__(self, sources, update_ids_from_dap=False, **kwargs): # noqa (updat def to_dict(self, update_ids_to_dap=False): # noqa (update_ids_to_dap may be unused) sources = self.sources + if sources and hasattr(sources[0], "to_dict"): + sources = [x.to_dict() for x in sources] dct = { 'sources': [Source.update_dict_ids_to_dap(o) for o in sources] if (update_ids_to_dap and sources) else sources, } @@ -14168,6 +14524,8 @@ def __init__(self, targets, update_ids_from_dap=False, **kwargs): # noqa (updat def to_dict(self, update_ids_to_dap=False): # noqa (update_ids_to_dap may be unused) targets = self.targets + if targets and hasattr(targets[0], "to_dict"): + targets = [x.to_dict() for x in targets] dct = { 'targets': [StepInTarget.update_dict_ids_to_dap(o) for o in targets] if (update_ids_to_dap and targets) else targets, } @@ -14209,6 +14567,8 @@ def __init__(self, targets, update_ids_from_dap=False, **kwargs): # noqa (updat def to_dict(self, update_ids_to_dap=False): # noqa (update_ids_to_dap may be unused) targets = self.targets + if targets and hasattr(targets[0], "to_dict"): + targets = [x.to_dict() for x in targets] dct = { 'targets': [GotoTarget.update_dict_ids_to_dap(o) for o in targets] if (update_ids_to_dap and targets) else targets, } @@ -14250,6 +14610,8 @@ def __init__(self, targets, update_ids_from_dap=False, **kwargs): # noqa (updat def to_dict(self, update_ids_to_dap=False): # noqa (update_ids_to_dap may be unused) targets = self.targets + if targets and hasattr(targets[0], "to_dict"): + targets = [x.to_dict() for x in targets] dct = { 'targets': [CompletionItem.update_dict_ids_to_dap(o) for o in targets] if (update_ids_to_dap and targets) else targets, } diff --git a/src/ptvsd/_vendored/pydevd/_pydevd_bundle/pydevd_api.py b/src/ptvsd/_vendored/pydevd/_pydevd_bundle/pydevd_api.py index 54f3bac10..36b841bbd 100644 --- a/src/ptvsd/_vendored/pydevd/_pydevd_bundle/pydevd_api.py +++ b/src/ptvsd/_vendored/pydevd/_pydevd_bundle/pydevd_api.py @@ -1,7 +1,9 @@ import sys +import bisect +import types from _pydev_imps._pydev_saved_modules import threading -from _pydevd_bundle import pydevd_utils +from _pydevd_bundle import pydevd_utils, pydevd_source_mapping from _pydevd_bundle.pydevd_additional_thread_info import set_additional_thread_info from _pydevd_bundle.pydevd_comm import (InternalGetThreadStack, internal_get_completions, pydevd_find_thread_by_id, InternalStepThread, InternalSetNextStatementThread, internal_reload_code, @@ -12,7 +14,7 @@ from _pydevd_bundle.pydevd_comm_constants import (CMD_THREAD_SUSPEND, file_system_encoding, CMD_STEP_INTO_MY_CODE, CMD_STOP_ON_START) from _pydevd_bundle.pydevd_constants import (get_current_thread_id, set_protocol, get_protocol, - HTTP_JSON_PROTOCOL, JSON_PROTOCOL, STATE_RUN, IS_PY3K, DebugInfoHolder, dict_keys) + HTTP_JSON_PROTOCOL, JSON_PROTOCOL, STATE_RUN, IS_PY3K, DebugInfoHolder, dict_keys, dict_items) from _pydevd_bundle.pydevd_net_command_factory_json import NetCommandFactoryJson from _pydevd_bundle.pydevd_net_command_factory_xml import NetCommandFactory import pydevd_file_utils @@ -20,6 +22,39 @@ from _pydevd_bundle.pydevd_breakpoints import LineBreakpoint from pydevd_tracing import get_exception_traceback_str +try: + import dis +except ImportError: + + def _get_code_lines(code): + raise NotImplementedError + +else: + + def _get_code_lines(code): + if not isinstance(code, types.CodeType): + path = code + with open(path) as f: + src = f.read() + code = compile(src, path, 'exec', 0, dont_inherit=True) + return _get_code_lines(code) + + def iterate(): + # First, get all line starts for this code object. This does not include + # bodies of nested class and function definitions, as they have their + # own objects. + for _, lineno in dis.findlinestarts(code): + yield lineno + + # For nested class and function definitions, their respective code objects + # are constants referenced by this object. + for const in code.co_consts: + if isinstance(const, types.CodeType) and const.co_filename == code.co_filename: + for lineno in _get_code_lines(const): + yield lineno + + return iterate() + class PyDevdAPI(object): @@ -272,11 +307,26 @@ def __init__(self, filename): ADD_BREAKPOINT_FILE_NOT_FOUND = 1 ADD_BREAKPOINT_FILE_EXCLUDED_BY_FILTERS = 2 + class _AddBreakpointResult(object): + + # :see: ADD_BREAKPOINT_NO_ERROR = 0 + # :see: ADD_BREAKPOINT_FILE_NOT_FOUND = 1 + # :see: ADD_BREAKPOINT_FILE_EXCLUDED_BY_FILTERS = 2 + + __slots__ = ['error_code', 'translated_filename', 'translated_line'] + + def __init__(self, translated_filename, translated_line): + self.error_code = PyDevdAPI.ADD_BREAKPOINT_NO_ERROR + self.translated_filename = translated_filename + self.translated_line = translated_line + def add_breakpoint( - self, py_db, filename, breakpoint_type, breakpoint_id, line, condition, func_name, expression, suspend_policy, hit_condition, is_logpoint): + self, py_db, filename, breakpoint_type, breakpoint_id, line, condition, func_name, + expression, suspend_policy, hit_condition, is_logpoint, adjust_line=False): ''' :param str filename: - Note: must be already translated for the server. + Note: must be sent as it was received in the protocol. It may be translated in this + function and its final value will be available in the returned _AddBreakpointResult. :param str breakpoint_type: One of: 'python-line', 'django-line', 'jinja2-line'. @@ -284,6 +334,8 @@ def add_breakpoint( :param int breakpoint_id: :param int line: + Note: it's possible that a new line was actually used. If that's the case its + final value will be available in the returned _AddBreakpointResult. :param condition: Either None or the condition to activate the breakpoint. @@ -308,33 +360,68 @@ def add_breakpoint( If True and an expression is passed, pydevd will create an io message command with the result of the evaluation. - :return int: - :see: ADD_BREAKPOINT_NO_ERROR = 0 - :see: ADD_BREAKPOINT_FILE_NOT_FOUND = 1 - :see: ADD_BREAKPOINT_FILE_EXCLUDED_BY_FILTERS = 2 + :return _AddBreakpointResult: ''' + original_filename = filename + # Parameters to reapply breakpoint. + api_add_breakpoint_params = (filename, breakpoint_type, breakpoint_id, line, condition, func_name, + expression, suspend_policy, hit_condition, is_logpoint) + + filename = self.filename_to_server(filename) # Apply user path mapping. + func_name = self.to_str(func_name) + assert filename.__class__ == str # i.e.: bytes on py2 and str on py3 assert func_name.__class__ == str # i.e.: bytes on py2 and str on py3 - if not pydevd_file_utils.exists(filename): - return self.ADD_BREAKPOINT_FILE_NOT_FOUND - - error_code = self.ADD_BREAKPOINT_NO_ERROR - if ( - py_db.is_files_filter_enabled and - not py_db.get_require_module_for_filters() and - py_db.apply_files_filter(self._DummyFrame(filename), filename, False) - ): - # Note that if `get_require_module_for_filters()` returns False, we don't do this check. - # This is because we don't have the module name given a file at this point (in - # runtime it's gotten from the frame.f_globals). - # An option could be calculate it based on the filename and current sys.path, - # but on some occasions that may be wrong (for instance with `__main__` or if - # the user dynamically changes the PYTHONPATH). - - # Note: depending on the use-case, filters may be changed, so, keep on going and add the - # breakpoint even with the error code. - error_code = self.ADD_BREAKPOINT_FILE_EXCLUDED_BY_FILTERS + # Apply source mapping (i.e.: ipython). + new_filename, new_line, multi_mapping_applied = py_db.source_mapping.map_to_server(filename, line) + + py_db.api_received_breakpoints[(original_filename, breakpoint_id)] = (new_filename, api_add_breakpoint_params) + + if multi_mapping_applied: + # Note that source mapping is internal and does not change the resulting filename nor line. + result = self._AddBreakpointResult(filename, line) + filename = new_filename + line = new_line + + else: + if adjust_line and not filename.startswith('<'): + # Validate breakpoints and adjust their positions. + try: + lines = sorted(_get_code_lines(filename)) + except Exception: + pass + else: + if line not in lines: + # Adjust to the first preceding valid line. + idx = bisect.bisect_left(lines, line) + if idx > 0: + line = lines[idx - 1] + + result = self._AddBreakpointResult(filename, line) + + if not filename.startswith('<'): + # Note: if a mapping pointed to a file starting with '<', don't validate. + + if not pydevd_file_utils.exists(filename): + result.error_code = self.ADD_BREAKPOINT_FILE_NOT_FOUND + return result + + if ( + py_db.is_files_filter_enabled and + not py_db.get_require_module_for_filters() and + py_db.apply_files_filter(self._DummyFrame(filename), filename, False) + ): + # Note that if `get_require_module_for_filters()` returns False, we don't do this check. + # This is because we don't have the module name given a file at this point (in + # runtime it's gotten from the frame.f_globals). + # An option could be calculate it based on the filename and current sys.path, + # but on some occasions that may be wrong (for instance with `__main__` or if + # the user dynamically changes the PYTHONPATH). + + # Note: depending on the use-case, filters may be changed, so, keep on going and add the + # breakpoint even with the error code. + result.error_code = self.ADD_BREAKPOINT_FILE_EXCLUDED_BY_FILTERS if breakpoint_type == 'python-line': added_breakpoint = LineBreakpoint(line, condition, func_name, expression, suspend_policy, hit_condition=hit_condition, is_logpoint=is_logpoint) @@ -343,13 +430,13 @@ def add_breakpoint( supported_type = True else: - result = None + add_plugin_breakpoint_result = None plugin = py_db.get_plugin_lazy_init() if plugin is not None: - result = plugin.add_breakpoint('add_line_breakpoint', py_db, breakpoint_type, filename, line, condition, expression, func_name, hit_condition=hit_condition, is_logpoint=is_logpoint) - if result is not None: + add_plugin_breakpoint_result = plugin.add_breakpoint('add_line_breakpoint', py_db, breakpoint_type, filename, line, condition, expression, func_name, hit_condition=hit_condition, is_logpoint=is_logpoint) + if add_plugin_breakpoint_result is not None: supported_type = True - added_breakpoint, breakpoints = result + added_breakpoint, breakpoints = add_plugin_breakpoint_result file_to_id_to_breakpoint = py_db.file_to_id_to_plugin_breakpoint else: supported_type = False @@ -371,12 +458,28 @@ def add_breakpoint( py_db.has_plugin_line_breaks = py_db.plugin.has_line_breaks() py_db.on_breakpoints_changed() - return error_code + return result + + def reapply_breakpoints(self, py_db): + ''' + Reapplies all the received breakpoints as they were received by the API (so, new + translations are applied). + ''' + items = dict_items(py_db.api_received_breakpoints) # Create a copy with items to reapply. + self.remove_all_breakpoints(py_db, '*') + for _key, val in items: + _new_filename, api_add_breakpoint_params = val + self.add_breakpoint(py_db, *api_add_breakpoint_params) def remove_all_breakpoints(self, py_db, filename): ''' Removes all the breakpoints from a given file or from all files if filename == '*'. + + :param str filename: + Note: must be sent as it was received in the protocol. It may be translated in this + function. ''' + assert filename.__class__ == str # i.e.: bytes on py2 and str on py3 changed = False lst = [ py_db.file_to_id_to_line_breakpoint, @@ -389,15 +492,30 @@ def remove_all_breakpoints(self, py_db, filename): if hasattr(py_db, 'jinja2_breakpoints'): lst.append(py_db.jinja2_breakpoints) - for file_to_id_to_breakpoint in lst: - if filename == '*': + if filename == '*': + py_db.api_received_breakpoints.clear() + + for file_to_id_to_breakpoint in lst: if file_to_id_to_breakpoint: file_to_id_to_breakpoint.clear() changed = True - else: - if filename in file_to_id_to_breakpoint: - del file_to_id_to_breakpoint[filename] - changed = True + + else: + items = dict_items(py_db.api_received_breakpoints) # Create a copy to remove items. + translated_filenames = [] + for key, val in items: + key_filename, _breakpoint_id = key + if key_filename == filename: + new_filename, _api_add_breakpoint_params = val + # Note: there can be actually 1:N mappings due to source mapping (i.e.: ipython). + translated_filenames.append(new_filename) + del py_db.api_received_breakpoints[key] + + for filename in translated_filenames: + for file_to_id_to_breakpoint in lst: + if filename in file_to_id_to_breakpoint: + del file_to_id_to_breakpoint[filename] + changed = True if changed: py_db.on_breakpoints_changed(removed=True) @@ -405,7 +523,8 @@ def remove_all_breakpoints(self, py_db, filename): def remove_breakpoint(self, py_db, filename, breakpoint_type, breakpoint_id): ''' :param str filename: - Note: must be already translated for the server. + Note: must be sent as it was received in the protocol. It may be translated in this + function. :param str breakpoint_type: One of: 'python-line', 'django-line', 'jinja2-line'. @@ -413,6 +532,7 @@ def remove_breakpoint(self, py_db, filename, breakpoint_type, breakpoint_id): :param int breakpoint_id: ''' file_to_id_to_breakpoint = None + filename = self.filename_to_server(filename) if breakpoint_type == 'python-line': breakpoints = py_db.breakpoints @@ -468,9 +588,11 @@ def request_console_exec(self, py_db, seq, thread_id, frame_id, expression): def request_load_source(self, py_db, seq, filename): ''' :param str filename: - Note: must be already translated for the server. + Note: must be sent as it was received in the protocol. It may be translated in this + function. ''' try: + filename = self.filename_to_server(filename) assert filename.__class__ == str # i.e.: bytes on py2 and str on py3 with open(filename, 'r') as stream: @@ -626,3 +748,25 @@ def stop_on_entry(self): info = set_additional_thread_info(main_thread) info.pydev_original_step_cmd = CMD_STOP_ON_START info.pydev_step_cmd = CMD_STEP_INTO_MY_CODE + + SourceMappingEntry = pydevd_source_mapping.SourceMappingEntry + + def set_source_mapping(self, py_db, source_filename, mapping): + ''' + :param str source_filename: + The filename for the source mapping (bytes on py2 and str on py3). + + :param list(SourceMappingEntry) mapping: + A list with the source mapping entries to be applied to the given filename. + + :return str: + An error message if it was not possible to set the mapping or an empty string if + everything is ok. + ''' + source_filename = self.filename_to_server(source_filename) + error_msg = py_db.source_mapping.set_source_mapping(source_filename, mapping) + if error_msg: + return error_msg + + self.reapply_breakpoints(py_db) + return '' diff --git a/src/ptvsd/_vendored/pydevd/_pydevd_bundle/pydevd_cython.c b/src/ptvsd/_vendored/pydevd/_pydevd_bundle/pydevd_cython.c index 365eb6410..43fa8bace 100644 --- a/src/ptvsd/_vendored/pydevd/_pydevd_bundle/pydevd_cython.c +++ b/src/ptvsd/_vendored/pydevd/_pydevd_bundle/pydevd_cython.c @@ -1,4 +1,4 @@ -/* Generated by Cython 0.29.7 */ +/* Generated by Cython 0.29.8 */ /* BEGIN: Cython Metadata { @@ -20,8 +20,8 @@ END: Cython Metadata */ #elif PY_VERSION_HEX < 0x02060000 || (0x03000000 <= PY_VERSION_HEX && PY_VERSION_HEX < 0x03030000) #error Cython requires Python 2.6+ or Python 3.3+. #else -#define CYTHON_ABI "0_29_7" -#define CYTHON_HEX_VERSION 0x001D07F0 +#define CYTHON_ABI "0_29_8" +#define CYTHON_HEX_VERSION 0x001D08F0 #define CYTHON_FUTURE_DIVISION 0 #include #ifndef offsetof @@ -323,8 +323,13 @@ END: Cython Metadata */ #define __Pyx_DefaultClassType PyClass_Type #else #define __Pyx_BUILTIN_MODULE_NAME "builtins" +#if PY_VERSION_HEX < 0x030800A4 #define __Pyx_PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\ PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) +#else + #define __Pyx_PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\ + PyCode_New(a, 0, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) +#endif #define __Pyx_DefaultClassType PyType_Type #endif #ifndef Py_TPFLAGS_CHECKTYPES @@ -26478,7 +26483,7 @@ static PyObject *__pyx_pf_14_pydevd_bundle_13pydevd_cython_12ThreadTracer_2__cal * back_frame_cache_key = (back_frame.f_code.co_firstlineno, back_frame.f_code.co_name, back_frame.f_code.co_filename) * cache_skips[back_frame_cache_key] = 1 # <<<<<<<<<<<<<< * # if DEBUG: print('skipped: trace_dispatch (filtered out: 1)', frame_cache_key, frame.f_lineno, event, frame.f_code.co_name) - * + * return None if event == 'call' else NO_FTRACE */ if (unlikely(__pyx_v_cache_skips == Py_None)) { PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable"); @@ -26486,20 +26491,20 @@ static PyObject *__pyx_pf_14_pydevd_bundle_13pydevd_cython_12ThreadTracer_2__cal } if (unlikely(PyDict_SetItem(__pyx_v_cache_skips, __pyx_v_back_frame_cache_key, __pyx_int_1) < 0)) __PYX_ERR(0, 1374, __pyx_L3_error) - /* "_pydevd_bundle/pydevd_cython.pyx":1377 + /* "_pydevd_bundle/pydevd_cython.pyx":1376 + * cache_skips[back_frame_cache_key] = 1 * # if DEBUG: print('skipped: trace_dispatch (filtered out: 1)', frame_cache_key, frame.f_lineno, event, frame.f_code.co_name) - * * return None if event == 'call' else NO_FTRACE # <<<<<<<<<<<<<< * else: * # if DEBUG: print('skipped: trace_dispatch (filtered out: 2)', frame_cache_key, frame.f_lineno, event, frame.f_code.co_name) */ __Pyx_XDECREF(__pyx_r); - __pyx_t_11 = (__Pyx_PyString_Equals(__pyx_v_event, __pyx_n_s_call, Py_EQ)); if (unlikely(__pyx_t_11 < 0)) __PYX_ERR(0, 1377, __pyx_L3_error) + __pyx_t_11 = (__Pyx_PyString_Equals(__pyx_v_event, __pyx_n_s_call, Py_EQ)); if (unlikely(__pyx_t_11 < 0)) __PYX_ERR(0, 1376, __pyx_L3_error) if (__pyx_t_11) { __Pyx_INCREF(Py_None); __pyx_t_1 = Py_None; } else { - __Pyx_GetModuleGlobalName(__pyx_t_5, __pyx_n_s_NO_FTRACE); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 1377, __pyx_L3_error) + __Pyx_GetModuleGlobalName(__pyx_t_5, __pyx_n_s_NO_FTRACE); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 1376, __pyx_L3_error) __Pyx_GOTREF(__pyx_t_5); __pyx_t_1 = __pyx_t_5; __pyx_t_5 = 0; @@ -26527,7 +26532,7 @@ static PyObject *__pyx_pf_14_pydevd_bundle_13pydevd_cython_12ThreadTracer_2__cal goto __pyx_L50; } - /* "_pydevd_bundle/pydevd_cython.pyx":1380 + /* "_pydevd_bundle/pydevd_cython.pyx":1379 * else: * # if DEBUG: print('skipped: trace_dispatch (filtered out: 2)', frame_cache_key, frame.f_lineno, event, frame.f_code.co_name) * return None if event == 'call' else NO_FTRACE # <<<<<<<<<<<<<< @@ -26536,12 +26541,12 @@ static PyObject *__pyx_pf_14_pydevd_bundle_13pydevd_cython_12ThreadTracer_2__cal */ /*else*/ { __Pyx_XDECREF(__pyx_r); - __pyx_t_11 = (__Pyx_PyString_Equals(__pyx_v_event, __pyx_n_s_call, Py_EQ)); if (unlikely(__pyx_t_11 < 0)) __PYX_ERR(0, 1380, __pyx_L3_error) + __pyx_t_11 = (__Pyx_PyString_Equals(__pyx_v_event, __pyx_n_s_call, Py_EQ)); if (unlikely(__pyx_t_11 < 0)) __PYX_ERR(0, 1379, __pyx_L3_error) if (__pyx_t_11) { __Pyx_INCREF(Py_None); __pyx_t_1 = Py_None; } else { - __Pyx_GetModuleGlobalName(__pyx_t_5, __pyx_n_s_NO_FTRACE); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 1380, __pyx_L3_error) + __Pyx_GetModuleGlobalName(__pyx_t_5, __pyx_n_s_NO_FTRACE); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 1379, __pyx_L3_error) __Pyx_GOTREF(__pyx_t_5); __pyx_t_1 = __pyx_t_5; __pyx_t_5 = 0; @@ -26570,7 +26575,7 @@ static PyObject *__pyx_pf_14_pydevd_bundle_13pydevd_cython_12ThreadTracer_2__cal */ } - /* "_pydevd_bundle/pydevd_cython.pyx":1383 + /* "_pydevd_bundle/pydevd_cython.pyx":1382 * * # if DEBUG: print('trace_dispatch', filename, frame.f_lineno, event, frame.f_code.co_name, file_type) * if additional_info.is_tracing: # <<<<<<<<<<<<<< @@ -26580,7 +26585,7 @@ static PyObject *__pyx_pf_14_pydevd_bundle_13pydevd_cython_12ThreadTracer_2__cal __pyx_t_11 = (__pyx_v_additional_info->is_tracing != 0); if (__pyx_t_11) { - /* "_pydevd_bundle/pydevd_cython.pyx":1384 + /* "_pydevd_bundle/pydevd_cython.pyx":1383 * # if DEBUG: print('trace_dispatch', filename, frame.f_lineno, event, frame.f_code.co_name, file_type) * if additional_info.is_tracing: * return None if event == 'call' else NO_FTRACE # we don't wan't to trace code invoked from pydevd_frame.trace_dispatch # <<<<<<<<<<<<<< @@ -26588,12 +26593,12 @@ static PyObject *__pyx_pf_14_pydevd_bundle_13pydevd_cython_12ThreadTracer_2__cal * # Just create PyDBFrame directly (removed support for Python versions < 2.5, which required keeping a weak */ __Pyx_XDECREF(__pyx_r); - __pyx_t_11 = (__Pyx_PyString_Equals(__pyx_v_event, __pyx_n_s_call, Py_EQ)); if (unlikely(__pyx_t_11 < 0)) __PYX_ERR(0, 1384, __pyx_L3_error) + __pyx_t_11 = (__Pyx_PyString_Equals(__pyx_v_event, __pyx_n_s_call, Py_EQ)); if (unlikely(__pyx_t_11 < 0)) __PYX_ERR(0, 1383, __pyx_L3_error) if (__pyx_t_11) { __Pyx_INCREF(Py_None); __pyx_t_1 = Py_None; } else { - __Pyx_GetModuleGlobalName(__pyx_t_5, __pyx_n_s_NO_FTRACE); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 1384, __pyx_L3_error) + __Pyx_GetModuleGlobalName(__pyx_t_5, __pyx_n_s_NO_FTRACE); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 1383, __pyx_L3_error) __Pyx_GOTREF(__pyx_t_5); __pyx_t_1 = __pyx_t_5; __pyx_t_5 = 0; @@ -26602,7 +26607,7 @@ static PyObject *__pyx_pf_14_pydevd_bundle_13pydevd_cython_12ThreadTracer_2__cal __pyx_t_1 = 0; goto __pyx_L7_try_return; - /* "_pydevd_bundle/pydevd_cython.pyx":1383 + /* "_pydevd_bundle/pydevd_cython.pyx":1382 * * # if DEBUG: print('trace_dispatch', filename, frame.f_lineno, event, frame.f_code.co_name, file_type) * if additional_info.is_tracing: # <<<<<<<<<<<<<< @@ -26611,14 +26616,14 @@ static PyObject *__pyx_pf_14_pydevd_bundle_13pydevd_cython_12ThreadTracer_2__cal */ } - /* "_pydevd_bundle/pydevd_cython.pyx":1390 + /* "_pydevd_bundle/pydevd_cython.pyx":1389 * ret = PyDBFrame( * ( * py_db, filename, additional_info, t, frame_skips_cache, frame_cache_key, # <<<<<<<<<<<<<< * ) * ).trace_dispatch(frame, event, arg) */ - __pyx_t_1 = PyTuple_New(6); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1390, __pyx_L3_error) + __pyx_t_1 = PyTuple_New(6); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1389, __pyx_L3_error) __Pyx_GOTREF(__pyx_t_1); __Pyx_INCREF(__pyx_v_py_db); __Pyx_GIVEREF(__pyx_v_py_db); @@ -26639,32 +26644,32 @@ static PyObject *__pyx_pf_14_pydevd_bundle_13pydevd_cython_12ThreadTracer_2__cal __Pyx_GIVEREF(__pyx_v_frame_cache_key); PyTuple_SET_ITEM(__pyx_t_1, 5, __pyx_v_frame_cache_key); - /* "_pydevd_bundle/pydevd_cython.pyx":1388 + /* "_pydevd_bundle/pydevd_cython.pyx":1387 * # Just create PyDBFrame directly (removed support for Python versions < 2.5, which required keeping a weak * # reference to the frame). * ret = PyDBFrame( # <<<<<<<<<<<<<< * ( * py_db, filename, additional_info, t, frame_skips_cache, frame_cache_key, */ - __pyx_t_5 = __Pyx_PyObject_CallOneArg(((PyObject *)__pyx_ptype_14_pydevd_bundle_13pydevd_cython_PyDBFrame), __pyx_t_1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 1388, __pyx_L3_error) + __pyx_t_5 = __Pyx_PyObject_CallOneArg(((PyObject *)__pyx_ptype_14_pydevd_bundle_13pydevd_cython_PyDBFrame), __pyx_t_1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 1387, __pyx_L3_error) __Pyx_GOTREF(__pyx_t_5); __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - /* "_pydevd_bundle/pydevd_cython.pyx":1392 + /* "_pydevd_bundle/pydevd_cython.pyx":1391 * py_db, filename, additional_info, t, frame_skips_cache, frame_cache_key, * ) * ).trace_dispatch(frame, event, arg) # <<<<<<<<<<<<<< * if ret is None: * # 1 means skipped because of filters. */ - if (!(likely(PyString_CheckExact(__pyx_v_event))||((__pyx_v_event) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "str", Py_TYPE(__pyx_v_event)->tp_name), 0))) __PYX_ERR(0, 1392, __pyx_L3_error) - __pyx_t_1 = ((struct __pyx_vtabstruct_14_pydevd_bundle_13pydevd_cython_PyDBFrame *)((struct __pyx_obj_14_pydevd_bundle_13pydevd_cython_PyDBFrame *)__pyx_t_5)->__pyx_vtab)->trace_dispatch(((struct __pyx_obj_14_pydevd_bundle_13pydevd_cython_PyDBFrame *)__pyx_t_5), __pyx_v_frame, ((PyObject*)__pyx_v_event), __pyx_v_arg, 0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1392, __pyx_L3_error) + if (!(likely(PyString_CheckExact(__pyx_v_event))||((__pyx_v_event) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "str", Py_TYPE(__pyx_v_event)->tp_name), 0))) __PYX_ERR(0, 1391, __pyx_L3_error) + __pyx_t_1 = ((struct __pyx_vtabstruct_14_pydevd_bundle_13pydevd_cython_PyDBFrame *)((struct __pyx_obj_14_pydevd_bundle_13pydevd_cython_PyDBFrame *)__pyx_t_5)->__pyx_vtab)->trace_dispatch(((struct __pyx_obj_14_pydevd_bundle_13pydevd_cython_PyDBFrame *)__pyx_t_5), __pyx_v_frame, ((PyObject*)__pyx_v_event), __pyx_v_arg, 0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1391, __pyx_L3_error) __Pyx_GOTREF(__pyx_t_1); __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; __pyx_v_ret = __pyx_t_1; __pyx_t_1 = 0; - /* "_pydevd_bundle/pydevd_cython.pyx":1393 + /* "_pydevd_bundle/pydevd_cython.pyx":1392 * ) * ).trace_dispatch(frame, event, arg) * if ret is None: # <<<<<<<<<<<<<< @@ -26675,7 +26680,7 @@ static PyObject *__pyx_pf_14_pydevd_bundle_13pydevd_cython_12ThreadTracer_2__cal __pyx_t_12 = (__pyx_t_11 != 0); if (__pyx_t_12) { - /* "_pydevd_bundle/pydevd_cython.pyx":1396 + /* "_pydevd_bundle/pydevd_cython.pyx":1395 * # 1 means skipped because of filters. * # 2 means skipped because no breakpoints were hit. * cache_skips[frame_cache_key] = 2 # <<<<<<<<<<<<<< @@ -26684,11 +26689,11 @@ static PyObject *__pyx_pf_14_pydevd_bundle_13pydevd_cython_12ThreadTracer_2__cal */ if (unlikely(__pyx_v_cache_skips == Py_None)) { PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable"); - __PYX_ERR(0, 1396, __pyx_L3_error) + __PYX_ERR(0, 1395, __pyx_L3_error) } - if (unlikely(PyDict_SetItem(__pyx_v_cache_skips, __pyx_v_frame_cache_key, __pyx_int_2) < 0)) __PYX_ERR(0, 1396, __pyx_L3_error) + if (unlikely(PyDict_SetItem(__pyx_v_cache_skips, __pyx_v_frame_cache_key, __pyx_int_2) < 0)) __PYX_ERR(0, 1395, __pyx_L3_error) - /* "_pydevd_bundle/pydevd_cython.pyx":1397 + /* "_pydevd_bundle/pydevd_cython.pyx":1396 * # 2 means skipped because no breakpoints were hit. * cache_skips[frame_cache_key] = 2 * return None if event == 'call' else NO_FTRACE # <<<<<<<<<<<<<< @@ -26696,12 +26701,12 @@ static PyObject *__pyx_pf_14_pydevd_bundle_13pydevd_cython_12ThreadTracer_2__cal * # IFDEF CYTHON -- DONT EDIT THIS FILE (it is automatically generated) */ __Pyx_XDECREF(__pyx_r); - __pyx_t_12 = (__Pyx_PyString_Equals(__pyx_v_event, __pyx_n_s_call, Py_EQ)); if (unlikely(__pyx_t_12 < 0)) __PYX_ERR(0, 1397, __pyx_L3_error) + __pyx_t_12 = (__Pyx_PyString_Equals(__pyx_v_event, __pyx_n_s_call, Py_EQ)); if (unlikely(__pyx_t_12 < 0)) __PYX_ERR(0, 1396, __pyx_L3_error) if (__pyx_t_12) { __Pyx_INCREF(Py_None); __pyx_t_1 = Py_None; } else { - __Pyx_GetModuleGlobalName(__pyx_t_5, __pyx_n_s_NO_FTRACE); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 1397, __pyx_L3_error) + __Pyx_GetModuleGlobalName(__pyx_t_5, __pyx_n_s_NO_FTRACE); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 1396, __pyx_L3_error) __Pyx_GOTREF(__pyx_t_5); __pyx_t_1 = __pyx_t_5; __pyx_t_5 = 0; @@ -26710,7 +26715,7 @@ static PyObject *__pyx_pf_14_pydevd_bundle_13pydevd_cython_12ThreadTracer_2__cal __pyx_t_1 = 0; goto __pyx_L7_try_return; - /* "_pydevd_bundle/pydevd_cython.pyx":1393 + /* "_pydevd_bundle/pydevd_cython.pyx":1392 * ) * ).trace_dispatch(frame, event, arg) * if ret is None: # <<<<<<<<<<<<<< @@ -26719,19 +26724,19 @@ static PyObject *__pyx_pf_14_pydevd_bundle_13pydevd_cython_12ThreadTracer_2__cal */ } - /* "_pydevd_bundle/pydevd_cython.pyx":1400 + /* "_pydevd_bundle/pydevd_cython.pyx":1399 * * # IFDEF CYTHON -- DONT EDIT THIS FILE (it is automatically generated) * frame.f_trace = SafeCallWrapper(ret) # Make sure we keep the returned tracer. # <<<<<<<<<<<<<< * # ELSE * # frame.f_trace = ret # Make sure we keep the returned tracer. */ - __pyx_t_1 = __Pyx_PyObject_CallOneArg(((PyObject *)__pyx_ptype_14_pydevd_bundle_13pydevd_cython_SafeCallWrapper), __pyx_v_ret); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1400, __pyx_L3_error) + __pyx_t_1 = __Pyx_PyObject_CallOneArg(((PyObject *)__pyx_ptype_14_pydevd_bundle_13pydevd_cython_SafeCallWrapper), __pyx_v_ret); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1399, __pyx_L3_error) __Pyx_GOTREF(__pyx_t_1); - if (__Pyx_PyObject_SetAttrStr(__pyx_v_frame, __pyx_n_s_f_trace, __pyx_t_1) < 0) __PYX_ERR(0, 1400, __pyx_L3_error) + if (__Pyx_PyObject_SetAttrStr(__pyx_v_frame, __pyx_n_s_f_trace, __pyx_t_1) < 0) __PYX_ERR(0, 1399, __pyx_L3_error) __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - /* "_pydevd_bundle/pydevd_cython.pyx":1404 + /* "_pydevd_bundle/pydevd_cython.pyx":1403 * # frame.f_trace = ret # Make sure we keep the returned tracer. * # ENDIF * return ret # <<<<<<<<<<<<<< @@ -26759,7 +26764,7 @@ static PyObject *__pyx_pf_14_pydevd_bundle_13pydevd_cython_12ThreadTracer_2__cal __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0; __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; - /* "_pydevd_bundle/pydevd_cython.pyx":1406 + /* "_pydevd_bundle/pydevd_cython.pyx":1405 * return ret * * except SystemExit: # <<<<<<<<<<<<<< @@ -26769,12 +26774,12 @@ static PyObject *__pyx_pf_14_pydevd_bundle_13pydevd_cython_12ThreadTracer_2__cal __pyx_t_7 = __Pyx_PyErr_ExceptionMatches(__pyx_builtin_SystemExit); if (__pyx_t_7) { __Pyx_AddTraceback("_pydevd_bundle.pydevd_cython.ThreadTracer.__call__", __pyx_clineno, __pyx_lineno, __pyx_filename); - if (__Pyx_GetException(&__pyx_t_1, &__pyx_t_5, &__pyx_t_3) < 0) __PYX_ERR(0, 1406, __pyx_L5_except_error) + if (__Pyx_GetException(&__pyx_t_1, &__pyx_t_5, &__pyx_t_3) < 0) __PYX_ERR(0, 1405, __pyx_L5_except_error) __Pyx_GOTREF(__pyx_t_1); __Pyx_GOTREF(__pyx_t_5); __Pyx_GOTREF(__pyx_t_3); - /* "_pydevd_bundle/pydevd_cython.pyx":1407 + /* "_pydevd_bundle/pydevd_cython.pyx":1406 * * except SystemExit: * return None if event == 'call' else NO_FTRACE # <<<<<<<<<<<<<< @@ -26782,12 +26787,12 @@ static PyObject *__pyx_pf_14_pydevd_bundle_13pydevd_cython_12ThreadTracer_2__cal * except Exception: */ __Pyx_XDECREF(__pyx_r); - __pyx_t_12 = (__Pyx_PyString_Equals(__pyx_v_event, __pyx_n_s_call, Py_EQ)); if (unlikely(__pyx_t_12 < 0)) __PYX_ERR(0, 1407, __pyx_L5_except_error) + __pyx_t_12 = (__Pyx_PyString_Equals(__pyx_v_event, __pyx_n_s_call, Py_EQ)); if (unlikely(__pyx_t_12 < 0)) __PYX_ERR(0, 1406, __pyx_L5_except_error) if (__pyx_t_12) { __Pyx_INCREF(Py_None); __pyx_t_6 = Py_None; } else { - __Pyx_GetModuleGlobalName(__pyx_t_4, __pyx_n_s_NO_FTRACE); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 1407, __pyx_L5_except_error) + __Pyx_GetModuleGlobalName(__pyx_t_4, __pyx_n_s_NO_FTRACE); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 1406, __pyx_L5_except_error) __Pyx_GOTREF(__pyx_t_4); __pyx_t_6 = __pyx_t_4; __pyx_t_4 = 0; @@ -26800,7 +26805,7 @@ static PyObject *__pyx_pf_14_pydevd_bundle_13pydevd_cython_12ThreadTracer_2__cal goto __pyx_L6_except_return; } - /* "_pydevd_bundle/pydevd_cython.pyx":1409 + /* "_pydevd_bundle/pydevd_cython.pyx":1408 * return None if event == 'call' else NO_FTRACE * * except Exception: # <<<<<<<<<<<<<< @@ -26810,25 +26815,25 @@ static PyObject *__pyx_pf_14_pydevd_bundle_13pydevd_cython_12ThreadTracer_2__cal __pyx_t_7 = __Pyx_PyErr_ExceptionMatches(((PyObject *)(&((PyTypeObject*)PyExc_Exception)[0]))); if (__pyx_t_7) { __Pyx_AddTraceback("_pydevd_bundle.pydevd_cython.ThreadTracer.__call__", __pyx_clineno, __pyx_lineno, __pyx_filename); - if (__Pyx_GetException(&__pyx_t_3, &__pyx_t_5, &__pyx_t_1) < 0) __PYX_ERR(0, 1409, __pyx_L5_except_error) + if (__Pyx_GetException(&__pyx_t_3, &__pyx_t_5, &__pyx_t_1) < 0) __PYX_ERR(0, 1408, __pyx_L5_except_error) __Pyx_GOTREF(__pyx_t_3); __Pyx_GOTREF(__pyx_t_5); __Pyx_GOTREF(__pyx_t_1); - /* "_pydevd_bundle/pydevd_cython.pyx":1410 + /* "_pydevd_bundle/pydevd_cython.pyx":1409 * * except Exception: * if py_db._finish_debugging_session: # <<<<<<<<<<<<<< * return None if event == 'call' else NO_FTRACE # Don't log errors when we're shutting down. * # Log it */ - __pyx_t_6 = __Pyx_PyObject_GetAttrStr(__pyx_v_py_db, __pyx_n_s_finish_debugging_session); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 1410, __pyx_L5_except_error) + __pyx_t_6 = __Pyx_PyObject_GetAttrStr(__pyx_v_py_db, __pyx_n_s_finish_debugging_session); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 1409, __pyx_L5_except_error) __Pyx_GOTREF(__pyx_t_6); - __pyx_t_12 = __Pyx_PyObject_IsTrue(__pyx_t_6); if (unlikely(__pyx_t_12 < 0)) __PYX_ERR(0, 1410, __pyx_L5_except_error) + __pyx_t_12 = __Pyx_PyObject_IsTrue(__pyx_t_6); if (unlikely(__pyx_t_12 < 0)) __PYX_ERR(0, 1409, __pyx_L5_except_error) __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; if (__pyx_t_12) { - /* "_pydevd_bundle/pydevd_cython.pyx":1411 + /* "_pydevd_bundle/pydevd_cython.pyx":1410 * except Exception: * if py_db._finish_debugging_session: * return None if event == 'call' else NO_FTRACE # Don't log errors when we're shutting down. # <<<<<<<<<<<<<< @@ -26836,12 +26841,12 @@ static PyObject *__pyx_pf_14_pydevd_bundle_13pydevd_cython_12ThreadTracer_2__cal * try: */ __Pyx_XDECREF(__pyx_r); - __pyx_t_12 = (__Pyx_PyString_Equals(__pyx_v_event, __pyx_n_s_call, Py_EQ)); if (unlikely(__pyx_t_12 < 0)) __PYX_ERR(0, 1411, __pyx_L5_except_error) + __pyx_t_12 = (__Pyx_PyString_Equals(__pyx_v_event, __pyx_n_s_call, Py_EQ)); if (unlikely(__pyx_t_12 < 0)) __PYX_ERR(0, 1410, __pyx_L5_except_error) if (__pyx_t_12) { __Pyx_INCREF(Py_None); __pyx_t_6 = Py_None; } else { - __Pyx_GetModuleGlobalName(__pyx_t_4, __pyx_n_s_NO_FTRACE); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 1411, __pyx_L5_except_error) + __Pyx_GetModuleGlobalName(__pyx_t_4, __pyx_n_s_NO_FTRACE); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 1410, __pyx_L5_except_error) __Pyx_GOTREF(__pyx_t_4); __pyx_t_6 = __pyx_t_4; __pyx_t_4 = 0; @@ -26853,7 +26858,7 @@ static PyObject *__pyx_pf_14_pydevd_bundle_13pydevd_cython_12ThreadTracer_2__cal __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; goto __pyx_L6_except_return; - /* "_pydevd_bundle/pydevd_cython.pyx":1410 + /* "_pydevd_bundle/pydevd_cython.pyx":1409 * * except Exception: * if py_db._finish_debugging_session: # <<<<<<<<<<<<<< @@ -26862,7 +26867,7 @@ static PyObject *__pyx_pf_14_pydevd_bundle_13pydevd_cython_12ThreadTracer_2__cal */ } - /* "_pydevd_bundle/pydevd_cython.pyx":1413 + /* "_pydevd_bundle/pydevd_cython.pyx":1412 * return None if event == 'call' else NO_FTRACE # Don't log errors when we're shutting down. * # Log it * try: # <<<<<<<<<<<<<< @@ -26878,28 +26883,28 @@ static PyObject *__pyx_pf_14_pydevd_bundle_13pydevd_cython_12ThreadTracer_2__cal __Pyx_XGOTREF(__pyx_t_15); /*try:*/ { - /* "_pydevd_bundle/pydevd_cython.pyx":1414 + /* "_pydevd_bundle/pydevd_cython.pyx":1413 * # Log it * try: * if pydev_log_exception is not None: # <<<<<<<<<<<<<< * # This can actually happen during the interpreter shutdown in Python 2.7 * pydev_log_exception() */ - __Pyx_GetModuleGlobalName(__pyx_t_6, __pyx_n_s_pydev_log_exception); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 1414, __pyx_L61_error) + __Pyx_GetModuleGlobalName(__pyx_t_6, __pyx_n_s_pydev_log_exception); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 1413, __pyx_L61_error) __Pyx_GOTREF(__pyx_t_6); __pyx_t_12 = (__pyx_t_6 != Py_None); __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; __pyx_t_11 = (__pyx_t_12 != 0); if (__pyx_t_11) { - /* "_pydevd_bundle/pydevd_cython.pyx":1416 + /* "_pydevd_bundle/pydevd_cython.pyx":1415 * if pydev_log_exception is not None: * # This can actually happen during the interpreter shutdown in Python 2.7 * pydev_log_exception() # <<<<<<<<<<<<<< * except: * # Error logging? We're really in the interpreter shutdown... */ - __Pyx_GetModuleGlobalName(__pyx_t_4, __pyx_n_s_pydev_log_exception); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 1416, __pyx_L61_error) + __Pyx_GetModuleGlobalName(__pyx_t_4, __pyx_n_s_pydev_log_exception); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 1415, __pyx_L61_error) __Pyx_GOTREF(__pyx_t_4); __pyx_t_2 = NULL; if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_4))) { @@ -26913,12 +26918,12 @@ static PyObject *__pyx_pf_14_pydevd_bundle_13pydevd_cython_12ThreadTracer_2__cal } __pyx_t_6 = (__pyx_t_2) ? __Pyx_PyObject_CallOneArg(__pyx_t_4, __pyx_t_2) : __Pyx_PyObject_CallNoArg(__pyx_t_4); __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; - if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 1416, __pyx_L61_error) + if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 1415, __pyx_L61_error) __Pyx_GOTREF(__pyx_t_6); __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; - /* "_pydevd_bundle/pydevd_cython.pyx":1414 + /* "_pydevd_bundle/pydevd_cython.pyx":1413 * # Log it * try: * if pydev_log_exception is not None: # <<<<<<<<<<<<<< @@ -26927,7 +26932,7 @@ static PyObject *__pyx_pf_14_pydevd_bundle_13pydevd_cython_12ThreadTracer_2__cal */ } - /* "_pydevd_bundle/pydevd_cython.pyx":1413 + /* "_pydevd_bundle/pydevd_cython.pyx":1412 * return None if event == 'call' else NO_FTRACE # Don't log errors when we're shutting down. * # Log it * try: # <<<<<<<<<<<<<< @@ -26944,7 +26949,7 @@ static PyObject *__pyx_pf_14_pydevd_bundle_13pydevd_cython_12ThreadTracer_2__cal __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; - /* "_pydevd_bundle/pydevd_cython.pyx":1417 + /* "_pydevd_bundle/pydevd_cython.pyx":1416 * # This can actually happen during the interpreter shutdown in Python 2.7 * pydev_log_exception() * except: # <<<<<<<<<<<<<< @@ -26963,7 +26968,7 @@ static PyObject *__pyx_pf_14_pydevd_bundle_13pydevd_cython_12ThreadTracer_2__cal __pyx_L68_try_end:; } - /* "_pydevd_bundle/pydevd_cython.pyx":1421 + /* "_pydevd_bundle/pydevd_cython.pyx":1420 * # (https://github.com/fabioz/PyDev.Debugger/issues/8) * pass * return None if event == 'call' else NO_FTRACE # <<<<<<<<<<<<<< @@ -26971,12 +26976,12 @@ static PyObject *__pyx_pf_14_pydevd_bundle_13pydevd_cython_12ThreadTracer_2__cal * */ __Pyx_XDECREF(__pyx_r); - __pyx_t_11 = (__Pyx_PyString_Equals(__pyx_v_event, __pyx_n_s_call, Py_EQ)); if (unlikely(__pyx_t_11 < 0)) __PYX_ERR(0, 1421, __pyx_L5_except_error) + __pyx_t_11 = (__Pyx_PyString_Equals(__pyx_v_event, __pyx_n_s_call, Py_EQ)); if (unlikely(__pyx_t_11 < 0)) __PYX_ERR(0, 1420, __pyx_L5_except_error) if (__pyx_t_11) { __Pyx_INCREF(Py_None); __pyx_t_6 = Py_None; } else { - __Pyx_GetModuleGlobalName(__pyx_t_4, __pyx_n_s_NO_FTRACE); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 1421, __pyx_L5_except_error) + __Pyx_GetModuleGlobalName(__pyx_t_4, __pyx_n_s_NO_FTRACE); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 1420, __pyx_L5_except_error) __Pyx_GOTREF(__pyx_t_4); __pyx_t_6 = __pyx_t_4; __pyx_t_4 = 0; @@ -27445,7 +27450,7 @@ static PyObject *__pyx_pf_14_pydevd_bundle_13pydevd_cython_12ThreadTracer_6__set return __pyx_r; } -/* "_pydevd_bundle/pydevd_cython.pyx":1436 +/* "_pydevd_bundle/pydevd_cython.pyx":1435 * _original_call = ThreadTracer.__call__ * * def __call__(self, frame, event, arg): # <<<<<<<<<<<<<< @@ -27491,23 +27496,23 @@ static PyObject *__pyx_pw_14_pydevd_bundle_13pydevd_cython_15__call__(PyObject * case 1: if (likely((values[1] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_frame)) != 0)) kw_args--; else { - __Pyx_RaiseArgtupleInvalid("__call__", 1, 4, 4, 1); __PYX_ERR(0, 1436, __pyx_L3_error) + __Pyx_RaiseArgtupleInvalid("__call__", 1, 4, 4, 1); __PYX_ERR(0, 1435, __pyx_L3_error) } CYTHON_FALLTHROUGH; case 2: if (likely((values[2] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_event)) != 0)) kw_args--; else { - __Pyx_RaiseArgtupleInvalid("__call__", 1, 4, 4, 2); __PYX_ERR(0, 1436, __pyx_L3_error) + __Pyx_RaiseArgtupleInvalid("__call__", 1, 4, 4, 2); __PYX_ERR(0, 1435, __pyx_L3_error) } CYTHON_FALLTHROUGH; case 3: if (likely((values[3] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_arg)) != 0)) kw_args--; else { - __Pyx_RaiseArgtupleInvalid("__call__", 1, 4, 4, 3); __PYX_ERR(0, 1436, __pyx_L3_error) + __Pyx_RaiseArgtupleInvalid("__call__", 1, 4, 4, 3); __PYX_ERR(0, 1435, __pyx_L3_error) } } if (unlikely(kw_args > 0)) { - if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "__call__") < 0)) __PYX_ERR(0, 1436, __pyx_L3_error) + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "__call__") < 0)) __PYX_ERR(0, 1435, __pyx_L3_error) } } else if (PyTuple_GET_SIZE(__pyx_args) != 4) { goto __pyx_L5_argtuple_error; @@ -27524,7 +27529,7 @@ static PyObject *__pyx_pw_14_pydevd_bundle_13pydevd_cython_15__call__(PyObject * } goto __pyx_L4_argument_unpacking_done; __pyx_L5_argtuple_error:; - __Pyx_RaiseArgtupleInvalid("__call__", 1, 4, 4, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 1436, __pyx_L3_error) + __Pyx_RaiseArgtupleInvalid("__call__", 1, 4, 4, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 1435, __pyx_L3_error) __pyx_L3_error:; __Pyx_AddTraceback("_pydevd_bundle.pydevd_cython.__call__", __pyx_clineno, __pyx_lineno, __pyx_filename); __Pyx_RefNannyFinishContext(); @@ -27547,28 +27552,28 @@ static PyObject *__pyx_pf_14_pydevd_bundle_13pydevd_cython_14__call__(CYTHON_UNU PyObject *__pyx_t_5 = NULL; __Pyx_RefNannySetupContext("__call__", 0); - /* "_pydevd_bundle/pydevd_cython.pyx":1437 + /* "_pydevd_bundle/pydevd_cython.pyx":1436 * * def __call__(self, frame, event, arg): * _tid_to_last_frame[self._args[1].ident] = frame # <<<<<<<<<<<<<< * return _original_call(self, frame, event, arg) * */ - __Pyx_GetModuleGlobalName(__pyx_t_1, __pyx_n_s_tid_to_last_frame); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1437, __pyx_L1_error) + __Pyx_GetModuleGlobalName(__pyx_t_1, __pyx_n_s_tid_to_last_frame); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1436, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_1); - __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_args_2); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 1437, __pyx_L1_error) + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_args_2); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 1436, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_2); - __pyx_t_3 = __Pyx_GetItemInt(__pyx_t_2, 1, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1437, __pyx_L1_error) + __pyx_t_3 = __Pyx_GetItemInt(__pyx_t_2, 1, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1436, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_3); __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_ident); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 1437, __pyx_L1_error) + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_ident); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 1436, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_2); __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - if (unlikely(PyObject_SetItem(__pyx_t_1, __pyx_t_2, __pyx_v_frame) < 0)) __PYX_ERR(0, 1437, __pyx_L1_error) + if (unlikely(PyObject_SetItem(__pyx_t_1, __pyx_t_2, __pyx_v_frame) < 0)) __PYX_ERR(0, 1436, __pyx_L1_error) __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - /* "_pydevd_bundle/pydevd_cython.pyx":1438 + /* "_pydevd_bundle/pydevd_cython.pyx":1437 * def __call__(self, frame, event, arg): * _tid_to_last_frame[self._args[1].ident] = frame * return _original_call(self, frame, event, arg) # <<<<<<<<<<<<<< @@ -27576,7 +27581,7 @@ static PyObject *__pyx_pf_14_pydevd_bundle_13pydevd_cython_14__call__(CYTHON_UNU * ThreadTracer.__call__ = __call__ */ __Pyx_XDECREF(__pyx_r); - __Pyx_GetModuleGlobalName(__pyx_t_1, __pyx_n_s_original_call); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1438, __pyx_L1_error) + __Pyx_GetModuleGlobalName(__pyx_t_1, __pyx_n_s_original_call); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1437, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_1); __pyx_t_3 = NULL; __pyx_t_4 = 0; @@ -27593,7 +27598,7 @@ static PyObject *__pyx_pf_14_pydevd_bundle_13pydevd_cython_14__call__(CYTHON_UNU #if CYTHON_FAST_PYCALL if (PyFunction_Check(__pyx_t_1)) { PyObject *__pyx_temp[5] = {__pyx_t_3, __pyx_v_self, __pyx_v_frame, __pyx_v_event, __pyx_v_arg}; - __pyx_t_2 = __Pyx_PyFunction_FastCall(__pyx_t_1, __pyx_temp+1-__pyx_t_4, 4+__pyx_t_4); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 1438, __pyx_L1_error) + __pyx_t_2 = __Pyx_PyFunction_FastCall(__pyx_t_1, __pyx_temp+1-__pyx_t_4, 4+__pyx_t_4); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 1437, __pyx_L1_error) __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; __Pyx_GOTREF(__pyx_t_2); } else @@ -27601,13 +27606,13 @@ static PyObject *__pyx_pf_14_pydevd_bundle_13pydevd_cython_14__call__(CYTHON_UNU #if CYTHON_FAST_PYCCALL if (__Pyx_PyFastCFunction_Check(__pyx_t_1)) { PyObject *__pyx_temp[5] = {__pyx_t_3, __pyx_v_self, __pyx_v_frame, __pyx_v_event, __pyx_v_arg}; - __pyx_t_2 = __Pyx_PyCFunction_FastCall(__pyx_t_1, __pyx_temp+1-__pyx_t_4, 4+__pyx_t_4); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 1438, __pyx_L1_error) + __pyx_t_2 = __Pyx_PyCFunction_FastCall(__pyx_t_1, __pyx_temp+1-__pyx_t_4, 4+__pyx_t_4); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 1437, __pyx_L1_error) __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; __Pyx_GOTREF(__pyx_t_2); } else #endif { - __pyx_t_5 = PyTuple_New(4+__pyx_t_4); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 1438, __pyx_L1_error) + __pyx_t_5 = PyTuple_New(4+__pyx_t_4); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 1437, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_5); if (__pyx_t_3) { __Pyx_GIVEREF(__pyx_t_3); PyTuple_SET_ITEM(__pyx_t_5, 0, __pyx_t_3); __pyx_t_3 = NULL; @@ -27624,7 +27629,7 @@ static PyObject *__pyx_pf_14_pydevd_bundle_13pydevd_cython_14__call__(CYTHON_UNU __Pyx_INCREF(__pyx_v_arg); __Pyx_GIVEREF(__pyx_v_arg); PyTuple_SET_ITEM(__pyx_t_5, 3+__pyx_t_4, __pyx_v_arg); - __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_1, __pyx_t_5, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 1438, __pyx_L1_error) + __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_1, __pyx_t_5, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 1437, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_2); __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; } @@ -27633,7 +27638,7 @@ static PyObject *__pyx_pf_14_pydevd_bundle_13pydevd_cython_14__call__(CYTHON_UNU __pyx_t_2 = 0; goto __pyx_L0; - /* "_pydevd_bundle/pydevd_cython.pyx":1436 + /* "_pydevd_bundle/pydevd_cython.pyx":1435 * _original_call = ThreadTracer.__call__ * * def __call__(self, frame, event, arg): # <<<<<<<<<<<<<< @@ -31785,7 +31790,7 @@ static CYTHON_SMALL_CODE int __Pyx_InitCachedBuiltins(void) { __pyx_builtin_StopIteration = __Pyx_GetBuiltinName(__pyx_n_s_StopIteration); if (!__pyx_builtin_StopIteration) __PYX_ERR(0, 576, __pyx_L1_error) __pyx_builtin_GeneratorExit = __Pyx_GetBuiltinName(__pyx_n_s_GeneratorExit); if (!__pyx_builtin_GeneratorExit) __PYX_ERR(0, 576, __pyx_L1_error) __pyx_builtin_KeyboardInterrupt = __Pyx_GetBuiltinName(__pyx_n_s_KeyboardInterrupt); if (!__pyx_builtin_KeyboardInterrupt) __PYX_ERR(0, 895, __pyx_L1_error) - __pyx_builtin_SystemExit = __Pyx_GetBuiltinName(__pyx_n_s_SystemExit); if (!__pyx_builtin_SystemExit) __PYX_ERR(0, 1406, __pyx_L1_error) + __pyx_builtin_SystemExit = __Pyx_GetBuiltinName(__pyx_n_s_SystemExit); if (!__pyx_builtin_SystemExit) __PYX_ERR(0, 1405, __pyx_L1_error) return 0; __pyx_L1_error:; return -1; @@ -31975,17 +31980,17 @@ static CYTHON_SMALL_CODE int __Pyx_InitCachedConstants(void) { __Pyx_GIVEREF(__pyx_tuple__26); __pyx_codeobj__27 = (PyObject*)__Pyx_PyCode_New(4, 0, 6, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__26, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_pydevd_bundle_pydevd_cython_pyx, __pyx_n_s_trace_dispatch, 1103, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__27)) __PYX_ERR(0, 1103, __pyx_L1_error) - /* "_pydevd_bundle/pydevd_cython.pyx":1436 + /* "_pydevd_bundle/pydevd_cython.pyx":1435 * _original_call = ThreadTracer.__call__ * * def __call__(self, frame, event, arg): # <<<<<<<<<<<<<< * _tid_to_last_frame[self._args[1].ident] = frame * return _original_call(self, frame, event, arg) */ - __pyx_tuple__28 = PyTuple_Pack(4, __pyx_n_s_self, __pyx_n_s_frame, __pyx_n_s_event, __pyx_n_s_arg); if (unlikely(!__pyx_tuple__28)) __PYX_ERR(0, 1436, __pyx_L1_error) + __pyx_tuple__28 = PyTuple_Pack(4, __pyx_n_s_self, __pyx_n_s_frame, __pyx_n_s_event, __pyx_n_s_arg); if (unlikely(!__pyx_tuple__28)) __PYX_ERR(0, 1435, __pyx_L1_error) __Pyx_GOTREF(__pyx_tuple__28); __Pyx_GIVEREF(__pyx_tuple__28); - __pyx_codeobj__29 = (PyObject*)__Pyx_PyCode_New(4, 0, 4, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__28, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_pydevd_bundle_pydevd_cython_pyx, __pyx_n_s_call_2, 1436, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__29)) __PYX_ERR(0, 1436, __pyx_L1_error) + __pyx_codeobj__29 = (PyObject*)__Pyx_PyCode_New(4, 0, 4, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__28, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_pydevd_bundle_pydevd_cython_pyx, __pyx_n_s_call_2, 1435, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__29)) __PYX_ERR(0, 1435, __pyx_L1_error) /* "(tree fragment)":1 * def __pyx_unpickle_PyDBAdditionalThreadInfo(__pyx_type, long __pyx_checksum, __pyx_state): # <<<<<<<<<<<<<< @@ -33639,75 +33644,75 @@ if (!__Pyx_RefNanny) { if (PyDict_SetItem(__pyx_d, __pyx_n_s_trace_dispatch, __pyx_t_1) < 0) __PYX_ERR(0, 1103, __pyx_L1_error) __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - /* "_pydevd_bundle/pydevd_cython.pyx":1424 + /* "_pydevd_bundle/pydevd_cython.pyx":1423 * * * if IS_IRONPYTHON: # <<<<<<<<<<<<<< * # This is far from ideal, as we'll leak frames (we'll always have the last created frame, not really * # the last topmost frame saved -- this should be Ok for our usage, but it may leak frames and things */ - __Pyx_GetModuleGlobalName(__pyx_t_1, __pyx_n_s_IS_IRONPYTHON); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1424, __pyx_L1_error) + __Pyx_GetModuleGlobalName(__pyx_t_1, __pyx_n_s_IS_IRONPYTHON); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1423, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_1); - __pyx_t_4 = __Pyx_PyObject_IsTrue(__pyx_t_1); if (unlikely(__pyx_t_4 < 0)) __PYX_ERR(0, 1424, __pyx_L1_error) + __pyx_t_4 = __Pyx_PyObject_IsTrue(__pyx_t_1); if (unlikely(__pyx_t_4 < 0)) __PYX_ERR(0, 1423, __pyx_L1_error) __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; if (__pyx_t_4) { - /* "_pydevd_bundle/pydevd_cython.pyx":1432 + /* "_pydevd_bundle/pydevd_cython.pyx":1431 * # * # See: https://github.com/IronLanguages/main/issues/1630 * from _pydevd_bundle.pydevd_additional_thread_info_regular import _tid_to_last_frame # <<<<<<<<<<<<<< * * _original_call = ThreadTracer.__call__ */ - __pyx_t_1 = PyList_New(1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1432, __pyx_L1_error) + __pyx_t_1 = PyList_New(1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1431, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_1); __Pyx_INCREF(__pyx_n_s_tid_to_last_frame); __Pyx_GIVEREF(__pyx_n_s_tid_to_last_frame); PyList_SET_ITEM(__pyx_t_1, 0, __pyx_n_s_tid_to_last_frame); - __pyx_t_2 = __Pyx_Import(__pyx_n_s_pydevd_bundle_pydevd_additional, __pyx_t_1, -1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 1432, __pyx_L1_error) + __pyx_t_2 = __Pyx_Import(__pyx_n_s_pydevd_bundle_pydevd_additional, __pyx_t_1, -1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 1431, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_2); __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __pyx_t_1 = __Pyx_ImportFrom(__pyx_t_2, __pyx_n_s_tid_to_last_frame); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1432, __pyx_L1_error) + __pyx_t_1 = __Pyx_ImportFrom(__pyx_t_2, __pyx_n_s_tid_to_last_frame); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1431, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_1); - if (PyDict_SetItem(__pyx_d, __pyx_n_s_tid_to_last_frame, __pyx_t_1) < 0) __PYX_ERR(0, 1432, __pyx_L1_error) + if (PyDict_SetItem(__pyx_d, __pyx_n_s_tid_to_last_frame, __pyx_t_1) < 0) __PYX_ERR(0, 1431, __pyx_L1_error) __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - /* "_pydevd_bundle/pydevd_cython.pyx":1434 + /* "_pydevd_bundle/pydevd_cython.pyx":1433 * from _pydevd_bundle.pydevd_additional_thread_info_regular import _tid_to_last_frame * * _original_call = ThreadTracer.__call__ # <<<<<<<<<<<<<< * * def __call__(self, frame, event, arg): */ - __pyx_t_2 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_ptype_14_pydevd_bundle_13pydevd_cython_ThreadTracer), __pyx_n_s_call_2); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 1434, __pyx_L1_error) + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_ptype_14_pydevd_bundle_13pydevd_cython_ThreadTracer), __pyx_n_s_call_2); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 1433, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_2); - if (PyDict_SetItem(__pyx_d, __pyx_n_s_original_call, __pyx_t_2) < 0) __PYX_ERR(0, 1434, __pyx_L1_error) + if (PyDict_SetItem(__pyx_d, __pyx_n_s_original_call, __pyx_t_2) < 0) __PYX_ERR(0, 1433, __pyx_L1_error) __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - /* "_pydevd_bundle/pydevd_cython.pyx":1436 + /* "_pydevd_bundle/pydevd_cython.pyx":1435 * _original_call = ThreadTracer.__call__ * * def __call__(self, frame, event, arg): # <<<<<<<<<<<<<< * _tid_to_last_frame[self._args[1].ident] = frame * return _original_call(self, frame, event, arg) */ - __pyx_t_2 = PyCFunction_NewEx(&__pyx_mdef_14_pydevd_bundle_13pydevd_cython_15__call__, NULL, __pyx_n_s_pydevd_bundle_pydevd_cython); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 1436, __pyx_L1_error) + __pyx_t_2 = PyCFunction_NewEx(&__pyx_mdef_14_pydevd_bundle_13pydevd_cython_15__call__, NULL, __pyx_n_s_pydevd_bundle_pydevd_cython); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 1435, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_2); - if (PyDict_SetItem(__pyx_d, __pyx_n_s_call_2, __pyx_t_2) < 0) __PYX_ERR(0, 1436, __pyx_L1_error) + if (PyDict_SetItem(__pyx_d, __pyx_n_s_call_2, __pyx_t_2) < 0) __PYX_ERR(0, 1435, __pyx_L1_error) __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - /* "_pydevd_bundle/pydevd_cython.pyx":1440 + /* "_pydevd_bundle/pydevd_cython.pyx":1439 * return _original_call(self, frame, event, arg) * * ThreadTracer.__call__ = __call__ # <<<<<<<<<<<<<< */ - __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_n_s_call_2); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 1440, __pyx_L1_error) + __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_n_s_call_2); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 1439, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_2); - if (__Pyx_PyObject_SetAttrStr(((PyObject *)__pyx_ptype_14_pydevd_bundle_13pydevd_cython_ThreadTracer), __pyx_n_s_call_2, __pyx_t_2) < 0) __PYX_ERR(0, 1440, __pyx_L1_error) + if (__Pyx_PyObject_SetAttrStr(((PyObject *)__pyx_ptype_14_pydevd_bundle_13pydevd_cython_ThreadTracer), __pyx_n_s_call_2, __pyx_t_2) < 0) __PYX_ERR(0, 1439, __pyx_L1_error) __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - /* "_pydevd_bundle/pydevd_cython.pyx":1424 + /* "_pydevd_bundle/pydevd_cython.pyx":1423 * * * if IS_IRONPYTHON: # <<<<<<<<<<<<<< diff --git a/src/ptvsd/_vendored/pydevd/_pydevd_bundle/pydevd_cython.pyx b/src/ptvsd/_vendored/pydevd/_pydevd_bundle/pydevd_cython.pyx index fa87798a9..deba282f6 100644 --- a/src/ptvsd/_vendored/pydevd/_pydevd_bundle/pydevd_cython.pyx +++ b/src/ptvsd/_vendored/pydevd/_pydevd_bundle/pydevd_cython.pyx @@ -1373,7 +1373,6 @@ cdef class ThreadTracer: back_frame_cache_key = (back_frame.f_code.co_firstlineno, back_frame.f_code.co_name, back_frame.f_code.co_filename) cache_skips[back_frame_cache_key] = 1 # if DEBUG: print('skipped: trace_dispatch (filtered out: 1)', frame_cache_key, frame.f_lineno, event, frame.f_code.co_name) - return None if event == 'call' else NO_FTRACE else: # if DEBUG: print('skipped: trace_dispatch (filtered out: 2)', frame_cache_key, frame.f_lineno, event, frame.f_code.co_name) diff --git a/src/ptvsd/_vendored/pydevd/_pydevd_bundle/pydevd_dont_trace_files.py b/src/ptvsd/_vendored/pydevd/_pydevd_bundle/pydevd_dont_trace_files.py index 520c0a3d3..4a8f6008b 100644 --- a/src/ptvsd/_vendored/pydevd/_pydevd_bundle/pydevd_dont_trace_files.py +++ b/src/ptvsd/_vendored/pydevd/_pydevd_bundle/pydevd_dont_trace_files.py @@ -111,6 +111,7 @@ 'pydevd_schema.py': PYDEV_FILE, 'pydevd_schema_log.py': PYDEV_FILE, 'pydevd_signature.py': PYDEV_FILE, + 'pydevd_source_mapping.py': PYDEV_FILE, 'pydevd_stackless.py': PYDEV_FILE, 'pydevd_suspended_frames.py': PYDEV_FILE, 'pydevd_thread_wrappers.py': PYDEV_FILE, diff --git a/src/ptvsd/_vendored/pydevd/_pydevd_bundle/pydevd_filtering.py b/src/ptvsd/_vendored/pydevd/_pydevd_bundle/pydevd_filtering.py index ec11080e4..ed6c1acc5 100644 --- a/src/ptvsd/_vendored/pydevd/_pydevd_bundle/pydevd_filtering.py +++ b/src/ptvsd/_vendored/pydevd/_pydevd_bundle/pydevd_filtering.py @@ -217,9 +217,16 @@ def in_project_roots(self, filename): ''' Note: don't call directly. Use PyDb.in_project_scope (no caching here). ''' + if filename.startswith('<') and filename.endswith('>'): + # This is a dummy filename that is usually used for eval or exec. Assume + # that it is user code, with one exception: is used in the + # standard library. + in_project = not filename.startswith(''): - filename = self._normpath(filename) + + filename = self._normpath(filename) found_in_project = [] for root in project_roots: @@ -236,13 +243,7 @@ def in_project_roots(self, filename): # If we have no project roots configured, consider it being in the project # roots if it's not found in site-packages (because we have defaults for those # and not the other way around). - if filename.endswith('>'): - # This is a dummy filename that is usually used for eval or exec. Assume - # that it is user code, with one exception: is used in the - # standard library. - in_project = not filename.startswith(' 0: - bp['line'] = lines[idx - 1] - btype = 'python-line' suspend_policy = 'ALL' - if not filename.lower().endswith('.py'): + if not filename.lower().endswith('.py'): # Note: check based on original file, not mapping. if self._debug_options.get('DJANGO_DEBUG', False): btype = 'django-line' elif self._debug_options.get('FLASK_DEBUG', False): @@ -519,8 +474,9 @@ def on_setbreakpoints_request(self, py_db, request): is_logpoint = True expression = convert_dap_log_message_to_expression(log_message) - error_code = self.api.add_breakpoint( - py_db, filename, btype, breakpoint_id, line, condition, func_name, expression, suspend_policy, hit_condition, is_logpoint) + result = self.api.add_breakpoint( + py_db, filename, btype, breakpoint_id, line, condition, func_name, expression, suspend_policy, hit_condition, is_logpoint, adjust_line=True) + error_code = result.error_code if error_code: if error_code == self.api.ADD_BREAKPOINT_FILE_NOT_FOUND: @@ -536,13 +492,13 @@ def on_setbreakpoints_request(self, py_db, request): error_msg = 'Breakpoint not validated (reason unknown -- please report as bug).' breakpoints_set.append(pydevd_schema.Breakpoint( - verified=False, line=line, message=error_msg).to_dict()) + verified=False, line=result.translated_line, message=error_msg).to_dict()) else: # Note that the id is made up (the id for pydevd is unique only within a file, so, the # line is used for it). # Also, the id is currently not used afterwards, so, we don't even keep a mapping. breakpoints_set.append(pydevd_schema.Breakpoint( - verified=True, id=self._next_breakpoint_id(), line=line).to_dict()) + verified=True, id=self._next_breakpoint_id(), line=result.translated_line).to_dict()) body = {'breakpoints': breakpoints_set} set_breakpoints_response = pydevd_base_schema.build_response(request, kwargs={'body': body}) @@ -859,7 +815,7 @@ def on_goto_request(self, py_db, request): return None def on_setdebuggerproperty_request(self, py_db, request): - args = request.arguments + args = request.arguments # : :type args: SetDebuggerPropertyArguments if args.ideOS is not None: self.api.set_ide_os(args.ideOS) @@ -891,5 +847,36 @@ def on_setdebuggerproperty_request(self, py_db, request): response = pydevd_base_schema.build_response(request, kwargs={'body': {}}) return NetCommand(CMD_RETURN, 0, response, is_json=True) + def on_setpydevdsourcemap_request(self, py_db, request): + args = request.arguments # : :type args: SetPydevdSourceMapArguments + SourceMappingEntry = self.api.SourceMappingEntry + + path = args.source.path + source_maps = args.pydevdSourceMaps + # : :type source_map: PydevdSourceMap + new_mappings = [ + SourceMappingEntry( + self.api.filename_to_str(path), + source_map['line'], + source_map['endLine'], + source_map['runtimeLine'], + self.api.filename_to_str(source_map['runtimeSource']['path']) + ) for source_map in source_maps + ] + + error_msg = self.api.set_source_mapping(py_db, path, new_mappings) + if error_msg: + response = pydevd_base_schema.build_response( + request, + kwargs={ + 'body': {}, + 'success': False, + 'message': error_msg, + }) + return NetCommand(CMD_RETURN, 0, response, is_json=True) + + response = pydevd_base_schema.build_response(request) + return NetCommand(CMD_RETURN, 0, response, is_json=True) + process_net_command_json = _PyDevJsonCommandProcessor(pydevd_base_schema.from_json).process_net_command_json diff --git a/src/ptvsd/_vendored/pydevd/_pydevd_bundle/pydevd_source_mapping.py b/src/ptvsd/_vendored/pydevd/_pydevd_bundle/pydevd_source_mapping.py new file mode 100644 index 000000000..db4489519 --- /dev/null +++ b/src/ptvsd/_vendored/pydevd/_pydevd_bundle/pydevd_source_mapping.py @@ -0,0 +1,130 @@ +import bisect +from _pydevd_bundle.pydevd_constants import dict_items + + +class SourceMappingEntry(object): + + __slots__ = ['source_filename', 'line', 'end_line', 'runtime_line', 'runtime_source'] + + def __init__(self, source_filename, line, end_line, runtime_line, runtime_source): + assert isinstance(source_filename, str) + assert isinstance(runtime_source, str) + + self.line = int(line) + self.end_line = int(end_line) + self.runtime_line = int(runtime_line) + self.runtime_source = runtime_source + self.source_filename = source_filename + + def contains_line(self, i): + return self.line <= i <= self.end_line + + def contains_runtime_line(self, i): + line_count = self.end_line + self.line + runtime_end_line = self.runtime_line + line_count + return self.runtime_line <= i <= runtime_end_line + + def __str__(self): + return 'SourceMappingEntry(%s)' % ( + ', '.join('%s=%r' % (attr, getattr(self, attr)) for attr in self.__slots__)) + + __repr__ = __str__ + + +class _KeyifyList(object): + + def __init__(self, inner, key): + self.inner = inner + self.key = key + + def __len__(self): + return len(self.inner) + + def __getitem__(self, k): + return self.key(self.inner[k]) + + +class SourceMapping(object): + + def __init__(self): + self._mappings_to_server = {} + self._mappings_to_client = {} + self._cache = {} + + def set_source_mapping(self, source_filename, mapping): + ''' + :param str source_filename: + The filename for the source mapping (bytes on py2 and str on py3). + Note: the source_filename must be already normalized to the server. + + :param list(SourceMappingEntry) mapping: + A list with the source mapping entries to be applied to the given filename. + + :return str: + An error message if it was not possible to set the mapping or an empty string if + everything is ok. + ''' + # Let's first validate if it's ok to apply that mapping. + # File mappings must be 1:N, not M:N (i.e.: if there's a mapping from file1.py to , + # there can be no other mapping from any other file to ). + # This is a limitation to make it easier to remove existing breakpoints when new breakpoints are + # set to a file (so, any file matching that breakpoint can be removed instead of needing to check + # which lines are corresponding to that file). + for map_entry in mapping: + existing_source_filename = self._mappings_to_client.get(map_entry.runtime_source) + if existing_source_filename and existing_source_filename != source_filename: + return 'Cannot apply mapping from %s to %s (it conflicts with mapping: %s to %s)' % ( + source_filename, map_entry.runtime_source, existing_source_filename, map_entry.runtime_source) + + current_mapping = self._mappings_to_server.get(source_filename, []) + for map_entry in current_mapping: + del self._mappings_to_client[map_entry.runtime_source] + + self._mappings_to_server[source_filename] = sorted(mapping, key=lambda entry:entry.line) + + for map_entry in mapping: + self._mappings_to_client[map_entry.runtime_source] = source_filename + + return '' + + def map_to_client(self, filename, lineno): + # Note: the filename must be normalized to the client after this point. + key = (filename, lineno, 'client') + try: + return self._cache[key] + except KeyError: + for source_filename, mapping in dict_items(self._mappings_to_server): + for map_entry in mapping: + if map_entry.runtime_source == filename: + if map_entry.contains_runtime_line(lineno): + return source_filename, map_entry.line + (lineno - map_entry.runtime_line), True + + return filename, lineno, False + + def map_to_server(self, filename, lineno): + # Note: the filename must be already normalized to the server at this point. + changed = False + mappings = self._mappings_to_server.get(filename) + if mappings: + + i = bisect.bisect(_KeyifyList(mappings, lambda entry:entry.line), lineno) + if i >= len(mappings): + i -= 1 + + if i == 0: + entry = mappings[i] + + elif i > 0: + entry = mappings[i - 1] + if not entry.contains_line(lineno): + entry = mappings[i] + if not entry.contains_line(lineno): + entry = None + + if entry is not None: + lineno = entry.runtime_line + (lineno - entry.line) + + filename = entry.runtime_source + changed = True + + return filename, lineno, changed diff --git a/src/ptvsd/_vendored/pydevd/_pydevd_bundle/pydevd_trace_dispatch_regular.py b/src/ptvsd/_vendored/pydevd/_pydevd_bundle/pydevd_trace_dispatch_regular.py index 2e74eb101..0970cc45f 100644 --- a/src/ptvsd/_vendored/pydevd/_pydevd_bundle/pydevd_trace_dispatch_regular.py +++ b/src/ptvsd/_vendored/pydevd/_pydevd_bundle/pydevd_trace_dispatch_regular.py @@ -466,7 +466,6 @@ def __call__(self, frame, event, arg): back_frame_cache_key = (back_frame.f_code.co_firstlineno, back_frame.f_code.co_name, back_frame.f_code.co_filename) cache_skips[back_frame_cache_key] = 1 # if DEBUG: print('skipped: trace_dispatch (filtered out: 1)', frame_cache_key, frame.f_lineno, event, frame.f_code.co_name) - return None if event == 'call' else NO_FTRACE else: # if DEBUG: print('skipped: trace_dispatch (filtered out: 2)', frame_cache_key, frame.f_lineno, event, frame.f_code.co_name) diff --git a/src/ptvsd/_vendored/pydevd/pydevd.py b/src/ptvsd/_vendored/pydevd/pydevd.py index 9f4e9b8ca..f6785b982 100644 --- a/src/ptvsd/_vendored/pydevd/pydevd.py +++ b/src/ptvsd/_vendored/pydevd/pydevd.py @@ -44,13 +44,13 @@ from _pydevd_bundle.pydevd_frame_utils import add_exception_to_frame, remove_exception_from_frame from _pydevd_bundle.pydevd_kill_all_pydevd_threads import kill_all_pydev_threads from _pydevd_bundle.pydevd_net_command_factory_xml import NetCommandFactory -from _pydevd_bundle.pydevd_net_command_factory_json import NetCommandFactoryJson from _pydevd_bundle.pydevd_trace_dispatch import ( trace_dispatch as _trace_dispatch, global_cache_skips, global_cache_frame_skips, fix_top_level_trace_and_get_trace_func) from _pydevd_bundle.pydevd_utils import save_main_module, is_current_thread_main_thread from _pydevd_frame_eval.pydevd_frame_eval_main import ( frame_eval_func, dummy_trace_dispatch) import pydev_ipython # @UnusedImport +from _pydevd_bundle.pydevd_source_mapping import SourceMapping from pydevd_concurrency_analyser.pydevd_concurrency_logger import ThreadingLogger, AsyncioLogger, send_message, cur_time from pydevd_concurrency_analyser.pydevd_thread_wrappers import wrap_threads from pydevd_file_utils import get_abs_path_real_path_and_base_from_frame, NORM_PATHS_AND_BASE_CONTAINER, get_abs_path_real_path_and_base_from_file @@ -363,9 +363,6 @@ def notify_thread_suspended(self, thread_id, stop_reason): yield -#======================================================================================================================= -# PyDB -#======================================================================================================================= class PyDB(object): """ Main debugging class Lots of stuff going on here: @@ -396,7 +393,13 @@ def __init__(self, set_as_global=True): self._cmd_queue = defaultdict(_queue.Queue) # Key is thread id or '*', value is Queue self.suspended_frames_manager = SuspendedFramesManager() self._files_filtering = FilesFiltering() + self.source_mapping = SourceMapping() + + # These are the breakpoints received by the PyDevdAPI. They are meant to store + # the breakpoints in the api -- its actual contents are managed by the api. + self.api_received_breakpoints = {} + # These are the breakpoints meant to be consumed during runtime. self.breakpoints = {} # Set communication protocol diff --git a/src/ptvsd/_vendored/pydevd/pydevd_file_utils.py b/src/ptvsd/_vendored/pydevd/pydevd_file_utils.py index 557f4ec23..f9c145750 100644 --- a/src/ptvsd/_vendored/pydevd/pydevd_file_utils.py +++ b/src/ptvsd/_vendored/pydevd/pydevd_file_utils.py @@ -50,7 +50,6 @@ import json import os.path import sys -import traceback import itertools import ntpath from functools import partial diff --git a/src/ptvsd/_vendored/pydevd/tests_python/debugger_fixtures.py b/src/ptvsd/_vendored/pydevd/tests_python/debugger_fixtures.py index 0ccf1c880..e7ad99a12 100644 --- a/src/ptvsd/_vendored/pydevd/tests_python/debugger_fixtures.py +++ b/src/ptvsd/_vendored/pydevd/tests_python/debugger_fixtures.py @@ -1,3 +1,4 @@ +# coding: utf-8 from contextlib import contextmanager import os import threading @@ -8,6 +9,8 @@ from tests_python.debugger_unittest import get_free_port, overrides, IS_CPYTHON, IS_JYTHON, IS_IRONPYTHON, \ IS_PY3K, CMD_ADD_DJANGO_EXCEPTION_BREAK, CMD_REMOVE_DJANGO_EXCEPTION_BREAK, \ CMD_ADD_EXCEPTION_BREAK +from tests_python.debug_constants import IS_PY2 +from _pydevd_bundle.pydevd_comm_constants import file_system_encoding import sys import time @@ -285,7 +288,7 @@ def add_command_line_args(self, args): @pytest.fixture -def case_setup(): +def case_setup(tmpdir): runner = DebuggerRunnerSimple() @@ -294,13 +297,35 @@ class WriterThread(debugger_unittest.AbstractWriterThread): class CaseSetup(object): + check_non_ascii = False + NON_ASCII_CHARS = u'áéíóú汉字' + @contextmanager def test_file( self, filename, **kwargs ): - WriterThread.TEST_FILE = debugger_unittest._get_debugger_test_file(filename) + import shutil + filename = debugger_unittest._get_debugger_test_file(filename) + if self.check_non_ascii: + basedir = str(tmpdir) + if isinstance(basedir, bytes): + basedir = basedir.decode('utf-8') + if isinstance(filename, bytes): + filename = filename.decode('utf-8') + + new_dir = os.path.join(basedir, self.NON_ASCII_CHARS) + os.makedirs(new_dir) + + new_filename = os.path.join(new_dir, self.NON_ASCII_CHARS + os.path.basename(filename)) + shutil.copyfile(filename, new_filename) + filename = new_filename + + if IS_PY2: + filename = filename.encode(file_system_encoding) + + WriterThread.TEST_FILE = filename for key, value in kwargs.items(): assert hasattr(WriterThread, key) setattr(WriterThread, key, value) diff --git a/src/ptvsd/_vendored/pydevd/tests_python/resources/_debugger_case_source_mapping.py b/src/ptvsd/_vendored/pydevd/tests_python/resources/_debugger_case_source_mapping.py new file mode 100644 index 000000000..d55714868 --- /dev/null +++ b/src/ptvsd/_vendored/pydevd/tests_python/resources/_debugger_case_source_mapping.py @@ -0,0 +1,31 @@ +def full_function(): + # Note that this function is not called, it's there just to make the mapping explicit. + a = 1 # map to cell1, line 2 + b = 2 # map to cell1, line 3 + + c = 3 # map to cell2, line 2 + d = 4 # map to cell2, line 3 + + +def create_code(): + cell1_code = compile(''' # line 1 +a = 1 # line 2 +b = 2 # line 3 +''', '', 'exec') + + cell2_code = compile('''# line 1 +c = 3 # line 2 +d = 4 # line 3 +''', '', 'exec') + + return {'cell1': cell1_code, 'cell2': cell2_code} + + +if __name__ == '__main__': + code = create_code() + exec(code['cell1']) + exec(code['cell1']) + + exec(code['cell2']) + exec(code['cell2']) + print('TEST SUCEEDED') diff --git a/src/ptvsd/_vendored/pydevd/tests_python/test_convert_utilities.py b/src/ptvsd/_vendored/pydevd/tests_python/test_convert_utilities.py index 0134334d5..9e35b4100 100644 --- a/src/ptvsd/_vendored/pydevd/tests_python/test_convert_utilities.py +++ b/src/ptvsd/_vendored/pydevd/tests_python/test_convert_utilities.py @@ -1,7 +1,9 @@ # coding: utf-8 import os.path -from _pydevd_bundle.pydevd_constants import IS_WINDOWS, IS_JYTHON, IS_PY2 +from _pydevd_bundle.pydevd_constants import IS_WINDOWS, IS_PY2 from _pydev_bundle._pydev_filesystem_encoding import getfilesystemencoding +import io +from _pydev_bundle.pydev_log import log_context def test_convert_utilities(tmpdir): @@ -108,6 +110,13 @@ def check(obtained, expected): if IS_WINDOWS: # Check with made-up files + pydevd_file_utils.setup_client_server_paths([('c:\\foo', 'c:\\bar'), ('c:\\foo2', 'c:\\bar2')]) + + stream = io.StringIO() + with log_context(0, stream=stream): + pydevd_file_utils.norm_file_to_server('y:\\only_exists_in_client_not_in_server') + assert r'pydev debugger: unable to find translation for: "y:\only_exists_in_client_not_in_server" in ["c:\foo", "c:\foo2"] (please revise your path mappings).' in stream.getvalue() + # Client and server are on windows. pydevd_file_utils.set_ide_os('WINDOWS') for in_eclipse, in_python in ([ @@ -294,3 +303,47 @@ def test_zip_paths(tmpdir): assert zipfile_path in pydevd_file_utils._ZIP_SEARCH_CACHE, '%s not in %s' % ( zipfile_path, '\n'.join(sorted(pydevd_file_utils._ZIP_SEARCH_CACHE.keys()))) + + +def test_source_mapping(): + + from _pydevd_bundle.pydevd_source_mapping import SourceMapping, SourceMappingEntry + source_mapping = SourceMapping() + mapping = [ + SourceMappingEntry(source_filename='file1.py', line=3, end_line=6, runtime_line=5, runtime_source=''), + SourceMappingEntry(source_filename='file1.py', line=10, end_line=11, runtime_line=1, runtime_source=''), + ] + source_mapping.set_source_mapping('file1.py', mapping) + + # Map to server + assert source_mapping.map_to_server('file1.py', 1) == ('file1.py', 1, False) + assert source_mapping.map_to_server('file1.py', 2) == ('file1.py', 2, False) + + assert source_mapping.map_to_server('file1.py', 3) == ('', 5, True) + assert source_mapping.map_to_server('file1.py', 4) == ('', 6, True) + assert source_mapping.map_to_server('file1.py', 5) == ('', 7, True) + assert source_mapping.map_to_server('file1.py', 6) == ('', 8, True) + + assert source_mapping.map_to_server('file1.py', 7) == ('file1.py', 7, False) + + assert source_mapping.map_to_server('file1.py', 10) == ('', 1, True) + assert source_mapping.map_to_server('file1.py', 11) == ('', 2, True) + + assert source_mapping.map_to_server('file1.py', 12) == ('file1.py', 12, False) + + # Map to client + assert source_mapping.map_to_client('file1.py', 1) == ('file1.py', 1, False) + assert source_mapping.map_to_client('file1.py', 2) == ('file1.py', 2, False) + + assert source_mapping.map_to_client('', 5) == ('file1.py', 3, True) + assert source_mapping.map_to_client('', 6) == ('file1.py', 4, True) + assert source_mapping.map_to_client('', 7) == ('file1.py', 5, True) + assert source_mapping.map_to_client('', 8) == ('file1.py', 6, True) + + assert source_mapping.map_to_client('file1.py', 7) == ('file1.py', 7, False) + + assert source_mapping.map_to_client('', 1) == ('file1.py', 10, True) + assert source_mapping.map_to_client('', 2) == ('file1.py', 11, True) + + assert source_mapping.map_to_client('file1.py', 12) == ('file1.py', 12, False) + diff --git a/src/ptvsd/_vendored/pydevd/tests_python/test_debugger_json.py b/src/ptvsd/_vendored/pydevd/tests_python/test_debugger_json.py index 595b46c74..89f2f30e9 100644 --- a/src/ptvsd/_vendored/pydevd/tests_python/test_debugger_json.py +++ b/src/ptvsd/_vendored/pydevd/tests_python/test_debugger_json.py @@ -14,6 +14,7 @@ import time from os.path import normcase from _pydev_bundle.pydev_localhost import get_socket_name +from _pydevd_bundle.pydevd_comm_constants import file_system_encoding pytest_plugins = [ str('tests_python.debugger_fixtures'), @@ -106,6 +107,10 @@ def write_list_threads(self): return self.wait_for_response(self.write_request(pydevd_schema.ThreadsRequest())) def wait_for_thread_stopped(self, reason='breakpoint', line=None, file=None, name=None): + ''' + :param file: + utf-8 bytes encoded file or unicode + ''' stopped_event = self.wait_for_json_message(StoppedEvent) assert stopped_event.body.reason == reason json_hit = self.get_stack_as_json_hit(stopped_event.body.threadId) @@ -115,7 +120,14 @@ def wait_for_thread_stopped(self, reason='breakpoint', line=None, file=None, nam line = [line] assert found_line in line, 'Expect to break at line: %s. Found: %s' % (line, found_line) if file is not None: - assert json_hit.stack_trace_response.body.stackFrames[0]['source']['path'].endswith(file) + path = json_hit.stack_trace_response.body.stackFrames[0]['source']['path'] + if IS_PY2: + if isinstance(file, bytes): + file = file.decode('utf-8') + if isinstance(path, bytes): + path = path.decode('utf-8') + + assert path.endswith(file) if name is not None: assert json_hit.stack_trace_response.body.stackFrames[0]['name'] == name return json_hit @@ -145,6 +157,10 @@ def write_set_breakpoints( if filename is None: filename = self.writer.get_main_filename() + if isinstance(filename, bytes): + filename = filename.decode(file_system_encoding) # file is in the filesystem encoding but protocol needs it in utf-8 + filename = filename.encode('utf-8') + source = pydevd_schema.Source(path=filename) breakpoints = [] for line in lines: @@ -360,6 +376,16 @@ def write_set_debugger_property(self, dont_trace_start_patterns, dont_trace_end_ assert response.success return response + def write_set_pydevd_source_map(self, source, pydevd_source_maps, success=True): + dbg_request = self.write_request( + pydevd_schema.SetPydevdSourceMapRequest(pydevd_schema.SetPydevdSourceMapArguments( + source=source, + pydevdSourceMaps=pydevd_source_maps, + ))) + response = self.wait_for_response(dbg_request) + assert response.success == success + return response + def test_case_json_logpoints(case_setup): with case_setup.test_file('_debugger_case_change_breaks.py') as writer: @@ -536,19 +562,19 @@ def test_case_path_translation_not_skipped(case_setup): if isinstance(sys_folder, (list, tuple)): sys_folder = next(iter(sys_folder)) - def get_environ(writer): - env = os.environ.copy() + with case_setup.test_file('my_code/my_code.py') as writer: + json_facade = JsonFacade(writer) + # We need to set up path mapping to enable source references. my_code = debugger_unittest._get_debugger_test_file('my_code') - env["PATHS_FROM_ECLIPSE_TO_PYTHON"] = json.dumps([ - (sys_folder, my_code), - ]) - env['PYDEVD_FILTER_LIBRARIES'] = '1' - return env - - with case_setup.test_file('my_code/my_code.py', get_environ=get_environ) as writer: - json_facade = JsonFacade(writer) + json_facade.write_launch( + debugOptions=['DebugStdLib'], + pathMappings=[{ + 'localRoot': sys_folder, + 'remoteRoot': my_code, + }] + ) bp_line = writer.get_line_index_with_content('break here') json_facade.write_set_breakpoints( @@ -1846,6 +1872,92 @@ def test_set_debugger_property(case_setup, dbg_property): writer.finished_ok = True +def test_source_mapping_errors(case_setup): + from _pydevd_bundle._debug_adapter.pydevd_schema import Source + from _pydevd_bundle._debug_adapter.pydevd_schema import PydevdSourceMap + + with case_setup.test_file('_debugger_case_source_mapping.py') as writer: + json_facade = JsonFacade(writer) + + map_to_cell_1_line2 = writer.get_line_index_with_content('map to cell1, line 2') + map_to_cell_2_line2 = writer.get_line_index_with_content('map to cell2, line 2') + + cell1_map = PydevdSourceMap(map_to_cell_1_line2, map_to_cell_1_line2 + 1, Source(path=''), 2) + cell2_map = PydevdSourceMap(map_to_cell_2_line2, map_to_cell_2_line2 + 1, Source(path=''), 2) + pydevd_source_maps = [ + cell1_map, cell2_map + ] + + json_facade.write_set_pydevd_source_map( + Source(path=writer.TEST_FILE), + pydevd_source_maps=pydevd_source_maps, + ) + # This will fail because file mappings must be 1:N, not M:N (i.e.: if there's a mapping from file1.py to , + # there can be no other mapping from any other file to ). + # This is a limitation to make it easier to remove existing breakpoints when new breakpoints are + # set to a file (so, any file matching that breakpoint can be removed instead of needing to check + # which lines are corresponding to that file). + json_facade.write_set_pydevd_source_map( + Source(path=os.path.join(os.path.dirname(writer.TEST_FILE), 'foo.py')), + pydevd_source_maps=pydevd_source_maps, + success=False, + ) + json_facade.write_make_initial_run() + + writer.finished_ok = True + + +def test_source_mapping(case_setup): + from _pydevd_bundle._debug_adapter.pydevd_schema import Source + from _pydevd_bundle._debug_adapter.pydevd_schema import PydevdSourceMap + + case_setup.check_non_ascii = True + + with case_setup.test_file('_debugger_case_source_mapping.py') as writer: + json_facade = JsonFacade(writer) + + json_facade.write_launch( + debugOptions=['DebugStdLib'], + ) + + map_to_cell_1_line2 = writer.get_line_index_with_content('map to cell1, line 2') + map_to_cell_2_line2 = writer.get_line_index_with_content('map to cell2, line 2') + + cell1_map = PydevdSourceMap(map_to_cell_1_line2, map_to_cell_1_line2 + 1, Source(path=''), 2) + cell2_map = PydevdSourceMap(map_to_cell_2_line2, map_to_cell_2_line2 + 1, Source(path=''), 2) + pydevd_source_maps = [ + cell1_map, cell2_map, cell2_map, # The one repeated should be ignored. + ] + + # Set breakpoints before setting the source map (check that we reapply them). + json_facade.write_set_breakpoints(map_to_cell_1_line2) + + test_file = writer.TEST_FILE + if isinstance(test_file, bytes): + # file is in the filesystem encoding (needed for launch) but protocol needs it in utf-8 + test_file = test_file.decode(file_system_encoding) + test_file = test_file.encode('utf-8') + + json_facade.write_set_pydevd_source_map( + Source(path=test_file), + pydevd_source_maps=pydevd_source_maps, + ) + + json_facade.write_make_initial_run() + + json_facade.wait_for_thread_stopped(line=map_to_cell_1_line2, file=os.path.basename(test_file)) + # Check that we no longer stop at the cell1 breakpoint (its mapping should be removed when + # the new one is added and we should only stop at cell2). + json_facade.write_set_breakpoints(map_to_cell_2_line2) + json_facade.write_continue() + + json_facade.wait_for_thread_stopped(line=map_to_cell_2_line2, file=os.path.basename(test_file)) + json_facade.write_set_breakpoints([]) # Clears breakpoints + json_facade.write_continue(wait_for_response=False) + + writer.finished_ok = True + + def test_wait_for_attach(case_setup_remote_attach_to): host_port = get_socket_name(close=True) @@ -1930,36 +2042,40 @@ def check_process_event(json_facade, start_method): @pytest.mark.skipif(IS_JYTHON, reason='Flaky on Jython.') def test_path_translation_and_source_reference(case_setup): + translated_dir_not_ascii = u'áéíóú汉字' + + if IS_PY2: + translated_dir_not_ascii = translated_dir_not_ascii.encode(file_system_encoding) + def get_file_in_client(writer): # Instead of using: test_python/_debugger_case_path_translation.py # we'll set the breakpoints at foo/_debugger_case_path_translation.py file_in_client = os.path.dirname(os.path.dirname(writer.TEST_FILE)) - return os.path.join(os.path.dirname(file_in_client), 'foo', '_debugger_case_path_translation.py') + return os.path.join(os.path.dirname(file_in_client), translated_dir_not_ascii, '_debugger_case_path_translation.py') def get_environ(writer): env = os.environ.copy() env["PYTHONIOENCODING"] = 'utf-8' - - assert writer.TEST_FILE.endswith('_debugger_case_path_translation.py') - env["PATHS_FROM_ECLIPSE_TO_PYTHON"] = json.dumps([ - ( - os.path.dirname(get_file_in_client(writer)), - os.path.dirname(writer.TEST_FILE) - ) - ]) return env with case_setup.test_file('_debugger_case_path_translation.py', get_environ=get_environ) as writer: file_in_client = get_file_in_client(writer) assert 'tests_python' not in file_in_client - assert 'foo' in file_in_client + assert translated_dir_not_ascii in file_in_client json_facade = JsonFacade(writer) bp_line = writer.get_line_index_with_content('break here') + assert writer.TEST_FILE.endswith('_debugger_case_path_translation.py') + local_root = os.path.dirname(get_file_in_client(writer)) + if IS_PY2: + local_root = local_root.decode(file_system_encoding).encode('utf-8') + json_facade.write_launch(pathMappings=[{ + 'localRoot': local_root, + 'remoteRoot': os.path.dirname(writer.TEST_FILE), + }]) json_facade.write_set_breakpoints(bp_line, filename=file_in_client) - json_facade.write_make_initial_run() json_hit = json_facade.wait_for_thread_stopped() @@ -1978,7 +2094,16 @@ def get_environ(writer): stack_trace_response_body = stack_trace_response.body stack_frame = stack_trace_response_body.stackFrames[0] assert stack_frame['name'] == '__main__.call_this : %s' % (bp_line,) - assert stack_frame['source']['path'] == file_in_client + + path = stack_frame['source']['path'] + file_in_client_unicode = file_in_client + if IS_PY2: + if isinstance(path, bytes): + path = path.decode('utf-8') + if isinstance(file_in_client_unicode, bytes): + file_in_client_unicode = file_in_client_unicode.decode(file_system_encoding) + + assert path == file_in_client_unicode source_reference = stack_frame['source']['sourceReference'] assert source_reference == 0 # When it's translated the source reference must be == 0 @@ -2002,18 +2127,16 @@ def get_environ(writer): @pytest.mark.skipif(IS_JYTHON, reason='Flaky on Jython.') def test_source_reference_no_file(case_setup, tmpdir): - def get_environ(writer): - env = os.environ.copy() - # We need to set up path mapping to enable source references. - env["PATHS_FROM_ECLIPSE_TO_PYTHON"] = json.dumps([ - (os.path.dirname(writer.TEST_FILE), os.path.dirname(writer.TEST_FILE)) - ]) - return env - - with case_setup.test_file('_debugger_case_source_reference.py', get_environ=get_environ) as writer: + with case_setup.test_file('_debugger_case_source_reference.py') as writer: json_facade = JsonFacade(writer) - json_facade.write_launch(debugOptions=['DebugStdLib']) + json_facade.write_launch( + debugOptions=['DebugStdLib'], + pathMappings=[{ + 'localRoot': os.path.dirname(writer.TEST_FILE), + 'remoteRoot': os.path.dirname(writer.TEST_FILE), + }]) + writer.write_add_breakpoint(writer.get_line_index_with_content('breakpoint')) json_facade.write_make_initial_run() diff --git a/src/ptvsd/_vendored/pydevd/tests_python/test_utilities.py b/src/ptvsd/_vendored/pydevd/tests_python/test_utilities.py index a782548ef..6c5a59845 100644 --- a/src/ptvsd/_vendored/pydevd/tests_python/test_utilities.py +++ b/src/ptvsd/_vendored/pydevd/tests_python/test_utilities.py @@ -150,3 +150,10 @@ def test_pydevd_log(): assert 'foo\n' in stream.getvalue() assert 'raise RuntimeError()' in stream.getvalue() + + stream = io.StringIO() + with log_context(0, stream=stream): + pydev_log.error_once('always %s %s', 1) + + # Even if there's an error in the formatting, don't fail, just print the message and args. + assert stream.getvalue() == 'always %s %s - (1,)\n' diff --git a/src/ptvsd/wrapper.py b/src/ptvsd/wrapper.py index 6e75211d0..fed7c30e0 100644 --- a/src/ptvsd/wrapper.py +++ b/src/ptvsd/wrapper.py @@ -1230,6 +1230,9 @@ def on_exceptionInfo(self, request, args): def on_completions(self, request, args): self._forward_request_to_pydevd(request, args) + def on_setPydevdSourceMap(self, request, args): + self._forward_request_to_pydevd(request, args) + # Custom ptvsd message def on_ptvsd_systemInfo(self, request, args): try: diff --git a/tests/func/test_source_mapping.py b/tests/func/test_source_mapping.py new file mode 100644 index 000000000..b08c1a9d0 --- /dev/null +++ b/tests/func/test_source_mapping.py @@ -0,0 +1,107 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See LICENSE in the project root +# for license information. + +from __future__ import print_function, with_statement, absolute_import + +from tests.helpers.pattern import Path +from tests.helpers.session import DebugSession +from tests.helpers import get_marked_line_numbers + + +def test_with_path_mappings(pyfile, tmpdir, run_as, start_method): + + @pyfile + def code_to_debug(): + from dbgimporter import import_and_enable_debugger + import_and_enable_debugger() + + def full_function(): + # Note that this function is not called, it's there just to make the mapping explicit. + print('cell1 line 2') # @map_to_cell1_line_2 + print('cell1 line 3') # @map_to_cell1_line_3 + + print('cell2 line 2') # @map_to_cell2_line_2 + print('cell2 line 3') # @map_to_cell2_line_3 + + def strip_lines(s): + return '\n'.join([line.strip() for line in s.splitlines()]) + + def create_code(): + cell1_code = compile(strip_lines(''' # line 1 + a = 1 # line 2 + b = 2 # line 3 + '''), '', 'exec') + + cell2_code = compile(strip_lines('''# line 1 + c = 3 # line 2 + d = 4 # line 3 + '''), '', 'exec') + + return {'cell1': cell1_code, 'cell2': cell2_code} + + code = create_code() + exec(code['cell1']) + exec(code['cell1']) + + exec(code['cell2']) + exec(code['cell2']) + print('ok') + + with DebugSession() as session: + session.initialize( + target=(run_as, code_to_debug), + start_method=start_method, + ) + + marked_line_numbers = get_marked_line_numbers(code_to_debug) + map_to_cell_1_line2 = marked_line_numbers['map_to_cell1_line_2'] + map_to_cell_2_line2 = marked_line_numbers['map_to_cell2_line_2'] + + # Set breakpoints first and the map afterwards to make sure that it's reapplied. + session.set_breakpoints(code_to_debug, [map_to_cell_1_line2]) + + session.send_request('setPydevdSourceMap', arguments={ + 'source': {'path': code_to_debug}, + 'pydevdSourceMaps': [ + { + 'line': map_to_cell_1_line2, + 'endLine': map_to_cell_1_line2 + 1, + 'runtimeSource': {'path': ''}, + 'runtimeLine': 2, + }, + { + 'line': map_to_cell_2_line2, + 'endLine': map_to_cell_2_line2 + 1, + 'runtimeSource': {'path': ''}, + 'runtimeLine': 2, + }, + ], + }).wait_for_response() + + session.start_debugging() + hit = session.wait_for_thread_stopped('breakpoint') + + frames = hit.stacktrace.body['stackFrames'] + assert frames[0]['source']['path'] == Path(code_to_debug) + + session.set_breakpoints(code_to_debug, [map_to_cell_2_line2]) + session.send_request('continue').wait_for_response() + + hit = session.wait_for_thread_stopped('breakpoint') + + # Remove the cell2 mapping so that it doesn't stop again. + session.send_request('setPydevdSourceMap', arguments={ + 'source': {'path': code_to_debug}, + 'pydevdSourceMaps': [ + { + 'line': map_to_cell_1_line2, + 'endLine': map_to_cell_1_line2 + 1, + 'runtimeSource': {'path': ''}, + 'runtimeLine': 2, + }, + ], + }).wait_for_response() + + session.send_request('continue').wait_for_response(freeze=False) + session.wait_for_exit()