Commit 5f531449 authored by Robert Bradshaw's avatar Robert Bradshaw

Undo EOL whitespace additions.

parent c5e16a3f
...@@ -20,7 +20,7 @@ import Code ...@@ -20,7 +20,7 @@ import Code
import Errors import Errors
# Do not import Parsing here, import it when needed, because Parsing imports # Do not import Parsing here, import it when needed, because Parsing imports
# Nodes, which globally needs debug command line options initialized to set a # Nodes, which globally needs debug command line options initialized to set a
# conditional metaclass. These options are processed by CmdLine called from # conditional metaclass. These options are processed by CmdLine called from
# main() in this file. # main() in this file.
# import Parsing # import Parsing
import Version import Version
...@@ -72,7 +72,7 @@ class Context(object): ...@@ -72,7 +72,7 @@ class Context(object):
# include_directories [string] # include_directories [string]
# future_directives [object] # future_directives [object]
# language_level int currently 2 or 3 for Python 2/3 # language_level int currently 2 or 3 for Python 2/3
def __init__(self, include_directories, compiler_directives, cpp=False, language_level=2): def __init__(self, include_directories, compiler_directives, cpp=False, language_level=2):
import Builtin, CythonScope import Builtin, CythonScope
self.modules = {"__builtin__" : Builtin.builtin_scope} self.modules = {"__builtin__" : Builtin.builtin_scope}
...@@ -89,7 +89,7 @@ class Context(object): ...@@ -89,7 +89,7 @@ class Context(object):
self.include_directories = include_directories + [standard_include_path] self.include_directories = include_directories + [standard_include_path]
self.set_language_level(language_level) self.set_language_level(language_level)
self.gdb_debug_outputwriter = None self.gdb_debug_outputwriter = None
def set_language_level(self, level): def set_language_level(self, level):
...@@ -124,12 +124,12 @@ class Context(object): ...@@ -124,12 +124,12 @@ class Context(object):
else: else:
_check_c_declarations = check_c_declarations _check_c_declarations = check_c_declarations
_specific_post_parse = None _specific_post_parse = None
if py and not pxd: if py and not pxd:
_align_function_definitions = AlignFunctionDefinitions(self) _align_function_definitions = AlignFunctionDefinitions(self)
else: else:
_align_function_definitions = None _align_function_definitions = None
return [ return [
NormalizeTree(self), NormalizeTree(self),
PostParse(self), PostParse(self),
...@@ -194,7 +194,7 @@ class Context(object): ...@@ -194,7 +194,7 @@ class Context(object):
debug_transform = [DebugTransform(self, options, result)] debug_transform = [DebugTransform(self, options, result)]
else: else:
debug_transform = [] debug_transform = []
return list(itertools.chain( return list(itertools.chain(
[create_parse(self)], [create_parse(self)],
self.create_pipeline(pxd=False, py=py), self.create_pipeline(pxd=False, py=py),
...@@ -218,7 +218,7 @@ class Context(object): ...@@ -218,7 +218,7 @@ class Context(object):
return [parse_pxd] + self.create_pipeline(pxd=True) + [ return [parse_pxd] + self.create_pipeline(pxd=True) + [
ExtractPxdCode(self), ExtractPxdCode(self),
] ]
def create_py_pipeline(self, options, result): def create_py_pipeline(self, options, result):
return self.create_pyx_pipeline(options, result, py=True) return self.create_pyx_pipeline(options, result, py=True)
...@@ -227,7 +227,7 @@ class Context(object): ...@@ -227,7 +227,7 @@ class Context(object):
pipeline = self.create_pxd_pipeline(scope, module_name) pipeline = self.create_pxd_pipeline(scope, module_name)
result = self.run_pipeline(pipeline, source_desc) result = self.run_pipeline(pipeline, source_desc)
return result return result
def nonfatal_error(self, exc): def nonfatal_error(self, exc):
return Errors.report_error(exc) return Errors.report_error(exc)
...@@ -257,7 +257,7 @@ class Context(object): ...@@ -257,7 +257,7 @@ class Context(object):
error = err error = err
return (error, data) return (error, data)
def find_module(self, module_name, def find_module(self, module_name,
relative_to = None, pos = None, need_pxd = 1): relative_to = None, pos = None, need_pxd = 1):
# Finds and returns the module scope corresponding to # Finds and returns the module scope corresponding to
# the given relative or absolute module name. If this # the given relative or absolute module name. If this
...@@ -327,7 +327,7 @@ class Context(object): ...@@ -327,7 +327,7 @@ class Context(object):
except CompileError: except CompileError:
pass pass
return scope return scope
def find_pxd_file(self, qualified_name, pos): def find_pxd_file(self, qualified_name, pos):
# Search include path for the .pxd file corresponding to the # Search include path for the .pxd file corresponding to the
# given fully-qualified module name. # given fully-qualified module name.
...@@ -362,7 +362,7 @@ class Context(object): ...@@ -362,7 +362,7 @@ class Context(object):
# Search include path for the .pyx file corresponding to the # Search include path for the .pyx file corresponding to the
# given fully-qualified module name, as for find_pxd_file(). # given fully-qualified module name, as for find_pxd_file().
return self.search_include_directories(qualified_name, ".pyx", pos) return self.search_include_directories(qualified_name, ".pyx", pos)
def find_include_file(self, filename, pos): def find_include_file(self, filename, pos):
# Search list of include directories for filename. # Search list of include directories for filename.
# Reports an error and returns None if not found. # Reports an error and returns None if not found.
...@@ -371,7 +371,7 @@ class Context(object): ...@@ -371,7 +371,7 @@ class Context(object):
if not path: if not path:
error(pos, "'%s' not found" % filename) error(pos, "'%s' not found" % filename)
return path return path
def search_include_directories(self, qualified_name, suffix, pos, def search_include_directories(self, qualified_name, suffix, pos,
include=False): include=False):
# Search the list of include directories for the given # Search the list of include directories for the given
...@@ -452,15 +452,15 @@ class Context(object): ...@@ -452,15 +452,15 @@ class Context(object):
if dep_path and Utils.file_newer_than(dep_path, c_time): if dep_path and Utils.file_newer_than(dep_path, c_time):
return 1 return 1
return 0 return 0
def find_cimported_module_names(self, source_path): def find_cimported_module_names(self, source_path):
return [ name for kind, name in self.read_dependency_file(source_path) return [ name for kind, name in self.read_dependency_file(source_path)
if kind == "cimport" ] if kind == "cimport" ]
def is_package_dir(self, dir_path): def is_package_dir(self, dir_path):
# Return true if the given directory is a package directory. # Return true if the given directory is a package directory.
for filename in ("__init__.py", for filename in ("__init__.py",
"__init__.pyx", "__init__.pyx",
"__init__.pxd"): "__init__.pxd"):
path = os.path.join(dir_path, filename) path = os.path.join(dir_path, filename)
if Utils.path_exists(path): if Utils.path_exists(path):
...@@ -486,7 +486,7 @@ class Context(object): ...@@ -486,7 +486,7 @@ class Context(object):
# Find a top-level module, creating a new one if needed. # Find a top-level module, creating a new one if needed.
scope = self.lookup_submodule(name) scope = self.lookup_submodule(name)
if not scope: if not scope:
scope = ModuleScope(name, scope = ModuleScope(name,
parent_module = None, context = self) parent_module = None, context = self)
self.modules[name] = scope self.modules[name] = scope
return scope return scope
...@@ -606,7 +606,7 @@ def run_pipeline(source, options, full_module_name = None): ...@@ -606,7 +606,7 @@ def run_pipeline(source, options, full_module_name = None):
# Set up result object # Set up result object
result = create_default_resultobj(source, options) result = create_default_resultobj(source, options)
# Get pipeline # Get pipeline
if source_ext.lower() == '.py': if source_ext.lower() == '.py':
pipeline = context.create_py_pipeline(options, result) pipeline = context.create_py_pipeline(options, result)
...@@ -617,7 +617,7 @@ def run_pipeline(source, options, full_module_name = None): ...@@ -617,7 +617,7 @@ def run_pipeline(source, options, full_module_name = None):
err, enddata = context.run_pipeline(pipeline, source) err, enddata = context.run_pipeline(pipeline, source)
context.teardown_errors(err, options, result) context.teardown_errors(err, options, result)
return result return result
#------------------------------------------------------------------------ #------------------------------------------------------------------------
# #
...@@ -638,7 +638,7 @@ class CompilationSource(object): ...@@ -638,7 +638,7 @@ class CompilationSource(object):
class CompilationOptions(object): class CompilationOptions(object):
""" """
Options to the Cython compiler: Options to the Cython compiler:
show_version boolean Display version number show_version boolean Display version number
use_listing_file boolean Generate a .lis file use_listing_file boolean Generate a .lis file
errors_to_stderr boolean Echo errors to stderr when using .lis errors_to_stderr boolean Echo errors to stderr when using .lis
...@@ -653,10 +653,10 @@ class CompilationOptions(object): ...@@ -653,10 +653,10 @@ class CompilationOptions(object):
compiler_directives dict Overrides for pragma options (see Options.py) compiler_directives dict Overrides for pragma options (see Options.py)
evaluate_tree_assertions boolean Test support: evaluate parse tree assertions evaluate_tree_assertions boolean Test support: evaluate parse tree assertions
language_level integer The Python language level: 2 or 3 language_level integer The Python language level: 2 or 3
cplus boolean Compile as c++ code cplus boolean Compile as c++ code
""" """
def __init__(self, defaults = None, **kw): def __init__(self, defaults = None, **kw):
self.include_path = [] self.include_path = []
if defaults: if defaults:
...@@ -675,7 +675,7 @@ class CompilationOptions(object): ...@@ -675,7 +675,7 @@ class CompilationOptions(object):
class CompilationResult(object): class CompilationResult(object):
""" """
Results from the Cython compiler: Results from the Cython compiler:
c_file string or None The generated C source file c_file string or None The generated C source file
h_file string or None The generated C header file h_file string or None The generated C header file
i_file string or None The generated .pxi file i_file string or None The generated .pxi file
...@@ -686,7 +686,7 @@ class CompilationResult(object): ...@@ -686,7 +686,7 @@ class CompilationResult(object):
num_errors integer Number of compilation errors num_errors integer Number of compilation errors
compilation_source CompilationSource compilation_source CompilationSource
""" """
def __init__(self): def __init__(self):
self.c_file = None self.c_file = None
self.h_file = None self.h_file = None
...@@ -703,10 +703,10 @@ class CompilationResultSet(dict): ...@@ -703,10 +703,10 @@ class CompilationResultSet(dict):
Results from compiling multiple Pyrex source files. A mapping Results from compiling multiple Pyrex source files. A mapping
from source file paths to CompilationResult instances. Also from source file paths to CompilationResult instances. Also
has the following attributes: has the following attributes:
num_errors integer Total number of compilation errors num_errors integer Total number of compilation errors
""" """
num_errors = 0 num_errors = 0
def add(self, source, result): def add(self, source, result):
...@@ -717,7 +717,7 @@ class CompilationResultSet(dict): ...@@ -717,7 +717,7 @@ class CompilationResultSet(dict):
def compile_single(source, options, full_module_name = None): def compile_single(source, options, full_module_name = None):
""" """
compile_single(source, options, full_module_name) compile_single(source, options, full_module_name)
Compile the given Pyrex implementation file and return a CompilationResult. Compile the given Pyrex implementation file and return a CompilationResult.
Always compiles a single file; does not perform timestamp checking or Always compiles a single file; does not perform timestamp checking or
recursion. recursion.
...@@ -728,7 +728,7 @@ def compile_single(source, options, full_module_name = None): ...@@ -728,7 +728,7 @@ def compile_single(source, options, full_module_name = None):
def compile_multiple(sources, options): def compile_multiple(sources, options):
""" """
compile_multiple(sources, options) compile_multiple(sources, options)
Compiles the given sequence of Pyrex implementation files and returns Compiles the given sequence of Pyrex implementation files and returns
a CompilationResultSet. Performs timestamp checking and/or recursion a CompilationResultSet. Performs timestamp checking and/or recursion
if these are specified in the options. if these are specified in the options.
...@@ -766,7 +766,7 @@ def compile_multiple(sources, options): ...@@ -766,7 +766,7 @@ def compile_multiple(sources, options):
def compile(source, options = None, full_module_name = None, **kwds): def compile(source, options = None, full_module_name = None, **kwds):
""" """
compile(source [, options], [, <option> = <value>]...) compile(source [, options], [, <option> = <value>]...)
Compile one or more Pyrex implementation files, with optional timestamp Compile one or more Pyrex implementation files, with optional timestamp
checking and recursing on dependecies. The source argument may be a string checking and recursing on dependecies. The source argument may be a string
or a sequence of strings If it is a string and no recursion or timestamp or a sequence of strings If it is a string and no recursion or timestamp
......
...@@ -40,24 +40,24 @@ class NameNodeCollector(TreeVisitor): ...@@ -40,24 +40,24 @@ class NameNodeCollector(TreeVisitor):
class SkipDeclarations(object): class SkipDeclarations(object):
""" """
Variable and function declarations can often have a deep tree structure, Variable and function declarations can often have a deep tree structure,
and yet most transformations don't need to descend to this depth. and yet most transformations don't need to descend to this depth.
Declaration nodes are removed after AnalyseDeclarationsTransform, so there Declaration nodes are removed after AnalyseDeclarationsTransform, so there
is no need to use this for transformations after that point. is no need to use this for transformations after that point.
""" """
def visit_CTypeDefNode(self, node): def visit_CTypeDefNode(self, node):
return node return node
def visit_CVarDefNode(self, node): def visit_CVarDefNode(self, node):
return node return node
def visit_CDeclaratorNode(self, node): def visit_CDeclaratorNode(self, node):
return node return node
def visit_CBaseTypeNode(self, node): def visit_CBaseTypeNode(self, node):
return node return node
def visit_CEnumDefNode(self, node): def visit_CEnumDefNode(self, node):
return node return node
...@@ -116,7 +116,7 @@ class NormalizeTree(CythonTransform): ...@@ -116,7 +116,7 @@ class NormalizeTree(CythonTransform):
def visit_ParallelAssignmentNode(self, node): def visit_ParallelAssignmentNode(self, node):
return self.visit_StatNode(node, True) return self.visit_StatNode(node, True)
def visit_CEnumDefNode(self, node): def visit_CEnumDefNode(self, node):
return self.visit_StatNode(node, True) return self.visit_StatNode(node, True)
...@@ -131,7 +131,7 @@ class NormalizeTree(CythonTransform): ...@@ -131,7 +131,7 @@ class NormalizeTree(CythonTransform):
return [] return []
def visit_CDeclaratorNode(self, node): def visit_CDeclaratorNode(self, node):
return node return node
class PostParseError(CompileError): pass class PostParseError(CompileError): pass
...@@ -151,7 +151,7 @@ class PostParse(ScopeTrackingTransform): ...@@ -151,7 +151,7 @@ class PostParse(ScopeTrackingTransform):
- Default values to cdef assignments are turned into single - Default values to cdef assignments are turned into single
assignments following the declaration (everywhere but in class assignments following the declaration (everywhere but in class
bodies, where they raise a compile error) bodies, where they raise a compile error)
- Interpret some node structures into Python runtime values. - Interpret some node structures into Python runtime values.
Some nodes take compile-time arguments (currently: Some nodes take compile-time arguments (currently:
TemplatedTypeNode[args] and __cythonbufferdefaults__ = {args}), TemplatedTypeNode[args] and __cythonbufferdefaults__ = {args}),
...@@ -279,7 +279,7 @@ class PostParse(ScopeTrackingTransform): ...@@ -279,7 +279,7 @@ class PostParse(ScopeTrackingTransform):
lhs_list = expr_list[:-1] lhs_list = expr_list[:-1]
rhs = expr_list[-1] rhs = expr_list[-1]
if len(lhs_list) == 1: if len(lhs_list) == 1:
node = Nodes.SingleAssignmentNode(rhs.pos, node = Nodes.SingleAssignmentNode(rhs.pos,
lhs = lhs_list[0], rhs = rhs) lhs = lhs_list[0], rhs = rhs)
else: else:
node = Nodes.CascadedAssignmentNode(rhs.pos, node = Nodes.CascadedAssignmentNode(rhs.pos,
...@@ -488,7 +488,7 @@ class PxdPostParse(CythonTransform, SkipDeclarations): ...@@ -488,7 +488,7 @@ class PxdPostParse(CythonTransform, SkipDeclarations):
- "def" functions are let through only if they fill the - "def" functions are let through only if they fill the
getbuffer/releasebuffer slots getbuffer/releasebuffer slots
- cdef functions are let through only if they are on the - cdef functions are let through only if they are on the
top level and are declared "inline" top level and are declared "inline"
""" """
...@@ -514,7 +514,7 @@ class PxdPostParse(CythonTransform, SkipDeclarations): ...@@ -514,7 +514,7 @@ class PxdPostParse(CythonTransform, SkipDeclarations):
if (isinstance(node, Nodes.DefNode) and self.scope_type == 'cclass' if (isinstance(node, Nodes.DefNode) and self.scope_type == 'cclass'
and node.name in ('__getbuffer__', '__releasebuffer__')): and node.name in ('__getbuffer__', '__releasebuffer__')):
err = None # allow these slots err = None # allow these slots
if isinstance(node, Nodes.CFuncDefNode): if isinstance(node, Nodes.CFuncDefNode):
if u'inline' in node.modifiers and self.scope_type == 'pxd': if u'inline' in node.modifiers and self.scope_type == 'pxd':
node.inline_in_pxd = True node.inline_in_pxd = True
...@@ -532,7 +532,7 @@ class PxdPostParse(CythonTransform, SkipDeclarations): ...@@ -532,7 +532,7 @@ class PxdPostParse(CythonTransform, SkipDeclarations):
return None return None
else: else:
return node return node
class InterpretCompilerDirectives(CythonTransform, SkipDeclarations): class InterpretCompilerDirectives(CythonTransform, SkipDeclarations):
""" """
After parsing, directives can be stored in a number of places: After parsing, directives can be stored in a number of places:
...@@ -561,14 +561,14 @@ class InterpretCompilerDirectives(CythonTransform, SkipDeclarations): ...@@ -561,14 +561,14 @@ class InterpretCompilerDirectives(CythonTransform, SkipDeclarations):
""" """
unop_method_nodes = { unop_method_nodes = {
'typeof': ExprNodes.TypeofNode, 'typeof': ExprNodes.TypeofNode,
'operator.address': ExprNodes.AmpersandNode, 'operator.address': ExprNodes.AmpersandNode,
'operator.dereference': ExprNodes.DereferenceNode, 'operator.dereference': ExprNodes.DereferenceNode,
'operator.preincrement' : ExprNodes.inc_dec_constructor(True, '++'), 'operator.preincrement' : ExprNodes.inc_dec_constructor(True, '++'),
'operator.predecrement' : ExprNodes.inc_dec_constructor(True, '--'), 'operator.predecrement' : ExprNodes.inc_dec_constructor(True, '--'),
'operator.postincrement': ExprNodes.inc_dec_constructor(False, '++'), 'operator.postincrement': ExprNodes.inc_dec_constructor(False, '++'),
'operator.postdecrement': ExprNodes.inc_dec_constructor(False, '--'), 'operator.postdecrement': ExprNodes.inc_dec_constructor(False, '--'),
# For backwards compatability. # For backwards compatability.
'address': ExprNodes.AmpersandNode, 'address': ExprNodes.AmpersandNode,
} }
...@@ -576,7 +576,7 @@ class InterpretCompilerDirectives(CythonTransform, SkipDeclarations): ...@@ -576,7 +576,7 @@ class InterpretCompilerDirectives(CythonTransform, SkipDeclarations):
binop_method_nodes = { binop_method_nodes = {
'operator.comma' : ExprNodes.c_binop_constructor(','), 'operator.comma' : ExprNodes.c_binop_constructor(','),
} }
special_methods = cython.set(['declare', 'union', 'struct', 'typedef', 'sizeof', special_methods = cython.set(['declare', 'union', 'struct', 'typedef', 'sizeof',
'cast', 'pointer', 'compiled', 'NULL']) 'cast', 'pointer', 'compiled', 'NULL'])
special_methods.update(unop_method_nodes.keys()) special_methods.update(unop_method_nodes.keys())
...@@ -597,7 +597,7 @@ class InterpretCompilerDirectives(CythonTransform, SkipDeclarations): ...@@ -597,7 +597,7 @@ class InterpretCompilerDirectives(CythonTransform, SkipDeclarations):
return False return False
else: else:
return True return True
# Set up processing and handle the cython: comments. # Set up processing and handle the cython: comments.
def visit_ModuleNode(self, node): def visit_ModuleNode(self, node):
for key, value in node.directive_comments.items(): for key, value in node.directive_comments.items():
...@@ -633,7 +633,7 @@ class InterpretCompilerDirectives(CythonTransform, SkipDeclarations): ...@@ -633,7 +633,7 @@ class InterpretCompilerDirectives(CythonTransform, SkipDeclarations):
# want to leave the cimport node sitting in the tree # want to leave the cimport node sitting in the tree
return None return None
return node return node
def visit_FromCImportStatNode(self, node): def visit_FromCImportStatNode(self, node):
if (node.module_name == u"cython") or \ if (node.module_name == u"cython") or \
node.module_name.startswith(u"cython."): node.module_name.startswith(u"cython."):
...@@ -654,7 +654,7 @@ class InterpretCompilerDirectives(CythonTransform, SkipDeclarations): ...@@ -654,7 +654,7 @@ class InterpretCompilerDirectives(CythonTransform, SkipDeclarations):
return None return None
node.imported_names = newimp node.imported_names = newimp
return node return node
def visit_FromImportStatNode(self, node): def visit_FromImportStatNode(self, node):
if (node.module.module_name.value == u"cython") or \ if (node.module.module_name.value == u"cython") or \
node.module.module_name.value.startswith(u"cython."): node.module.module_name.value.startswith(u"cython."):
...@@ -674,14 +674,14 @@ class InterpretCompilerDirectives(CythonTransform, SkipDeclarations): ...@@ -674,14 +674,14 @@ class InterpretCompilerDirectives(CythonTransform, SkipDeclarations):
def visit_SingleAssignmentNode(self, node): def visit_SingleAssignmentNode(self, node):
if (isinstance(node.rhs, ExprNodes.ImportNode) and if (isinstance(node.rhs, ExprNodes.ImportNode) and
node.rhs.module_name.value == u'cython'): node.rhs.module_name.value == u'cython'):
node = Nodes.CImportStatNode(node.pos, node = Nodes.CImportStatNode(node.pos,
module_name = u'cython', module_name = u'cython',
as_name = node.lhs.name) as_name = node.lhs.name)
self.visit_CImportStatNode(node) self.visit_CImportStatNode(node)
else: else:
self.visitchildren(node) self.visitchildren(node)
return node return node
def visit_NameNode(self, node): def visit_NameNode(self, node):
if node.name in self.cython_module_names: if node.name in self.cython_module_names:
node.is_cython_module = True node.is_cython_module = True
...@@ -771,7 +771,7 @@ class InterpretCompilerDirectives(CythonTransform, SkipDeclarations): ...@@ -771,7 +771,7 @@ class InterpretCompilerDirectives(CythonTransform, SkipDeclarations):
directives=newdirectives) directives=newdirectives)
self.directives = olddirectives self.directives = olddirectives
return directive return directive
# Handle decorators # Handle decorators
def visit_FuncDefNode(self, node): def visit_FuncDefNode(self, node):
directives = self._extract_directives(node, 'function') directives = self._extract_directives(node, 'function')
...@@ -905,7 +905,7 @@ class WithTransform(CythonTransform, SkipDeclarations): ...@@ -905,7 +905,7 @@ class WithTransform(CythonTransform, SkipDeclarations):
if EXC: if EXC:
EXIT(None, None, None) EXIT(None, None, None)
MGR = EXIT = VALUE = EXC = None MGR = EXIT = VALUE = EXC = None
""", temps=[u'MGR', u'EXC', u"EXIT", u"VALUE"], """, temps=[u'MGR', u'EXC', u"EXIT", u"VALUE"],
pipeline=[NormalizeTree(None)]) pipeline=[NormalizeTree(None)])
...@@ -913,7 +913,7 @@ class WithTransform(CythonTransform, SkipDeclarations): ...@@ -913,7 +913,7 @@ class WithTransform(CythonTransform, SkipDeclarations):
# TODO: Cleanup badly needed # TODO: Cleanup badly needed
TemplateTransform.temp_name_counter += 1 TemplateTransform.temp_name_counter += 1
handle = "__tmpvar_%d" % TemplateTransform.temp_name_counter handle = "__tmpvar_%d" % TemplateTransform.temp_name_counter
self.visitchildren(node, ['body']) self.visitchildren(node, ['body'])
excinfo_temp = ExprNodes.NameNode(node.pos, name=handle)#TempHandle(Builtin.tuple_type) excinfo_temp = ExprNodes.NameNode(node.pos, name=handle)#TempHandle(Builtin.tuple_type)
if node.target is not None: if node.target is not None:
...@@ -939,11 +939,11 @@ class WithTransform(CythonTransform, SkipDeclarations): ...@@ -939,11 +939,11 @@ class WithTransform(CythonTransform, SkipDeclarations):
# node.pos, temps=[excinfo_temp], body=try_except) # node.pos, temps=[excinfo_temp], body=try_except)
return result return result
def visit_ExprNode(self, node): def visit_ExprNode(self, node):
# With statements are never inside expressions. # With statements are never inside expressions.
return node return node
class DecoratorTransform(CythonTransform, SkipDeclarations): class DecoratorTransform(CythonTransform, SkipDeclarations):
...@@ -1022,8 +1022,8 @@ property NAME: ...@@ -1022,8 +1022,8 @@ property NAME:
self.env_stack = [root.scope] self.env_stack = [root.scope]
# needed to determine if a cdef var is declared after it's used. # needed to determine if a cdef var is declared after it's used.
self.seen_vars_stack = [] self.seen_vars_stack = []
return super(AnalyseDeclarationsTransform, self).__call__(root) return super(AnalyseDeclarationsTransform, self).__call__(root)
def visit_NameNode(self, node): def visit_NameNode(self, node):
self.seen_vars_stack[-1].add(node.name) self.seen_vars_stack[-1].add(node.name)
return node return node
...@@ -1045,7 +1045,7 @@ property NAME: ...@@ -1045,7 +1045,7 @@ property NAME:
self.visitchildren(node) self.visitchildren(node)
self.env_stack.pop() self.env_stack.pop()
return node return node
def visit_CClassDefNode(self, node): def visit_CClassDefNode(self, node):
node = self.visit_ClassDefNode(node) node = self.visit_ClassDefNode(node)
if node.scope and node.scope.implemented: if node.scope and node.scope.implemented:
...@@ -1059,7 +1059,7 @@ property NAME: ...@@ -1059,7 +1059,7 @@ property NAME:
if stats: if stats:
node.body.stats += stats node.body.stats += stats
return node return node
def visit_FuncDefNode(self, node): def visit_FuncDefNode(self, node):
self.seen_vars_stack.append(cython.set()) self.seen_vars_stack.append(cython.set())
lenv = node.local_scope lenv = node.local_scope
...@@ -1108,13 +1108,13 @@ property NAME: ...@@ -1108,13 +1108,13 @@ property NAME:
# necessary to ensure that all CNameDeclaratorNodes are visited. # necessary to ensure that all CNameDeclaratorNodes are visited.
self.visitchildren(node) self.visitchildren(node)
return node return node
def visit_CTypeDefNode(self, node): def visit_CTypeDefNode(self, node):
return node return node
def visit_CBaseTypeNode(self, node): def visit_CBaseTypeNode(self, node):
return None return None
def visit_CEnumDefNode(self, node): def visit_CEnumDefNode(self, node):
if node.visibility == 'public': if node.visibility == 'public':
return node return node
...@@ -1136,7 +1136,7 @@ property NAME: ...@@ -1136,7 +1136,7 @@ property NAME:
# to ensure all CNameDeclaratorNodes are visited. # to ensure all CNameDeclaratorNodes are visited.
self.visitchildren(node) self.visitchildren(node)
return None return None
def create_Property(self, entry): def create_Property(self, entry):
if entry.visibility == 'public': if entry.visibility == 'public':
if entry.type.is_pyobject: if entry.type.is_pyobject:
...@@ -1147,14 +1147,14 @@ property NAME: ...@@ -1147,14 +1147,14 @@ property NAME:
template = self.basic_property_ro template = self.basic_property_ro
property = template.substitute({ property = template.substitute({
u"ATTR": ExprNodes.AttributeNode(pos=entry.pos, u"ATTR": ExprNodes.AttributeNode(pos=entry.pos,
obj=ExprNodes.NameNode(pos=entry.pos, name="self"), obj=ExprNodes.NameNode(pos=entry.pos, name="self"),
attribute=entry.name), attribute=entry.name),
}, pos=entry.pos).stats[0] }, pos=entry.pos).stats[0]
property.name = entry.name property.name = entry.name
# --------------------------------------- # ---------------------------------------
# XXX This should go to AutoDocTransforms # XXX This should go to AutoDocTransforms
# --------------------------------------- # ---------------------------------------
if (Options.docstrings and if (Options.docstrings and
self.current_directives['embedsignature']): self.current_directives['embedsignature']):
attr_name = entry.name attr_name = entry.name
type_name = entry.type.declaration_code("", for_display=1) type_name = entry.type.declaration_code("", for_display=1)
...@@ -1179,7 +1179,7 @@ class AnalyseExpressionsTransform(CythonTransform): ...@@ -1179,7 +1179,7 @@ class AnalyseExpressionsTransform(CythonTransform):
node.body.analyse_expressions(node.scope) node.body.analyse_expressions(node.scope)
self.visitchildren(node) self.visitchildren(node)
return node return node
def visit_FuncDefNode(self, node): def visit_FuncDefNode(self, node):
node.local_scope.infer_types() node.local_scope.infer_types()
node.body.analyse_expressions(node.local_scope) node.body.analyse_expressions(node.local_scope)
...@@ -1194,7 +1194,7 @@ class AnalyseExpressionsTransform(CythonTransform): ...@@ -1194,7 +1194,7 @@ class AnalyseExpressionsTransform(CythonTransform):
return node return node
class ExpandInplaceOperators(EnvTransform): class ExpandInplaceOperators(EnvTransform):
def visit_InPlaceAssignmentNode(self, node): def visit_InPlaceAssignmentNode(self, node):
lhs = node.lhs lhs = node.lhs
rhs = node.rhs rhs = node.rhs
...@@ -1229,7 +1229,7 @@ class ExpandInplaceOperators(EnvTransform): ...@@ -1229,7 +1229,7 @@ class ExpandInplaceOperators(EnvTransform):
except ValueError: except ValueError:
return node return node
dup = lhs.__class__(**lhs.__dict__) dup = lhs.__class__(**lhs.__dict__)
binop = ExprNodes.binop_node(node.pos, binop = ExprNodes.binop_node(node.pos,
operator = node.operator, operator = node.operator,
operand1 = dup, operand1 = dup,
operand2 = rhs, operand2 = rhs,
...@@ -1239,7 +1239,7 @@ class ExpandInplaceOperators(EnvTransform): ...@@ -1239,7 +1239,7 @@ class ExpandInplaceOperators(EnvTransform):
dup.analyse_types(env) dup.analyse_types(env)
binop.analyse_operation(env) binop.analyse_operation(env)
node = Nodes.SingleAssignmentNode( node = Nodes.SingleAssignmentNode(
node.pos, node.pos,
lhs = lhs, lhs = lhs,
rhs=binop.coerce_to(lhs.type, env)) rhs=binop.coerce_to(lhs.type, env))
# Use LetRefNode to avoid side effects. # Use LetRefNode to avoid side effects.
...@@ -1255,16 +1255,16 @@ class ExpandInplaceOperators(EnvTransform): ...@@ -1255,16 +1255,16 @@ class ExpandInplaceOperators(EnvTransform):
class AlignFunctionDefinitions(CythonTransform): class AlignFunctionDefinitions(CythonTransform):
""" """
This class takes the signatures from a .pxd file and applies them to This class takes the signatures from a .pxd file and applies them to
the def methods in a .py file. the def methods in a .py file.
""" """
def visit_ModuleNode(self, node): def visit_ModuleNode(self, node):
self.scope = node.scope self.scope = node.scope
self.directives = node.directives self.directives = node.directives
self.visitchildren(node) self.visitchildren(node)
return node return node
def visit_PyClassDefNode(self, node): def visit_PyClassDefNode(self, node):
pxd_def = self.scope.lookup(node.name) pxd_def = self.scope.lookup(node.name)
if pxd_def: if pxd_def:
...@@ -1276,7 +1276,7 @@ class AlignFunctionDefinitions(CythonTransform): ...@@ -1276,7 +1276,7 @@ class AlignFunctionDefinitions(CythonTransform):
return None return None
else: else:
return node return node
def visit_CClassDefNode(self, node, pxd_def=None): def visit_CClassDefNode(self, node, pxd_def=None):
if pxd_def is None: if pxd_def is None:
pxd_def = self.scope.lookup(node.class_name) pxd_def = self.scope.lookup(node.class_name)
...@@ -1287,7 +1287,7 @@ class AlignFunctionDefinitions(CythonTransform): ...@@ -1287,7 +1287,7 @@ class AlignFunctionDefinitions(CythonTransform):
if pxd_def: if pxd_def:
self.scope = outer_scope self.scope = outer_scope
return node return node
def visit_DefNode(self, node): def visit_DefNode(self, node):
pxd_def = self.scope.lookup(node.name) pxd_def = self.scope.lookup(node.name)
if pxd_def: if pxd_def:
...@@ -1298,10 +1298,10 @@ class AlignFunctionDefinitions(CythonTransform): ...@@ -1298,10 +1298,10 @@ class AlignFunctionDefinitions(CythonTransform):
node = node.as_cfunction(pxd_def) node = node.as_cfunction(pxd_def)
elif self.scope.is_module_scope and self.directives['auto_cpdef']: elif self.scope.is_module_scope and self.directives['auto_cpdef']:
node = node.as_cfunction(scope=self.scope) node = node.as_cfunction(scope=self.scope)
# Enable this when internal def functions are allowed. # Enable this when internal def functions are allowed.
# self.visitchildren(node) # self.visitchildren(node)
return node return node
class MarkClosureVisitor(CythonTransform): class MarkClosureVisitor(CythonTransform):
...@@ -1316,7 +1316,7 @@ class MarkClosureVisitor(CythonTransform): ...@@ -1316,7 +1316,7 @@ class MarkClosureVisitor(CythonTransform):
node.needs_closure = self.needs_closure node.needs_closure = self.needs_closure
self.needs_closure = True self.needs_closure = True
return node return node
def visit_CFuncDefNode(self, node): def visit_CFuncDefNode(self, node):
self.visit_FuncDefNode(node) self.visit_FuncDefNode(node)
if node.needs_closure: if node.needs_closure:
...@@ -1482,14 +1482,14 @@ class TransformBuiltinMethods(EnvTransform): ...@@ -1482,14 +1482,14 @@ class TransformBuiltinMethods(EnvTransform):
else: else:
self.visitchildren(node) self.visitchildren(node)
return node return node
def visit_AttributeNode(self, node): def visit_AttributeNode(self, node):
self.visitchildren(node) self.visitchildren(node)
return self.visit_cython_attribute(node) return self.visit_cython_attribute(node)
def visit_NameNode(self, node): def visit_NameNode(self, node):
return self.visit_cython_attribute(node) return self.visit_cython_attribute(node)
def visit_cython_attribute(self, node): def visit_cython_attribute(self, node):
attribute = node.as_cython_attribute() attribute = node.as_cython_attribute()
if attribute: if attribute:
...@@ -1571,7 +1571,7 @@ class TransformBuiltinMethods(EnvTransform): ...@@ -1571,7 +1571,7 @@ class TransformBuiltinMethods(EnvTransform):
node.function = ExprNodes.NameNode(node.pos, name=EncodedString('set')) node.function = ExprNodes.NameNode(node.pos, name=EncodedString('set'))
else: else:
error(node.function.pos, u"'%s' not a valid cython language construct" % function) error(node.function.pos, u"'%s' not a valid cython language construct" % function)
self.visitchildren(node) self.visitchildren(node)
return node return node
...@@ -1581,64 +1581,64 @@ class DebugTransform(CythonTransform): ...@@ -1581,64 +1581,64 @@ class DebugTransform(CythonTransform):
Create debug information and all functions' visibility to extern in order Create debug information and all functions' visibility to extern in order
to enable debugging. to enable debugging.
""" """
def __init__(self, context, options, result): def __init__(self, context, options, result):
super(DebugTransform, self).__init__(context) super(DebugTransform, self).__init__(context)
self.visited = cython.set() self.visited = cython.set()
# our treebuilder and debug output writer # our treebuilder and debug output writer
# (see Cython.Debugger.debug_output.CythonDebugWriter) # (see Cython.Debugger.debug_output.CythonDebugWriter)
self.tb = self.context.gdb_debug_outputwriter self.tb = self.context.gdb_debug_outputwriter
#self.c_output_file = options.output_file #self.c_output_file = options.output_file
self.c_output_file = result.c_file self.c_output_file = result.c_file
# Closure support, basically treat nested functions as if the AST were # Closure support, basically treat nested functions as if the AST were
# never nested # never nested
self.nested_funcdefs = [] self.nested_funcdefs = []
# tells visit_NameNode whether it should register step-into functions # tells visit_NameNode whether it should register step-into functions
self.register_stepinto = False self.register_stepinto = False
def visit_ModuleNode(self, node): def visit_ModuleNode(self, node):
self.tb.module_name = node.full_module_name self.tb.module_name = node.full_module_name
attrs = dict( attrs = dict(
module_name=node.full_module_name, module_name=node.full_module_name,
filename=node.pos[0].filename, filename=node.pos[0].filename,
c_filename=self.c_output_file) c_filename=self.c_output_file)
self.tb.start('Module', attrs) self.tb.start('Module', attrs)
# serialize functions # serialize functions
self.tb.start('Functions') self.tb.start('Functions')
# First, serialize functions normally... # First, serialize functions normally...
self.visitchildren(node) self.visitchildren(node)
# ... then, serialize nested functions # ... then, serialize nested functions
for nested_funcdef in self.nested_funcdefs: for nested_funcdef in self.nested_funcdefs:
self.visit_FuncDefNode(nested_funcdef) self.visit_FuncDefNode(nested_funcdef)
self.register_stepinto = True self.register_stepinto = True
self.serialize_modulenode_as_function(node) self.serialize_modulenode_as_function(node)
self.register_stepinto = False self.register_stepinto = False
self.tb.end('Functions') self.tb.end('Functions')
# 2.3 compatibility. Serialize global variables # 2.3 compatibility. Serialize global variables
self.tb.start('Globals') self.tb.start('Globals')
entries = {} entries = {}
for k, v in node.scope.entries.iteritems(): for k, v in node.scope.entries.iteritems():
if (v.qualified_name not in self.visited and not if (v.qualified_name not in self.visited and not
v.name.startswith('__pyx_') and not v.name.startswith('__pyx_') and not
v.type.is_cfunction and not v.type.is_cfunction and not
v.type.is_extension_type): v.type.is_extension_type):
entries[k]= v entries[k]= v
self.serialize_local_variables(entries) self.serialize_local_variables(entries)
self.tb.end('Globals') self.tb.end('Globals')
# self.tb.end('Module') # end Module after the line number mapping in # self.tb.end('Module') # end Module after the line number mapping in
# Cython.Compiler.ModuleNode.ModuleNode._serialize_lineno_map # Cython.Compiler.ModuleNode.ModuleNode._serialize_lineno_map
return node return node
def visit_FuncDefNode(self, node): def visit_FuncDefNode(self, node):
self.visited.add(node.local_scope.qualified_name) self.visited.add(node.local_scope.qualified_name)
if getattr(node, 'is_wrapper', False): if getattr(node, 'is_wrapper', False):
...@@ -1653,16 +1653,16 @@ class DebugTransform(CythonTransform): ...@@ -1653,16 +1653,16 @@ class DebugTransform(CythonTransform):
pf_cname = '' pf_cname = ''
else: else:
pf_cname = node.py_func.entry.func_cname pf_cname = node.py_func.entry.func_cname
attrs = dict( attrs = dict(
name=node.entry.name, name=node.entry.name,
cname=node.entry.func_cname, cname=node.entry.func_cname,
pf_cname=pf_cname, pf_cname=pf_cname,
qualified_name=node.local_scope.qualified_name, qualified_name=node.local_scope.qualified_name,
lineno=str(node.pos[1])) lineno=str(node.pos[1]))
self.tb.start('Function', attrs=attrs) self.tb.start('Function', attrs=attrs)
self.tb.start('Locals') self.tb.start('Locals')
self.serialize_local_variables(node.local_scope.entries) self.serialize_local_variables(node.local_scope.entries)
self.tb.end('Locals') self.tb.end('Locals')
...@@ -1683,22 +1683,22 @@ class DebugTransform(CythonTransform): ...@@ -1683,22 +1683,22 @@ class DebugTransform(CythonTransform):
return node return node
def visit_NameNode(self, node): def visit_NameNode(self, node):
if (self.register_stepinto and if (self.register_stepinto and
node.type.is_cfunction and node.type.is_cfunction and
getattr(node, 'is_called', False) and getattr(node, 'is_called', False) and
node.entry.func_cname is not None): node.entry.func_cname is not None):
# don't check node.entry.in_cinclude, as 'cdef extern: ...' # don't check node.entry.in_cinclude, as 'cdef extern: ...'
# declared functions are not 'in_cinclude'. # declared functions are not 'in_cinclude'.
# This means we will list called 'cdef' functions as # This means we will list called 'cdef' functions as
# "step into functions", but this is not an issue as they will be # "step into functions", but this is not an issue as they will be
# recognized as Cython functions anyway. # recognized as Cython functions anyway.
attrs = dict(name=node.entry.func_cname) attrs = dict(name=node.entry.func_cname)
self.tb.start('StepIntoFunction', attrs=attrs) self.tb.start('StepIntoFunction', attrs=attrs)
self.tb.end('StepIntoFunction') self.tb.end('StepIntoFunction')
self.visitchildren(node) self.visitchildren(node)
return node return node
def serialize_modulenode_as_function(self, node): def serialize_modulenode_as_function(self, node):
""" """
Serialize the module-level code as a function so the debugger will know Serialize the module-level code as a function so the debugger will know
...@@ -1706,29 +1706,29 @@ class DebugTransform(CythonTransform): ...@@ -1706,29 +1706,29 @@ class DebugTransform(CythonTransform):
for 'break modulename'. for 'break modulename'.
""" """
name = node.full_module_name.rpartition('.')[-1] name = node.full_module_name.rpartition('.')[-1]
cname_py2 = 'init' + name cname_py2 = 'init' + name
cname_py3 = 'PyInit_' + name cname_py3 = 'PyInit_' + name
py2_attrs = dict( py2_attrs = dict(
name=name, name=name,
cname=cname_py2, cname=cname_py2,
pf_cname='', pf_cname='',
# Ignore the qualified_name, breakpoints should be set using # Ignore the qualified_name, breakpoints should be set using
# `cy break modulename:lineno` for module-level breakpoints. # `cy break modulename:lineno` for module-level breakpoints.
qualified_name='', qualified_name='',
lineno='1', lineno='1',
is_initmodule_function="True", is_initmodule_function="True",
) )
py3_attrs = dict(py2_attrs, cname=cname_py3) py3_attrs = dict(py2_attrs, cname=cname_py3)
self._serialize_modulenode_as_function(node, py2_attrs) self._serialize_modulenode_as_function(node, py2_attrs)
self._serialize_modulenode_as_function(node, py3_attrs) self._serialize_modulenode_as_function(node, py3_attrs)
def _serialize_modulenode_as_function(self, node, attrs): def _serialize_modulenode_as_function(self, node, attrs):
self.tb.start('Function', attrs=attrs) self.tb.start('Function', attrs=attrs)
self.tb.start('Locals') self.tb.start('Locals')
self.serialize_local_variables(node.scope.entries) self.serialize_local_variables(node.scope.entries)
self.tb.end('Locals') self.tb.end('Locals')
...@@ -1741,27 +1741,27 @@ class DebugTransform(CythonTransform): ...@@ -1741,27 +1741,27 @@ class DebugTransform(CythonTransform):
self.visitchildren(node) self.visitchildren(node)
self.register_stepinto = False self.register_stepinto = False
self.tb.end('StepIntoFunctions') self.tb.end('StepIntoFunctions')
self.tb.end('Function') self.tb.end('Function')
def serialize_local_variables(self, entries): def serialize_local_variables(self, entries):
for entry in entries.values(): for entry in entries.values():
if entry.type.is_pyobject: if entry.type.is_pyobject:
vartype = 'PythonObject' vartype = 'PythonObject'
else: else:
vartype = 'CObject' vartype = 'CObject'
if entry.from_closure: if entry.from_closure:
# We're dealing with a closure where a variable from an outer # We're dealing with a closure where a variable from an outer
# scope is accessed, get it from the scope object. # scope is accessed, get it from the scope object.
cname = '%s->%s' % (Naming.cur_scope_cname, cname = '%s->%s' % (Naming.cur_scope_cname,
entry.outer_entry.cname) entry.outer_entry.cname)
qname = '%s.%s.%s' % (entry.scope.outer_scope.qualified_name, qname = '%s.%s.%s' % (entry.scope.outer_scope.qualified_name,
entry.scope.name, entry.scope.name,
entry.name) entry.name)
elif entry.in_closure: elif entry.in_closure:
cname = '%s->%s' % (Naming.cur_scope_cname, cname = '%s->%s' % (Naming.cur_scope_cname,
entry.cname) entry.cname)
qname = entry.qualified_name qname = entry.qualified_name
else: else:
...@@ -1775,14 +1775,14 @@ class DebugTransform(CythonTransform): ...@@ -1775,14 +1775,14 @@ class DebugTransform(CythonTransform):
lineno = '0' lineno = '0'
else: else:
lineno = str(entry.pos[1]) lineno = str(entry.pos[1])
attrs = dict( attrs = dict(
name=entry.name, name=entry.name,
cname=cname, cname=cname,
qualified_name=qname, qualified_name=qname,
type=vartype, type=vartype,
lineno=lineno) lineno=lineno)
self.tb.start('LocalVar', attrs) self.tb.start('LocalVar', attrs)
self.tb.end('LocalVar') self.tb.end('LocalVar')
...@@ -17,7 +17,7 @@ class TestNormalizeTree(TransformTest): ...@@ -17,7 +17,7 @@ class TestNormalizeTree(TransformTest):
body: ExprStatNode body: ExprStatNode
expr: NameNode expr: NameNode
""", self.treetypes(t)) """, self.treetypes(t))
def test_wrap_singlestat(self): def test_wrap_singlestat(self):
t = self.run_pipeline([NormalizeTree(None)], u"if x: y") t = self.run_pipeline([NormalizeTree(None)], u"if x: y")
self.assertLines(u""" self.assertLines(u"""
...@@ -83,7 +83,7 @@ class TestNormalizeTree(TransformTest): ...@@ -83,7 +83,7 @@ class TestNormalizeTree(TransformTest):
stats[0]: ExprStatNode stats[0]: ExprStatNode
expr: NameNode expr: NameNode
""", self.treetypes(t)) """, self.treetypes(t))
def test_pass_eliminated(self): def test_pass_eliminated(self):
t = self.run_pipeline([NormalizeTree(None)], u"pass") t = self.run_pipeline([NormalizeTree(None)], u"pass")
...@@ -142,7 +142,7 @@ class TestWithTransform(object): # (TransformTest): # Disabled! ...@@ -142,7 +142,7 @@ class TestWithTransform(object): # (TransformTest): # Disabled!
$0_2(None, None, None) $0_2(None, None, None)
""", t) """, t)
# TODO: Re-enable once they're more robust. # TODO: Re-enable once they're more robust.
if sys.version_info[:2] >= (2, 5) and False: if sys.version_info[:2] >= (2, 5) and False:
...@@ -153,15 +153,15 @@ else: ...@@ -153,15 +153,15 @@ else:
DebuggerTestCase = object DebuggerTestCase = object
class TestDebugTransform(DebuggerTestCase): class TestDebugTransform(DebuggerTestCase):
def elem_hasattrs(self, elem, attrs): def elem_hasattrs(self, elem, attrs):
# we shall supporteth python 2.3 ! # we shall supporteth python 2.3 !
return all([attr in elem.attrib for attr in attrs]) return all([attr in elem.attrib for attr in attrs])
def test_debug_info(self): def test_debug_info(self):
try: try:
assert os.path.exists(self.debug_dest) assert os.path.exists(self.debug_dest)
t = DebugWriter.etree.parse(self.debug_dest) t = DebugWriter.etree.parse(self.debug_dest)
# the xpath of the standard ElementTree is primitive, don't use # the xpath of the standard ElementTree is primitive, don't use
# anything fancy # anything fancy
...@@ -171,23 +171,23 @@ class TestDebugTransform(DebuggerTestCase): ...@@ -171,23 +171,23 @@ class TestDebugTransform(DebuggerTestCase):
xml_globals = dict( xml_globals = dict(
[(e.attrib['name'], e.attrib['type']) for e in L]) [(e.attrib['name'], e.attrib['type']) for e in L])
self.assertEqual(len(L), len(xml_globals)) self.assertEqual(len(L), len(xml_globals))
L = list(t.find('/Module/Functions')) L = list(t.find('/Module/Functions'))
assert L assert L
xml_funcs = dict([(e.attrib['qualified_name'], e) for e in L]) xml_funcs = dict([(e.attrib['qualified_name'], e) for e in L])
self.assertEqual(len(L), len(xml_funcs)) self.assertEqual(len(L), len(xml_funcs))
# test globals # test globals
self.assertEqual('CObject', xml_globals.get('c_var')) self.assertEqual('CObject', xml_globals.get('c_var'))
self.assertEqual('PythonObject', xml_globals.get('python_var')) self.assertEqual('PythonObject', xml_globals.get('python_var'))
# test functions # test functions
funcnames = ('codefile.spam', 'codefile.ham', 'codefile.eggs', funcnames = ('codefile.spam', 'codefile.ham', 'codefile.eggs',
'codefile.closure', 'codefile.inner') 'codefile.closure', 'codefile.inner')
required_xml_attrs = 'name', 'cname', 'qualified_name' required_xml_attrs = 'name', 'cname', 'qualified_name'
assert all([f in xml_funcs for f in funcnames]) assert all([f in xml_funcs for f in funcnames])
spam, ham, eggs = [xml_funcs[funcname] for funcname in funcnames] spam, ham, eggs = [xml_funcs[funcname] for funcname in funcnames]
self.assertEqual(spam.attrib['name'], 'spam') self.assertEqual(spam.attrib['name'], 'spam')
self.assertNotEqual('spam', spam.attrib['cname']) self.assertNotEqual('spam', spam.attrib['cname'])
assert self.elem_hasattrs(spam, required_xml_attrs) assert self.elem_hasattrs(spam, required_xml_attrs)
...@@ -199,12 +199,12 @@ class TestDebugTransform(DebuggerTestCase): ...@@ -199,12 +199,12 @@ class TestDebugTransform(DebuggerTestCase):
names = [e.attrib['name'] for e in spam_locals] names = [e.attrib['name'] for e in spam_locals]
self.assertEqual(list('abcd'), names) self.assertEqual(list('abcd'), names)
assert self.elem_hasattrs(spam_locals[0], required_xml_attrs) assert self.elem_hasattrs(spam_locals[0], required_xml_attrs)
# test arguments of functions # test arguments of functions
spam_arguments = list(spam.find('Arguments')) spam_arguments = list(spam.find('Arguments'))
assert spam_arguments assert spam_arguments
self.assertEqual(1, len(list(spam_arguments))) self.assertEqual(1, len(list(spam_arguments)))
# test step-into functions # test step-into functions
step_into = spam.find('StepIntoFunctions') step_into = spam.find('StepIntoFunctions')
spam_stepinto = [x.attrib['name'] for x in step_into] spam_stepinto = [x.attrib['name'] for x in step_into]
...@@ -215,10 +215,10 @@ class TestDebugTransform(DebuggerTestCase): ...@@ -215,10 +215,10 @@ class TestDebugTransform(DebuggerTestCase):
except: except:
print open(self.debug_dest).read() print open(self.debug_dest).read()
raise raise
if __name__ == "__main__": if __name__ == "__main__":
import unittest import unittest
......
...@@ -385,7 +385,7 @@ class TestClosure(DebugTestCase): ...@@ -385,7 +385,7 @@ class TestClosure(DebugTestCase):
def test_inner(self): def test_inner(self):
self.break_and_run_func('inner') self.break_and_run_func('inner')
self.assertEqual('', gdb.execute('cy locals', to_string=True)) self.assertEqual('', gdb.execute('cy locals', to_string=True))
# Allow the Cython-generated code to initialize the scope variable # Allow the Cython-generated code to initialize the scope variable
gdb.execute('cy step') gdb.execute('cy step')
...@@ -400,7 +400,7 @@ class TestClosure(DebugTestCase): ...@@ -400,7 +400,7 @@ class TestClosure(DebugTestCase):
# Initialize scope with 'a' uninitialized # Initialize scope with 'a' uninitialized
gdb.execute('cy step') gdb.execute('cy step')
self.assertEqual('', gdb.execute('cy locals', to_string=True)) self.assertEqual('', gdb.execute('cy locals', to_string=True))
# Initialize 'a' to 1 # Initialize 'a' to 1
gdb.execute('cy step') gdb.execute('cy step')
print_result = gdb.execute('cy print a', to_string=True).strip() print_result = gdb.execute('cy print a', to_string=True).strip()
......
...@@ -67,7 +67,7 @@ def dont_suppress_errors(function): ...@@ -67,7 +67,7 @@ def dont_suppress_errors(function):
except Exception: except Exception:
traceback.print_exc() traceback.print_exc()
raise raise
return wrapper return wrapper
def default_selected_gdb_frame(err=True): def default_selected_gdb_frame(err=True):
...@@ -78,10 +78,10 @@ def default_selected_gdb_frame(err=True): ...@@ -78,10 +78,10 @@ def default_selected_gdb_frame(err=True):
frame = frame or gdb.selected_frame() frame = frame or gdb.selected_frame()
except RuntimeError: except RuntimeError:
raise gdb.GdbError("No frame is currently selected.") raise gdb.GdbError("No frame is currently selected.")
if err and frame.name() is None: if err and frame.name() is None:
raise NoFunctionNameInFrameError() raise NoFunctionNameInFrameError()
return function(self, frame, *args, **kwargs) return function(self, frame, *args, **kwargs)
return wrapper return wrapper
return decorator return decorator
...@@ -95,7 +95,7 @@ def require_cython_frame(function): ...@@ -95,7 +95,7 @@ def require_cython_frame(function):
raise gdb.GdbError('Selected frame does not correspond with a ' raise gdb.GdbError('Selected frame does not correspond with a '
'Cython function we know about.') 'Cython function we know about.')
return function(self, *args, **kwargs) return function(self, *args, **kwargs)
return wrapper return wrapper
def dispatch_on_frame(c_command, python_command=None): def dispatch_on_frame(c_command, python_command=None):
def decorator(function): def decorator(function):
...@@ -103,7 +103,7 @@ def dispatch_on_frame(c_command, python_command=None): ...@@ -103,7 +103,7 @@ def dispatch_on_frame(c_command, python_command=None):
def wrapper(self, *args, **kwargs): def wrapper(self, *args, **kwargs):
is_cy = self.is_cython_function() is_cy = self.is_cython_function()
is_py = self.is_python_function() is_py = self.is_python_function()
if is_cy or (is_py and not python_command): if is_cy or (is_py and not python_command):
function(self, *args, **kwargs) function(self, *args, **kwargs)
elif is_py: elif is_py:
...@@ -113,7 +113,7 @@ def dispatch_on_frame(c_command, python_command=None): ...@@ -113,7 +113,7 @@ def dispatch_on_frame(c_command, python_command=None):
else: else:
raise gdb.GdbError("Not a function cygdb knows about. " raise gdb.GdbError("Not a function cygdb knows about. "
"Use the normal GDB commands instead.") "Use the normal GDB commands instead.")
return wrapper return wrapper
return decorator return decorator
...@@ -124,10 +124,10 @@ def require_running_program(function): ...@@ -124,10 +124,10 @@ def require_running_program(function):
gdb.selected_frame() gdb.selected_frame()
except RuntimeError: except RuntimeError:
raise gdb.GdbError("No frame is currently selected.") raise gdb.GdbError("No frame is currently selected.")
return function(*args, **kwargs) return function(*args, **kwargs)
return wrapper return wrapper
def gdb_function_value_to_unicode(function): def gdb_function_value_to_unicode(function):
@functools.wraps(function) @functools.wraps(function)
...@@ -153,7 +153,7 @@ class CythonModule(object): ...@@ -153,7 +153,7 @@ class CythonModule(object):
# {c_lineno: cython_lineno} # {c_lineno: cython_lineno}
self.lineno_c2cy = {} self.lineno_c2cy = {}
self.functions = {} self.functions = {}
class CythonVariable(object): class CythonVariable(object):
def __init__(self, name, cname, qualified_name, type, lineno): def __init__(self, name, cname, qualified_name, type, lineno):
...@@ -164,18 +164,18 @@ class CythonVariable(object): ...@@ -164,18 +164,18 @@ class CythonVariable(object):
self.lineno = int(lineno) self.lineno = int(lineno)
class CythonFunction(CythonVariable): class CythonFunction(CythonVariable):
def __init__(self, def __init__(self,
module, module,
name, name,
cname, cname,
pf_cname, pf_cname,
qualified_name, qualified_name,
lineno, lineno,
type=CObject, type=CObject,
is_initmodule_function="False"): is_initmodule_function="False"):
super(CythonFunction, self).__init__(name, super(CythonFunction, self).__init__(name,
cname, cname,
qualified_name, qualified_name,
type, type,
lineno) lineno)
self.module = module self.module = module
...@@ -189,7 +189,7 @@ class CythonFunction(CythonVariable): ...@@ -189,7 +189,7 @@ class CythonFunction(CythonVariable):
# General purpose classes # General purpose classes
class CythonBase(object): class CythonBase(object):
@default_selected_gdb_frame(err=False) @default_selected_gdb_frame(err=False)
def is_cython_function(self, frame): def is_cython_function(self, frame):
return frame.name() in self.cy.functions_by_cname return frame.name() in self.cy.functions_by_cname
...@@ -204,7 +204,7 @@ class CythonBase(object): ...@@ -204,7 +204,7 @@ class CythonBase(object):
pyframe = libpython.Frame(frame).get_pyop() pyframe = libpython.Frame(frame).get_pyop()
return pyframe and not pyframe.is_optimized_out() return pyframe and not pyframe.is_optimized_out()
return False return False
@default_selected_gdb_frame() @default_selected_gdb_frame()
def get_c_function_name(self, frame): def get_c_function_name(self, frame):
return frame.name() return frame.name()
...@@ -212,24 +212,24 @@ class CythonBase(object): ...@@ -212,24 +212,24 @@ class CythonBase(object):
@default_selected_gdb_frame() @default_selected_gdb_frame()
def get_c_lineno(self, frame): def get_c_lineno(self, frame):
return frame.find_sal().line return frame.find_sal().line
@default_selected_gdb_frame() @default_selected_gdb_frame()
def get_cython_function(self, frame): def get_cython_function(self, frame):
result = self.cy.functions_by_cname.get(frame.name()) result = self.cy.functions_by_cname.get(frame.name())
if result is None: if result is None:
raise NoCythonFunctionInFrameError() raise NoCythonFunctionInFrameError()
return result return result
@default_selected_gdb_frame() @default_selected_gdb_frame()
def get_cython_lineno(self, frame): def get_cython_lineno(self, frame):
""" """
Get the current Cython line number. Returns 0 if there is no Get the current Cython line number. Returns 0 if there is no
correspondence between the C and Cython code. correspondence between the C and Cython code.
""" """
cyfunc = self.get_cython_function(frame) cyfunc = self.get_cython_function(frame)
return cyfunc.module.lineno_c2cy.get(self.get_c_lineno(frame), 0) return cyfunc.module.lineno_c2cy.get(self.get_c_lineno(frame), 0)
@default_selected_gdb_frame() @default_selected_gdb_frame()
def get_source_desc(self, frame): def get_source_desc(self, frame):
filename = lineno = lexer = None filename = lineno = lexer = None
...@@ -247,7 +247,7 @@ class CythonBase(object): ...@@ -247,7 +247,7 @@ class CythonBase(object):
filename = pyframeobject.filename() filename = pyframeobject.filename()
lineno = pyframeobject.current_line_num() lineno = pyframeobject.current_line_num()
if pygments: if pygments:
lexer = pygments.lexers.PythonLexer(stripall=False) lexer = pygments.lexers.PythonLexer(stripall=False)
else: else:
...@@ -260,14 +260,14 @@ class CythonBase(object): ...@@ -260,14 +260,14 @@ class CythonBase(object):
lineno = symbol_and_line_obj.line lineno = symbol_and_line_obj.line
if pygments: if pygments:
lexer = pygments.lexers.CLexer(stripall=False) lexer = pygments.lexers.CLexer(stripall=False)
return SourceFileDescriptor(filename, lexer), lineno return SourceFileDescriptor(filename, lexer), lineno
@default_selected_gdb_frame() @default_selected_gdb_frame()
def get_source_line(self, frame): def get_source_line(self, frame):
source_desc, lineno = self.get_source_desc() source_desc, lineno = self.get_source_desc()
return source_desc.get_source(lineno) return source_desc.get_source(lineno)
@default_selected_gdb_frame() @default_selected_gdb_frame()
def is_relevant_function(self, frame): def is_relevant_function(self, frame):
""" """
...@@ -284,7 +284,7 @@ class CythonBase(object): ...@@ -284,7 +284,7 @@ class CythonBase(object):
return name in cython_func.step_into_functions return name in cython_func.step_into_functions
return False return False
@default_selected_gdb_frame(err=False) @default_selected_gdb_frame(err=False)
def print_stackframe(self, frame, index, is_c=False): def print_stackframe(self, frame, index, is_c=False):
""" """
...@@ -295,7 +295,7 @@ class CythonBase(object): ...@@ -295,7 +295,7 @@ class CythonBase(object):
# raising GdbError when calling self.cy.cy_cvalue.invoke() # raising GdbError when calling self.cy.cy_cvalue.invoke()
selected_frame = gdb.selected_frame() selected_frame = gdb.selected_frame()
frame.select() frame.select()
try: try:
source_desc, lineno = self.get_source_desc(frame) source_desc, lineno = self.get_source_desc(frame)
except NoFunctionNameInFrameError: except NoFunctionNameInFrameError:
...@@ -307,14 +307,14 @@ class CythonBase(object): ...@@ -307,14 +307,14 @@ class CythonBase(object):
if pyframe is None or pyframe.is_optimized_out(): if pyframe is None or pyframe.is_optimized_out():
# print this python function as a C function # print this python function as a C function
return self.print_stackframe(frame, index, is_c=True) return self.print_stackframe(frame, index, is_c=True)
func_name = pyframe.co_name func_name = pyframe.co_name
func_cname = 'PyEval_EvalFrameEx' func_cname = 'PyEval_EvalFrameEx'
func_args = [] func_args = []
elif self.is_cython_function(frame): elif self.is_cython_function(frame):
cyfunc = self.get_cython_function(frame) cyfunc = self.get_cython_function(frame)
f = lambda arg: self.cy.cy_cvalue.invoke(arg, frame=frame) f = lambda arg: self.cy.cy_cvalue.invoke(arg, frame=frame)
func_name = cyfunc.name func_name = cyfunc.name
func_cname = cyfunc.cname func_cname = cyfunc.cname
func_args = [] # [(arg, f(arg)) for arg in cyfunc.arguments] func_args = [] # [(arg, f(arg)) for arg in cyfunc.arguments]
...@@ -323,7 +323,7 @@ class CythonBase(object): ...@@ -323,7 +323,7 @@ class CythonBase(object):
func_name = frame.name() func_name = frame.name()
func_cname = func_name func_cname = func_name
func_args = [] func_args = []
try: try:
gdb_value = gdb.parse_and_eval(func_cname) gdb_value = gdb.parse_and_eval(func_cname)
except RuntimeError: except RuntimeError:
...@@ -331,36 +331,36 @@ class CythonBase(object): ...@@ -331,36 +331,36 @@ class CythonBase(object):
else: else:
# Seriously? Why is the address not an int? # Seriously? Why is the address not an int?
func_address = int(str(gdb_value.address).split()[0], 0) func_address = int(str(gdb_value.address).split()[0], 0)
a = ', '.join('%s=%s' % (name, val) for name, val in func_args) a = ', '.join('%s=%s' % (name, val) for name, val in func_args)
print '#%-2d 0x%016x in %s(%s)' % (index, func_address, func_name, a), print '#%-2d 0x%016x in %s(%s)' % (index, func_address, func_name, a),
if source_desc.filename is not None: if source_desc.filename is not None:
print 'at %s:%s' % (source_desc.filename, lineno), print 'at %s:%s' % (source_desc.filename, lineno),
print print
try: try:
print ' ' + source_desc.get_source(lineno) print ' ' + source_desc.get_source(lineno)
except gdb.GdbError: except gdb.GdbError:
pass pass
selected_frame.select() selected_frame.select()
def get_remote_cython_globals_dict(self): def get_remote_cython_globals_dict(self):
m = gdb.parse_and_eval('__pyx_m') m = gdb.parse_and_eval('__pyx_m')
try: try:
PyModuleObject = gdb.lookup_type('PyModuleObject') PyModuleObject = gdb.lookup_type('PyModuleObject')
except RuntimeError: except RuntimeError:
raise gdb.GdbError(textwrap.dedent("""\ raise gdb.GdbError(textwrap.dedent("""\
Unable to lookup type PyModuleObject, did you compile python Unable to lookup type PyModuleObject, did you compile python
with debugging support (-g)?""")) with debugging support (-g)?"""))
m = m.cast(PyModuleObject.pointer()) m = m.cast(PyModuleObject.pointer())
return m['md_dict'] return m['md_dict']
def get_cython_globals_dict(self): def get_cython_globals_dict(self):
""" """
Get the Cython globals dict where the remote names are turned into Get the Cython globals dict where the remote names are turned into
...@@ -368,12 +368,12 @@ class CythonBase(object): ...@@ -368,12 +368,12 @@ class CythonBase(object):
""" """
remote_dict = self.get_remote_cython_globals_dict() remote_dict = self.get_remote_cython_globals_dict()
pyobject_dict = libpython.PyObjectPtr.from_pyobject_ptr(remote_dict) pyobject_dict = libpython.PyObjectPtr.from_pyobject_ptr(remote_dict)
result = {} result = {}
seen = set() seen = set()
for k, v in pyobject_dict.iteritems(): for k, v in pyobject_dict.iteritems():
result[k.proxyval(seen)] = v result[k.proxyval(seen)] = v
return result return result
def print_gdb_value(self, name, value, max_name_length=None, prefix=''): def print_gdb_value(self, name, value, max_name_length=None, prefix=''):
...@@ -381,11 +381,11 @@ class CythonBase(object): ...@@ -381,11 +381,11 @@ class CythonBase(object):
typename = '' typename = ''
else: else:
typename = '(%s) ' % (value.type,) typename = '(%s) ' % (value.type,)
if max_name_length is None: if max_name_length is None:
print '%s%s = %s%s' % (prefix, name, typename, value) print '%s%s = %s%s' % (prefix, name, typename, value)
else: else:
print '%s%-*s = %s%s' % (prefix, max_name_length, name, typename, print '%s%-*s = %s%s' % (prefix, max_name_length, name, typename,
value) value)
def is_initialized(self, cython_func, local_name): def is_initialized(self, cython_func, local_name):
...@@ -399,7 +399,7 @@ class CythonBase(object): ...@@ -399,7 +399,7 @@ class CythonBase(object):
return long(gdb.parse_and_eval(cyvar.cname)) return long(gdb.parse_and_eval(cyvar.cname))
return True return True
return False return False
cur_lineno = self.get_cython_lineno() cur_lineno = self.get_cython_lineno()
return (local_name in cython_func.arguments or return (local_name in cython_func.arguments or
(islocal and cur_lineno > cyvar.lineno)) (islocal and cur_lineno > cyvar.lineno))
...@@ -430,30 +430,30 @@ class SourceFileDescriptor(object): ...@@ -430,30 +430,30 @@ class SourceFileDescriptor(object):
# to provide "correct" colouring, the entire code needs to be # to provide "correct" colouring, the entire code needs to be
# lexed. However, this makes a lot of things terribly slow, so # lexed. However, this makes a lot of things terribly slow, so
# we decide not to. Besides, it's unlikely to matter. # we decide not to. Besides, it's unlikely to matter.
if lex_source and lex_entire: if lex_source and lex_entire:
f = self.lex(f.read()).splitlines() f = self.lex(f.read()).splitlines()
slice = itertools.islice(f, start - 1, stop - 1) slice = itertools.islice(f, start - 1, stop - 1)
for idx, line in enumerate(slice): for idx, line in enumerate(slice):
if start + idx == mark_line: if start + idx == mark_line:
prefix = '>' prefix = '>'
else: else:
prefix = ' ' prefix = ' '
if lex_source and not lex_entire: if lex_source and not lex_entire:
line = self.lex(line) line = self.lex(line)
yield '%s %4d %s' % (prefix, start + idx, line.rstrip()) yield '%s %4d %s' % (prefix, start + idx, line.rstrip())
def get_source(self, start, stop=None, lex_source=True, mark_line=0, def get_source(self, start, stop=None, lex_source=True, mark_line=0,
lex_entire=False): lex_entire=False):
exc = gdb.GdbError('Unable to retrieve source code') exc = gdb.GdbError('Unable to retrieve source code')
if not self.filename: if not self.filename:
raise exc raise exc
start = max(start, 1) start = max(start, 1)
if stop is None: if stop is None:
stop = start + 1 stop = start + 1
...@@ -471,21 +471,21 @@ class CyGDBError(gdb.GdbError): ...@@ -471,21 +471,21 @@ class CyGDBError(gdb.GdbError):
""" """
Base class for Cython-command related erorrs Base class for Cython-command related erorrs
""" """
def __init__(self, *args): def __init__(self, *args):
args = args or (self.msg,) args = args or (self.msg,)
super(CyGDBError, self).__init__(*args) super(CyGDBError, self).__init__(*args)
class NoCythonFunctionInFrameError(CyGDBError): class NoCythonFunctionInFrameError(CyGDBError):
""" """
raised when the user requests the current cython function, which is raised when the user requests the current cython function, which is
unavailable unavailable
""" """
msg = "Current function is a function cygdb doesn't know about" msg = "Current function is a function cygdb doesn't know about"
class NoFunctionNameInFrameError(NoCythonFunctionInFrameError): class NoFunctionNameInFrameError(NoCythonFunctionInFrameError):
""" """
raised when the name of the C function could not be determined raised when the name of the C function could not be determined
in the current C stack frame in the current C stack frame
""" """
msg = ('C function name could not be determined in the current C stack ' msg = ('C function name could not be determined in the current C stack '
...@@ -498,23 +498,23 @@ class CythonParameter(gdb.Parameter): ...@@ -498,23 +498,23 @@ class CythonParameter(gdb.Parameter):
""" """
Base class for cython parameters Base class for cython parameters
""" """
def __init__(self, name, command_class, parameter_class, default=None): def __init__(self, name, command_class, parameter_class, default=None):
self.show_doc = self.set_doc = self.__class__.__doc__ self.show_doc = self.set_doc = self.__class__.__doc__
super(CythonParameter, self).__init__(name, command_class, super(CythonParameter, self).__init__(name, command_class,
parameter_class) parameter_class)
if default is not None: if default is not None:
self.value = default self.value = default
def __nonzero__(self): def __nonzero__(self):
return bool(self.value) return bool(self.value)
__bool__ = __nonzero__ # python 3 __bool__ = __nonzero__ # python 3
class CompleteUnqualifiedFunctionNames(CythonParameter): class CompleteUnqualifiedFunctionNames(CythonParameter):
""" """
Have 'cy break' complete unqualified function or method names. Have 'cy break' complete unqualified function or method names.
""" """
class ColorizeSourceCode(CythonParameter): class ColorizeSourceCode(CythonParameter):
""" """
...@@ -531,7 +531,7 @@ class CythonParameters(object): ...@@ -531,7 +531,7 @@ class CythonParameters(object):
Simple container class that might get more functionality in the distant Simple container class that might get more functionality in the distant
future (mostly to remind us that we're dealing with parameters). future (mostly to remind us that we're dealing with parameters).
""" """
def __init__(self): def __init__(self):
self.complete_unqualified = CompleteUnqualifiedFunctionNames( self.complete_unqualified = CompleteUnqualifiedFunctionNames(
'cy_complete_unqualified', 'cy_complete_unqualified',
...@@ -548,7 +548,7 @@ class CythonParameters(object): ...@@ -548,7 +548,7 @@ class CythonParameters(object):
gdb.COMMAND_FILES, gdb.COMMAND_FILES,
gdb.PARAM_STRING, gdb.PARAM_STRING,
"dark") "dark")
parameters = CythonParameters() parameters = CythonParameters()
...@@ -558,30 +558,30 @@ class CythonCommand(gdb.Command, CythonBase): ...@@ -558,30 +558,30 @@ class CythonCommand(gdb.Command, CythonBase):
""" """
Base class for Cython commands Base class for Cython commands
""" """
command_class = gdb.COMMAND_NONE command_class = gdb.COMMAND_NONE
@classmethod @classmethod
def _register(cls, clsname, args, kwargs): def _register(cls, clsname, args, kwargs):
if not hasattr(cls, 'completer_class'): if not hasattr(cls, 'completer_class'):
return cls(clsname, cls.command_class, *args, **kwargs) return cls(clsname, cls.command_class, *args, **kwargs)
else: else:
return cls(clsname, cls.command_class, cls.completer_class, return cls(clsname, cls.command_class, cls.completer_class,
*args, **kwargs) *args, **kwargs)
@classmethod @classmethod
def register(cls, *args, **kwargs): def register(cls, *args, **kwargs):
alias = getattr(cls, 'alias', None) alias = getattr(cls, 'alias', None)
if alias: if alias:
cls._register(cls.alias, args, kwargs) cls._register(cls.alias, args, kwargs)
return cls._register(cls.name, args, kwargs) return cls._register(cls.name, args, kwargs)
class CyCy(CythonCommand): class CyCy(CythonCommand):
""" """
Invoke a Cython command. Available commands are: Invoke a Cython command. Available commands are:
cy import cy import
cy break cy break
cy step cy step
...@@ -599,16 +599,16 @@ class CyCy(CythonCommand): ...@@ -599,16 +599,16 @@ class CyCy(CythonCommand):
cy globals cy globals
cy exec cy exec
""" """
name = 'cy' name = 'cy'
command_class = gdb.COMMAND_NONE command_class = gdb.COMMAND_NONE
completer_class = gdb.COMPLETE_COMMAND completer_class = gdb.COMPLETE_COMMAND
def __init__(self, name, command_class, completer_class): def __init__(self, name, command_class, completer_class):
# keep the signature 2.5 compatible (i.e. do not use f(*a, k=v) # keep the signature 2.5 compatible (i.e. do not use f(*a, k=v)
super(CythonCommand, self).__init__(name, command_class, super(CythonCommand, self).__init__(name, command_class,
completer_class, prefix=True) completer_class, prefix=True)
commands = dict( commands = dict(
import_ = CyImport.register(), import_ = CyImport.register(),
break_ = CyBreak.register(), break_ = CyBreak.register(),
...@@ -631,24 +631,24 @@ class CyCy(CythonCommand): ...@@ -631,24 +631,24 @@ class CyCy(CythonCommand):
cy_cvalue = CyCValue('cy_cvalue'), cy_cvalue = CyCValue('cy_cvalue'),
cy_lineno = CyLine('cy_lineno'), cy_lineno = CyLine('cy_lineno'),
) )
for command_name, command in commands.iteritems(): for command_name, command in commands.iteritems():
command.cy = self command.cy = self
setattr(self, command_name, command) setattr(self, command_name, command)
self.cy = self self.cy = self
# Cython module namespace # Cython module namespace
self.cython_namespace = {} self.cython_namespace = {}
# maps (unique) qualified function names (e.g. # maps (unique) qualified function names (e.g.
# cythonmodule.ClassName.method_name) to the CythonFunction object # cythonmodule.ClassName.method_name) to the CythonFunction object
self.functions_by_qualified_name = {} self.functions_by_qualified_name = {}
# unique cnames of Cython functions # unique cnames of Cython functions
self.functions_by_cname = {} self.functions_by_cname = {}
# map function names like method_name to a list of all such # map function names like method_name to a list of all such
# CythonFunction objects # CythonFunction objects
self.functions_by_name = collections.defaultdict(list) self.functions_by_name = collections.defaultdict(list)
...@@ -658,46 +658,46 @@ class CyImport(CythonCommand): ...@@ -658,46 +658,46 @@ class CyImport(CythonCommand):
Import debug information outputted by the Cython compiler Import debug information outputted by the Cython compiler
Example: cy import FILE... Example: cy import FILE...
""" """
name = 'cy import' name = 'cy import'
command_class = gdb.COMMAND_STATUS command_class = gdb.COMMAND_STATUS
completer_class = gdb.COMPLETE_FILENAME completer_class = gdb.COMPLETE_FILENAME
def invoke(self, args, from_tty): def invoke(self, args, from_tty):
args = args.encode(_filesystemencoding) args = args.encode(_filesystemencoding)
for arg in string_to_argv(args): for arg in string_to_argv(args):
try: try:
f = open(arg) f = open(arg)
except OSError, e: except OSError, e:
raise gdb.GdbError('Unable to open file %r: %s' % raise gdb.GdbError('Unable to open file %r: %s' %
(args, e.args[1])) (args, e.args[1]))
t = etree.parse(f) t = etree.parse(f)
for module in t.getroot(): for module in t.getroot():
cython_module = CythonModule(**module.attrib) cython_module = CythonModule(**module.attrib)
self.cy.cython_namespace[cython_module.name] = cython_module self.cy.cython_namespace[cython_module.name] = cython_module
for variable in module.find('Globals'): for variable in module.find('Globals'):
d = variable.attrib d = variable.attrib
cython_module.globals[d['name']] = CythonVariable(**d) cython_module.globals[d['name']] = CythonVariable(**d)
for function in module.find('Functions'): for function in module.find('Functions'):
cython_function = CythonFunction(module=cython_module, cython_function = CythonFunction(module=cython_module,
**function.attrib) **function.attrib)
# update the global function mappings # update the global function mappings
name = cython_function.name name = cython_function.name
qname = cython_function.qualified_name qname = cython_function.qualified_name
self.cy.functions_by_name[name].append(cython_function) self.cy.functions_by_name[name].append(cython_function)
self.cy.functions_by_qualified_name[ self.cy.functions_by_qualified_name[
cython_function.qualified_name] = cython_function cython_function.qualified_name] = cython_function
self.cy.functions_by_cname[ self.cy.functions_by_cname[
cython_function.cname] = cython_function cython_function.cname] = cython_function
d = cython_module.functions[qname] = cython_function d = cython_module.functions[qname] = cython_function
for local in function.find('Locals'): for local in function.find('Locals'):
d = local.attrib d = local.attrib
cython_function.locals[d['name']] = CythonVariable(**d) cython_function.locals[d['name']] = CythonVariable(**d)
...@@ -705,7 +705,7 @@ class CyImport(CythonCommand): ...@@ -705,7 +705,7 @@ class CyImport(CythonCommand):
for step_into_func in function.find('StepIntoFunctions'): for step_into_func in function.find('StepIntoFunctions'):
d = step_into_func.attrib d = step_into_func.attrib
cython_function.step_into_functions.add(d['name']) cython_function.step_into_functions.add(d['name'])
cython_function.arguments.extend( cython_function.arguments.extend(
funcarg.tag for funcarg in function.find('Arguments')) funcarg.tag for funcarg in function.find('Arguments'))
...@@ -720,30 +720,30 @@ class CyImport(CythonCommand): ...@@ -720,30 +720,30 @@ class CyImport(CythonCommand):
class CyBreak(CythonCommand): class CyBreak(CythonCommand):
""" """
Set a breakpoint for Cython code using Cython qualified name notation, e.g.: Set a breakpoint for Cython code using Cython qualified name notation, e.g.:
cy break cython_modulename.ClassName.method_name... cy break cython_modulename.ClassName.method_name...
or normal notation: or normal notation:
cy break function_or_method_name... cy break function_or_method_name...
or for a line number: or for a line number:
cy break cython_module:lineno... cy break cython_module:lineno...
Set a Python breakpoint: Set a Python breakpoint:
Break on any function or method named 'func' in module 'modname' Break on any function or method named 'func' in module 'modname'
cy break -p modname.func... cy break -p modname.func...
Break on any function or method named 'func' Break on any function or method named 'func'
cy break -p func... cy break -p func...
""" """
name = 'cy break' name = 'cy break'
command_class = gdb.COMMAND_BREAKPOINTS command_class = gdb.COMMAND_BREAKPOINTS
def _break_pyx(self, name): def _break_pyx(self, name):
modulename, _, lineno = name.partition(':') modulename, _, lineno = name.partition(':')
lineno = int(lineno) lineno = int(lineno)
...@@ -759,29 +759,29 @@ class CyBreak(CythonCommand): ...@@ -759,29 +759,29 @@ class CyBreak(CythonCommand):
else: else:
raise GdbError("Not a valid line number. " raise GdbError("Not a valid line number. "
"Does it contain actual code?") "Does it contain actual code?")
def _break_funcname(self, funcname): def _break_funcname(self, funcname):
func = self.cy.functions_by_qualified_name.get(funcname) func = self.cy.functions_by_qualified_name.get(funcname)
if func and func.is_initmodule_function: if func and func.is_initmodule_function:
func = None func = None
break_funcs = [func] break_funcs = [func]
if not func: if not func:
funcs = self.cy.functions_by_name.get(funcname) or [] funcs = self.cy.functions_by_name.get(funcname) or []
funcs = [f for f in funcs if not f.is_initmodule_function] funcs = [f for f in funcs if not f.is_initmodule_function]
if not funcs: if not funcs:
gdb.execute('break ' + funcname) gdb.execute('break ' + funcname)
return return
if len(funcs) > 1: if len(funcs) > 1:
# multiple functions, let the user pick one # multiple functions, let the user pick one
print 'There are multiple such functions:' print 'There are multiple such functions:'
for idx, func in enumerate(funcs): for idx, func in enumerate(funcs):
print '%3d) %s' % (idx, func.qualified_name) print '%3d) %s' % (idx, func.qualified_name)
while True: while True:
try: try:
result = raw_input( result = raw_input(
...@@ -795,7 +795,7 @@ class CyBreak(CythonCommand): ...@@ -795,7 +795,7 @@ class CyBreak(CythonCommand):
elif result.lower() == 'a': elif result.lower() == 'a':
break_funcs = funcs break_funcs = funcs
break break
elif (result.isdigit() and elif (result.isdigit() and
0 <= int(result) < len(funcs)): 0 <= int(result) < len(funcs)):
break_funcs = [funcs[int(result)]] break_funcs = [funcs[int(result)]]
break break
...@@ -803,12 +803,12 @@ class CyBreak(CythonCommand): ...@@ -803,12 +803,12 @@ class CyBreak(CythonCommand):
print 'Not understood...' print 'Not understood...'
else: else:
break_funcs = [funcs[0]] break_funcs = [funcs[0]]
for func in break_funcs: for func in break_funcs:
gdb.execute('break %s' % func.cname) gdb.execute('break %s' % func.cname)
if func.pf_cname: if func.pf_cname:
gdb.execute('break %s' % func.pf_cname) gdb.execute('break %s' % func.pf_cname)
def invoke(self, function_names, from_tty): def invoke(self, function_names, from_tty):
argv = string_to_argv(function_names.encode('UTF-8')) argv = string_to_argv(function_names.encode('UTF-8'))
if function_names.startswith('-p'): if function_names.startswith('-p'):
...@@ -816,7 +816,7 @@ class CyBreak(CythonCommand): ...@@ -816,7 +816,7 @@ class CyBreak(CythonCommand):
python_breakpoints = True python_breakpoints = True
else: else:
python_breakpoints = False python_breakpoints = False
for funcname in argv: for funcname in argv:
if python_breakpoints: if python_breakpoints:
gdb.execute('py-break %s' % funcname) gdb.execute('py-break %s' % funcname)
...@@ -824,16 +824,16 @@ class CyBreak(CythonCommand): ...@@ -824,16 +824,16 @@ class CyBreak(CythonCommand):
self._break_pyx(funcname) self._break_pyx(funcname)
else: else:
self._break_funcname(funcname) self._break_funcname(funcname)
@dont_suppress_errors @dont_suppress_errors
def complete(self, text, word): def complete(self, text, word):
# Filter init-module functions (breakpoints can be set using # Filter init-module functions (breakpoints can be set using
# modulename:linenumber). # modulename:linenumber).
names = [n for n, L in self.cy.functions_by_name.iteritems() names = [n for n, L in self.cy.functions_by_name.iteritems()
if any(not f.is_initmodule_function for f in L)] if any(not f.is_initmodule_function for f in L)]
qnames = [n for n, f in self.cy.functions_by_qualified_name.iteritems() qnames = [n for n, f in self.cy.functions_by_qualified_name.iteritems()
if not f.is_initmodule_function] if not f.is_initmodule_function]
if parameters.complete_unqualified: if parameters.complete_unqualified:
all_names = itertools.chain(qnames, names) all_names = itertools.chain(qnames, names)
else: else:
...@@ -843,19 +843,19 @@ class CyBreak(CythonCommand): ...@@ -843,19 +843,19 @@ class CyBreak(CythonCommand):
if not words or '.' not in words[-1]: if not words or '.' not in words[-1]:
# complete unqualified # complete unqualified
seen = set(text[:-len(word)].split()) seen = set(text[:-len(word)].split())
return [n for n in all_names return [n for n in all_names
if n.startswith(word) and n not in seen] if n.startswith(word) and n not in seen]
# complete qualified name # complete qualified name
lastword = words[-1] lastword = words[-1]
compl = [n for n in qnames if n.startswith(lastword)] compl = [n for n in qnames if n.startswith(lastword)]
if len(lastword) > len(word): if len(lastword) > len(word):
# readline sees something (e.g. a '.') as a word boundary, so don't # readline sees something (e.g. a '.') as a word boundary, so don't
# "recomplete" this prefix # "recomplete" this prefix
strip_prefix_length = len(lastword) - len(word) strip_prefix_length = len(lastword) - len(word)
compl = [n[strip_prefix_length:] for n in compl] compl = [n[strip_prefix_length:] for n in compl]
return compl return compl
...@@ -863,7 +863,7 @@ class CythonInfo(CythonBase, libpython.PythonInfo): ...@@ -863,7 +863,7 @@ class CythonInfo(CythonBase, libpython.PythonInfo):
""" """
Implementation of the interface dictated by libpython.LanguageInfo. Implementation of the interface dictated by libpython.LanguageInfo.
""" """
def lineno(self, frame): def lineno(self, frame):
# Take care of the Python and Cython levels. We need to care for both # Take care of the Python and Cython levels. We need to care for both
# as we can't simply dispath to 'py-step', since that would work for # as we can't simply dispath to 'py-step', since that would work for
...@@ -872,7 +872,7 @@ class CythonInfo(CythonBase, libpython.PythonInfo): ...@@ -872,7 +872,7 @@ class CythonInfo(CythonBase, libpython.PythonInfo):
if self.is_cython_function(frame): if self.is_cython_function(frame):
return self.get_cython_lineno(frame) return self.get_cython_lineno(frame)
return super(CythonInfo, self).lineno(frame) return super(CythonInfo, self).lineno(frame)
def get_source_line(self, frame): def get_source_line(self, frame):
try: try:
line = super(CythonInfo, self).get_source_line(frame) line = super(CythonInfo, self).get_source_line(frame)
...@@ -889,16 +889,16 @@ class CythonInfo(CythonBase, libpython.PythonInfo): ...@@ -889,16 +889,16 @@ class CythonInfo(CythonBase, libpython.PythonInfo):
if self.is_cython_function(): if self.is_cython_function():
return self.get_cython_function().step_into_functions return self.get_cython_function().step_into_functions
return () return ()
def static_break_functions(self): def static_break_functions(self):
result = ['PyEval_EvalFrameEx'] result = ['PyEval_EvalFrameEx']
result.extend(self.cy.functions_by_cname) result.extend(self.cy.functions_by_cname)
return result return result
class CythonExecutionControlCommand(CythonCommand, class CythonExecutionControlCommand(CythonCommand,
libpython.ExecutionControlCommandBase): libpython.ExecutionControlCommandBase):
@classmethod @classmethod
def register(cls): def register(cls):
return cls(cls.name, cython_info) return cls(cls.name, cython_info)
...@@ -906,10 +906,10 @@ class CythonExecutionControlCommand(CythonCommand, ...@@ -906,10 +906,10 @@ class CythonExecutionControlCommand(CythonCommand,
class CyStep(CythonExecutionControlCommand, libpython.PythonStepperMixin): class CyStep(CythonExecutionControlCommand, libpython.PythonStepperMixin):
"Step through Cython, Python or C code." "Step through Cython, Python or C code."
name = 'cy -step' name = 'cy -step'
stepinto = True stepinto = True
def invoke(self, args, from_tty): def invoke(self, args, from_tty):
if self.is_python_function(): if self.is_python_function():
self.python_step(self.stepinto) self.python_step(self.stepinto)
...@@ -918,7 +918,7 @@ class CyStep(CythonExecutionControlCommand, libpython.PythonStepperMixin): ...@@ -918,7 +918,7 @@ class CyStep(CythonExecutionControlCommand, libpython.PythonStepperMixin):
command = 'step' command = 'step'
else: else:
command = 'next' command = 'next'
self.finish_executing(gdb.execute(command, to_string=True)) self.finish_executing(gdb.execute(command, to_string=True))
else: else:
self.step(stepinto=self.stepinto) self.step(stepinto=self.stepinto)
...@@ -933,21 +933,21 @@ class CyNext(CyStep): ...@@ -933,21 +933,21 @@ class CyNext(CyStep):
class CyRun(CythonExecutionControlCommand): class CyRun(CythonExecutionControlCommand):
""" """
Run a Cython program. This is like the 'run' command, except that it Run a Cython program. This is like the 'run' command, except that it
displays Cython or Python source lines as well displays Cython or Python source lines as well
""" """
name = 'cy run' name = 'cy run'
invoke = CythonExecutionControlCommand.run invoke = CythonExecutionControlCommand.run
class CyCont(CythonExecutionControlCommand): class CyCont(CythonExecutionControlCommand):
""" """
Continue a Cython program. This is like the 'run' command, except that it Continue a Cython program. This is like the 'run' command, except that it
displays Cython or Python source lines as well. displays Cython or Python source lines as well.
""" """
name = 'cy cont' name = 'cy cont'
invoke = CythonExecutionControlCommand.cont invoke = CythonExecutionControlCommand.cont
...@@ -967,7 +967,7 @@ class CyUp(CythonCommand): ...@@ -967,7 +967,7 @@ class CyUp(CythonCommand):
""" """
name = 'cy up' name = 'cy up'
_command = 'up' _command = 'up'
def invoke(self, *args): def invoke(self, *args):
try: try:
gdb.execute(self._command, to_string=True) gdb.execute(self._command, to_string=True)
...@@ -975,13 +975,13 @@ class CyUp(CythonCommand): ...@@ -975,13 +975,13 @@ class CyUp(CythonCommand):
gdb.execute(self._command, to_string=True) gdb.execute(self._command, to_string=True)
except RuntimeError, e: except RuntimeError, e:
raise gdb.GdbError(*e.args) raise gdb.GdbError(*e.args)
frame = gdb.selected_frame() frame = gdb.selected_frame()
index = 0 index = 0
while frame: while frame:
frame = frame.older() frame = frame.older()
index += 1 index += 1
self.print_stackframe(index=index - 1) self.print_stackframe(index=index - 1)
...@@ -989,7 +989,7 @@ class CyDown(CyUp): ...@@ -989,7 +989,7 @@ class CyDown(CyUp):
""" """
Go down a Cython, Python or relevant C frame. Go down a Cython, Python or relevant C frame.
""" """
name = 'cy down' name = 'cy down'
_command = 'down' _command = 'down'
...@@ -999,21 +999,21 @@ class CySelect(CythonCommand): ...@@ -999,21 +999,21 @@ class CySelect(CythonCommand):
Select a frame. Use frame numbers as listed in `cy backtrace`. Select a frame. Use frame numbers as listed in `cy backtrace`.
This command is useful because `cy backtrace` prints a reversed backtrace. This command is useful because `cy backtrace` prints a reversed backtrace.
""" """
name = 'cy select' name = 'cy select'
def invoke(self, stackno, from_tty): def invoke(self, stackno, from_tty):
try: try:
stackno = int(stackno) stackno = int(stackno)
except ValueError: except ValueError:
raise gdb.GdbError("Not a valid number: %r" % (stackno,)) raise gdb.GdbError("Not a valid number: %r" % (stackno,))
frame = gdb.selected_frame() frame = gdb.selected_frame()
while frame.newer(): while frame.newer():
frame = frame.newer() frame = frame.newer()
stackdepth = libpython.stackdepth(frame) stackdepth = libpython.stackdepth(frame)
try: try:
gdb.execute('select %d' % (stackdepth - stackno - 1,)) gdb.execute('select %d' % (stackdepth - stackno - 1,))
except RuntimeError, e: except RuntimeError, e:
...@@ -1022,37 +1022,37 @@ class CySelect(CythonCommand): ...@@ -1022,37 +1022,37 @@ class CySelect(CythonCommand):
class CyBacktrace(CythonCommand): class CyBacktrace(CythonCommand):
'Print the Cython stack' 'Print the Cython stack'
name = 'cy bt' name = 'cy bt'
alias = 'cy backtrace' alias = 'cy backtrace'
command_class = gdb.COMMAND_STACK command_class = gdb.COMMAND_STACK
completer_class = gdb.COMPLETE_NONE completer_class = gdb.COMPLETE_NONE
@require_running_program @require_running_program
def invoke(self, args, from_tty): def invoke(self, args, from_tty):
# get the first frame # get the first frame
selected_frame = frame = gdb.selected_frame() selected_frame = frame = gdb.selected_frame()
while frame.older(): while frame.older():
frame = frame.older() frame = frame.older()
print_all = args == '-a' print_all = args == '-a'
index = 0 index = 0
while frame: while frame:
is_c = False is_c = False
is_relevant = False is_relevant = False
try: try:
is_relevant = self.is_relevant_function(frame) is_relevant = self.is_relevant_function(frame)
except CyGDBError: except CyGDBError:
pass pass
if print_all or is_relevant: if print_all or is_relevant:
self.print_stackframe(frame, index) self.print_stackframe(frame, index)
index += 1 index += 1
frame = frame.newer() frame = frame.newer()
selected_frame.select() selected_frame.select()
...@@ -1061,15 +1061,15 @@ class CyList(CythonCommand): ...@@ -1061,15 +1061,15 @@ class CyList(CythonCommand):
List Cython source code. To disable to customize colouring see the cy_* List Cython source code. To disable to customize colouring see the cy_*
parameters. parameters.
""" """
name = 'cy list' name = 'cy list'
command_class = gdb.COMMAND_FILES command_class = gdb.COMMAND_FILES
completer_class = gdb.COMPLETE_NONE completer_class = gdb.COMPLETE_NONE
# @dispatch_on_frame(c_command='list') # @dispatch_on_frame(c_command='list')
def invoke(self, _, from_tty): def invoke(self, _, from_tty):
sd, lineno = self.get_source_desc() sd, lineno = self.get_source_desc()
source = sd.get_source(lineno - 5, lineno + 5, mark_line=lineno, source = sd.get_source(lineno - 5, lineno + 5, mark_line=lineno,
lex_entire=True) lex_entire=True)
print source print source
...@@ -1078,10 +1078,10 @@ class CyPrint(CythonCommand): ...@@ -1078,10 +1078,10 @@ class CyPrint(CythonCommand):
""" """
Print a Cython variable using 'cy-print x' or 'cy-print module.function.x' Print a Cython variable using 'cy-print x' or 'cy-print module.function.x'
""" """
name = 'cy print' name = 'cy print'
command_class = gdb.COMMAND_DATA command_class = gdb.COMMAND_DATA
def invoke(self, name, from_tty, max_name_length=None): def invoke(self, name, from_tty, max_name_length=None):
if self.is_python_function(): if self.is_python_function():
return gdb.execute('py-print ' + name) return gdb.execute('py-print ' + name)
...@@ -1092,11 +1092,11 @@ class CyPrint(CythonCommand): ...@@ -1092,11 +1092,11 @@ class CyPrint(CythonCommand):
value = value.dereference() value = value.dereference()
else: else:
break break
self.print_gdb_value(name, value, max_name_length) self.print_gdb_value(name, value, max_name_length)
else: else:
gdb.execute('print ' + name) gdb.execute('print ' + name)
def complete(self): def complete(self):
if self.is_cython_function(): if self.is_cython_function():
f = self.get_cython_function() f = self.get_cython_function()
...@@ -1111,15 +1111,15 @@ class CyLocals(CythonCommand): ...@@ -1111,15 +1111,15 @@ class CyLocals(CythonCommand):
""" """
List the locals from the current Cython frame. List the locals from the current Cython frame.
""" """
name = 'cy locals' name = 'cy locals'
command_class = gdb.COMMAND_STACK command_class = gdb.COMMAND_STACK
completer_class = gdb.COMPLETE_NONE completer_class = gdb.COMPLETE_NONE
@dispatch_on_frame(c_command='info locals', python_command='py-locals') @dispatch_on_frame(c_command='info locals', python_command='py-locals')
def invoke(self, args, from_tty): def invoke(self, args, from_tty):
cython_function = self.get_cython_function() cython_function = self.get_cython_function()
if cython_function.is_initmodule_function: if cython_function.is_initmodule_function:
self.cy.globals.invoke(args, from_tty) self.cy.globals.invoke(args, from_tty)
return return
...@@ -1130,7 +1130,7 @@ class CyLocals(CythonCommand): ...@@ -1130,7 +1130,7 @@ class CyLocals(CythonCommand):
if self.is_initialized(self.get_cython_function(), cyvar.name): if self.is_initialized(self.get_cython_function(), cyvar.name):
value = gdb.parse_and_eval(cyvar.cname) value = gdb.parse_and_eval(cyvar.cname)
if not value.is_optimized_out: if not value.is_optimized_out:
self.print_gdb_value(cyvar.name, value, self.print_gdb_value(cyvar.name, value,
max_name_length, '') max_name_length, '')
...@@ -1138,32 +1138,32 @@ class CyGlobals(CyLocals): ...@@ -1138,32 +1138,32 @@ class CyGlobals(CyLocals):
""" """
List the globals from the current Cython module. List the globals from the current Cython module.
""" """
name = 'cy globals' name = 'cy globals'
command_class = gdb.COMMAND_STACK command_class = gdb.COMMAND_STACK
completer_class = gdb.COMPLETE_NONE completer_class = gdb.COMPLETE_NONE
@dispatch_on_frame(c_command='info variables', python_command='py-globals') @dispatch_on_frame(c_command='info variables', python_command='py-globals')
def invoke(self, args, from_tty): def invoke(self, args, from_tty):
global_python_dict = self.get_cython_globals_dict() global_python_dict = self.get_cython_globals_dict()
module_globals = self.get_cython_function().module.globals module_globals = self.get_cython_function().module.globals
max_globals_len = 0 max_globals_len = 0
max_globals_dict_len = 0 max_globals_dict_len = 0
if module_globals: if module_globals:
max_globals_len = len(max(module_globals, key=len)) max_globals_len = len(max(module_globals, key=len))
if global_python_dict: if global_python_dict:
max_globals_dict_len = len(max(global_python_dict)) max_globals_dict_len = len(max(global_python_dict))
max_name_length = max(max_globals_len, max_globals_dict_len) max_name_length = max(max_globals_len, max_globals_dict_len)
seen = set() seen = set()
print 'Python globals:' print 'Python globals:'
for k, v in sorted(global_python_dict.iteritems(), key=sortkey): for k, v in sorted(global_python_dict.iteritems(), key=sortkey):
v = v.get_truncated_repr(libpython.MAX_OUTPUT_LEN) v = v.get_truncated_repr(libpython.MAX_OUTPUT_LEN)
seen.add(k) seen.add(k)
print ' %-*s = %s' % (max_name_length, k, v) print ' %-*s = %s' % (max_name_length, k, v)
print 'C globals:' print 'C globals:'
for name, cyvar in sorted(module_globals.iteritems(), key=sortkey): for name, cyvar in sorted(module_globals.iteritems(), key=sortkey):
if name not in seen: if name not in seen:
...@@ -1181,20 +1181,20 @@ class CyExec(CythonCommand, libpython.PyExec): ...@@ -1181,20 +1181,20 @@ class CyExec(CythonCommand, libpython.PyExec):
""" """
Execute Python code in the nearest Python or Cython frame. Execute Python code in the nearest Python or Cython frame.
""" """
name = '-cy-exec' name = '-cy-exec'
command_class = gdb.COMMAND_STACK command_class = gdb.COMMAND_STACK
completer_class = gdb.COMPLETE_NONE completer_class = gdb.COMPLETE_NONE
def _fill_locals_dict(self, executor, local_dict_pointer): def _fill_locals_dict(self, executor, local_dict_pointer):
"Fill a remotely allocated dict with values from the Cython C stack" "Fill a remotely allocated dict with values from the Cython C stack"
cython_func = self.get_cython_function() cython_func = self.get_cython_function()
current_lineno = self.get_cython_lineno() current_lineno = self.get_cython_lineno()
for name, cyvar in cython_func.locals.iteritems(): for name, cyvar in cython_func.locals.iteritems():
if (cyvar.type == PythonObject and if (cyvar.type == PythonObject and
self.is_initialized(cython_func, name)): self.is_initialized(cython_func, name)):
try: try:
val = gdb.parse_and_eval(cyvar.cname) val = gdb.parse_and_eval(cyvar.cname)
except RuntimeError: except RuntimeError:
...@@ -1202,7 +1202,7 @@ class CyExec(CythonCommand, libpython.PyExec): ...@@ -1202,7 +1202,7 @@ class CyExec(CythonCommand, libpython.PyExec):
else: else:
if val.is_optimized_out: if val.is_optimized_out:
continue continue
pystringp = executor.alloc_pystring(name) pystringp = executor.alloc_pystring(name)
code = ''' code = '''
(PyObject *) PyDict_SetItem( (PyObject *) PyDict_SetItem(
...@@ -1218,38 +1218,38 @@ class CyExec(CythonCommand, libpython.PyExec): ...@@ -1218,38 +1218,38 @@ class CyExec(CythonCommand, libpython.PyExec):
finally: finally:
# PyDict_SetItem doesn't steal our reference # PyDict_SetItem doesn't steal our reference
executor.decref(pystringp) executor.decref(pystringp)
def _find_first_cython_or_python_frame(self): def _find_first_cython_or_python_frame(self):
frame = gdb.selected_frame() frame = gdb.selected_frame()
while frame: while frame:
if (self.is_cython_function(frame) or if (self.is_cython_function(frame) or
self.is_python_function(frame)): self.is_python_function(frame)):
return frame return frame
frame = frame.older() frame = frame.older()
raise gdb.GdbError("There is no Cython or Python frame on the stack.") raise gdb.GdbError("There is no Cython or Python frame on the stack.")
def invoke(self, expr, from_tty): def invoke(self, expr, from_tty):
frame = self._find_first_cython_or_python_frame() frame = self._find_first_cython_or_python_frame()
if self.is_python_function(frame): if self.is_python_function(frame):
libpython.py_exec.invoke(expr, from_tty) libpython.py_exec.invoke(expr, from_tty)
return return
expr, input_type = self.readcode(expr) expr, input_type = self.readcode(expr)
executor = libpython.PythonCodeExecutor() executor = libpython.PythonCodeExecutor()
with libpython.FetchAndRestoreError(): with libpython.FetchAndRestoreError():
# get the dict of Cython globals and construct a dict in the # get the dict of Cython globals and construct a dict in the
# inferior with Cython locals # inferior with Cython locals
global_dict = gdb.parse_and_eval( global_dict = gdb.parse_and_eval(
'(PyObject *) PyModule_GetDict(__pyx_m)') '(PyObject *) PyModule_GetDict(__pyx_m)')
local_dict = gdb.parse_and_eval('(PyObject *) PyDict_New()') local_dict = gdb.parse_and_eval('(PyObject *) PyDict_New()')
cython_function = self.get_cython_function() cython_function = self.get_cython_function()
try: try:
self._fill_locals_dict(executor, self._fill_locals_dict(executor,
libpython.pointervalue(local_dict)) libpython.pointervalue(local_dict))
executor.evalcode(expr, input_type, global_dict, local_dict) executor.evalcode(expr, input_type, global_dict, local_dict)
finally: finally:
...@@ -1262,18 +1262,18 @@ class CyCName(gdb.Function, CythonBase): ...@@ -1262,18 +1262,18 @@ class CyCName(gdb.Function, CythonBase):
""" """
Get the C name of a Cython variable in the current context. Get the C name of a Cython variable in the current context.
Examples: Examples:
print $cy_cname("function") print $cy_cname("function")
print $cy_cname("Class.method") print $cy_cname("Class.method")
print $cy_cname("module.function") print $cy_cname("module.function")
""" """
@require_cython_frame @require_cython_frame
@gdb_function_value_to_unicode @gdb_function_value_to_unicode
def invoke(self, cyname, frame=None): def invoke(self, cyname, frame=None):
frame = frame or gdb.selected_frame() frame = frame or gdb.selected_frame()
cname = None cname = None
if self.is_cython_function(frame): if self.is_cython_function(frame):
cython_function = self.get_cython_function(frame) cython_function = self.get_cython_function(frame)
if cyname in cython_function.locals: if cyname in cython_function.locals:
...@@ -1284,13 +1284,13 @@ class CyCName(gdb.Function, CythonBase): ...@@ -1284,13 +1284,13 @@ class CyCName(gdb.Function, CythonBase):
qname = '%s.%s' % (cython_function.module.name, cyname) qname = '%s.%s' % (cython_function.module.name, cyname)
if qname in cython_function.module.functions: if qname in cython_function.module.functions:
cname = cython_function.module.functions[qname].cname cname = cython_function.module.functions[qname].cname
if not cname: if not cname:
cname = self.cy.functions_by_qualified_name.get(cyname) cname = self.cy.functions_by_qualified_name.get(cyname)
if not cname: if not cname:
raise gdb.GdbError('No such Cython variable: %s' % cyname) raise gdb.GdbError('No such Cython variable: %s' % cyname)
return cname return cname
...@@ -1298,7 +1298,7 @@ class CyCValue(CyCName): ...@@ -1298,7 +1298,7 @@ class CyCValue(CyCName):
""" """
Get the value of a Cython variable. Get the value of a Cython variable.
""" """
@require_cython_frame @require_cython_frame
@gdb_function_value_to_unicode @gdb_function_value_to_unicode
def invoke(self, cyname, frame=None): def invoke(self, cyname, frame=None):
...@@ -1318,7 +1318,7 @@ class CyLine(gdb.Function, CythonBase): ...@@ -1318,7 +1318,7 @@ class CyLine(gdb.Function, CythonBase):
""" """
Get the current Cython line. Get the current Cython line.
""" """
@require_cython_frame @require_cython_frame
def invoke(self): def invoke(self):
return self.get_cython_lineno() return self.get_cython_lineno()
...@@ -1332,18 +1332,18 @@ def register_defines(): ...@@ -1332,18 +1332,18 @@ def register_defines():
define cy step define cy step
cy -step cy -step
end end
define cy next define cy next
cy -next cy -next
end end
document cy step document cy step
%s %s
end end
document cy next document cy next
%s %s
end end
""") % (CyStep.__doc__, CyNext.__doc__)) """) % (CyStep.__doc__, CyNext.__doc__))
register_defines() register_defines()
\ No newline at end of file
...@@ -162,7 +162,7 @@ class TruncatedStringIO(object): ...@@ -162,7 +162,7 @@ class TruncatedStringIO(object):
all_pretty_typenames = set() all_pretty_typenames = set()
class PrettyPrinterTrackerMeta(type): class PrettyPrinterTrackerMeta(type):
def __init__(self, name, bases, dict): def __init__(self, name, bases, dict):
super(PrettyPrinterTrackerMeta, self).__init__(name, bases, dict) super(PrettyPrinterTrackerMeta, self).__init__(name, bases, dict)
all_pretty_typenames.add(self._typename) all_pretty_typenames.add(self._typename)
...@@ -179,11 +179,11 @@ class PyObjectPtr(object): ...@@ -179,11 +179,11 @@ class PyObjectPtr(object):
Note that at every stage the underlying pointer could be NULL, point Note that at every stage the underlying pointer could be NULL, point
to corrupt data, etc; this is the debugger, after all. to corrupt data, etc; this is the debugger, after all.
""" """
__metaclass__ = PrettyPrinterTrackerMeta __metaclass__ = PrettyPrinterTrackerMeta
_typename = 'PyObject' _typename = 'PyObject'
def __init__(self, gdbval, cast_to=None): def __init__(self, gdbval, cast_to=None):
if cast_to: if cast_to:
self._gdbval = gdbval.cast(cast_to) self._gdbval = gdbval.cast(cast_to)
...@@ -356,7 +356,7 @@ class PyObjectPtr(object): ...@@ -356,7 +356,7 @@ class PyObjectPtr(object):
#print 'tp_flags = 0x%08x' % tp_flags #print 'tp_flags = 0x%08x' % tp_flags
#print 'tp_name = %r' % tp_name #print 'tp_name = %r' % tp_name
name_map = {'bool': PyBoolObjectPtr, name_map = {'bool': PyBoolObjectPtr,
'classobj': PyClassObjectPtr, 'classobj': PyClassObjectPtr,
'instance': PyInstanceObjectPtr, 'instance': PyInstanceObjectPtr,
...@@ -368,7 +368,7 @@ class PyObjectPtr(object): ...@@ -368,7 +368,7 @@ class PyObjectPtr(object):
} }
if tp_name in name_map: if tp_name in name_map:
return name_map[tp_name] return name_map[tp_name]
if tp_flags & (Py_TPFLAGS_HEAPTYPE|Py_TPFLAGS_TYPE_SUBCLASS): if tp_flags & (Py_TPFLAGS_HEAPTYPE|Py_TPFLAGS_TYPE_SUBCLASS):
return PyTypeObjectPtr return PyTypeObjectPtr
...@@ -484,7 +484,7 @@ def _PyObject_VAR_SIZE(typeobj, nitems): ...@@ -484,7 +484,7 @@ def _PyObject_VAR_SIZE(typeobj, nitems):
class PyTypeObjectPtr(PyObjectPtr): class PyTypeObjectPtr(PyObjectPtr):
_typename = 'PyTypeObject' _typename = 'PyTypeObject'
def get_attr_dict(self): def get_attr_dict(self):
''' '''
Get the PyDictObject ptr representing the attribute dictionary Get the PyDictObject ptr representing the attribute dictionary
...@@ -543,13 +543,13 @@ class PyTypeObjectPtr(PyObjectPtr): ...@@ -543,13 +543,13 @@ class PyTypeObjectPtr(PyObjectPtr):
out.write('<...>') out.write('<...>')
return return
visited.add(self.as_address()) visited.add(self.as_address())
try: try:
tp_name = self.field('tp_name').string() tp_name = self.field('tp_name').string()
except RuntimeError: except RuntimeError:
tp_name = 'unknown' tp_name = 'unknown'
out.write('<type %s at remote 0x%x>' % (tp_name, out.write('<type %s at remote 0x%x>' % (tp_name,
self.as_address())) self.as_address()))
# pyop_attrdict = self.get_attr_dict() # pyop_attrdict = self.get_attr_dict()
# _write_instance_repr(out, visited, # _write_instance_repr(out, visited,
...@@ -569,7 +569,7 @@ class PyBaseExceptionObjectPtr(PyObjectPtr): ...@@ -569,7 +569,7 @@ class PyBaseExceptionObjectPtr(PyObjectPtr):
within the process being debugged. within the process being debugged.
""" """
_typename = 'PyBaseExceptionObject' _typename = 'PyBaseExceptionObject'
def proxyval(self, visited): def proxyval(self, visited):
# Guard against infinite loops: # Guard against infinite loops:
if self.as_address() in visited: if self.as_address() in visited:
...@@ -682,7 +682,7 @@ class PyDictObjectPtr(PyObjectPtr): ...@@ -682,7 +682,7 @@ class PyDictObjectPtr(PyObjectPtr):
if not pyop_value.is_null(): if not pyop_value.is_null():
pyop_key = PyObjectPtr.from_pyobject_ptr(ep['me_key']) pyop_key = PyObjectPtr.from_pyobject_ptr(ep['me_key'])
yield (pyop_key, pyop_value) yield (pyop_key, pyop_value)
def proxyval(self, visited): def proxyval(self, visited):
# Guard against infinite loops: # Guard against infinite loops:
if self.as_address() in visited: if self.as_address() in visited:
...@@ -716,7 +716,7 @@ class PyDictObjectPtr(PyObjectPtr): ...@@ -716,7 +716,7 @@ class PyDictObjectPtr(PyObjectPtr):
class PyInstanceObjectPtr(PyObjectPtr): class PyInstanceObjectPtr(PyObjectPtr):
_typename = 'PyInstanceObject' _typename = 'PyInstanceObject'
def proxyval(self, visited): def proxyval(self, visited):
# Guard against infinite loops: # Guard against infinite loops:
if self.as_address() in visited: if self.as_address() in visited:
...@@ -761,7 +761,7 @@ class PyIntObjectPtr(PyObjectPtr): ...@@ -761,7 +761,7 @@ class PyIntObjectPtr(PyObjectPtr):
class PyListObjectPtr(PyObjectPtr): class PyListObjectPtr(PyObjectPtr):
_typename = 'PyListObject' _typename = 'PyListObject'
def __getitem__(self, i): def __getitem__(self, i):
# Get the gdb.Value for the (PyObject*) with the given index: # Get the gdb.Value for the (PyObject*) with the given index:
field_ob_item = self.field('ob_item') field_ob_item = self.field('ob_item')
...@@ -794,7 +794,7 @@ class PyListObjectPtr(PyObjectPtr): ...@@ -794,7 +794,7 @@ class PyListObjectPtr(PyObjectPtr):
class PyLongObjectPtr(PyObjectPtr): class PyLongObjectPtr(PyObjectPtr):
_typename = 'PyLongObject' _typename = 'PyLongObject'
def proxyval(self, visited): def proxyval(self, visited):
''' '''
Python's Include/longobjrep.h has this declaration: Python's Include/longobjrep.h has this declaration:
...@@ -812,7 +812,7 @@ class PyLongObjectPtr(PyObjectPtr): ...@@ -812,7 +812,7 @@ class PyLongObjectPtr(PyObjectPtr):
where SHIFT can be either: where SHIFT can be either:
#define PyLong_SHIFT 30 #define PyLong_SHIFT 30
#define PyLong_SHIFT 15 #define PyLong_SHIFT 15
''' '''
ob_size = long(self.field('ob_size')) ob_size = long(self.field('ob_size'))
if ob_size == 0: if ob_size == 0:
return 0L return 0L
...@@ -843,7 +843,7 @@ class PyBoolObjectPtr(PyLongObjectPtr): ...@@ -843,7 +843,7 @@ class PyBoolObjectPtr(PyLongObjectPtr):
<bool> instances (Py_True/Py_False) within the process being debugged. <bool> instances (Py_True/Py_False) within the process being debugged.
""" """
_typename = 'PyBoolObject' _typename = 'PyBoolObject'
def proxyval(self, visited): def proxyval(self, visited):
castto = gdb.lookup_type('PyLongObject').pointer() castto = gdb.lookup_type('PyLongObject').pointer()
self._gdbval = self._gdbval.cast(castto) self._gdbval = self._gdbval.cast(castto)
...@@ -1055,11 +1055,11 @@ class PySetObjectPtr(PyObjectPtr): ...@@ -1055,11 +1055,11 @@ class PySetObjectPtr(PyObjectPtr):
class PyBytesObjectPtr(PyObjectPtr): class PyBytesObjectPtr(PyObjectPtr):
_typename = 'PyBytesObject' _typename = 'PyBytesObject'
def __str__(self): def __str__(self):
field_ob_size = self.field('ob_size') field_ob_size = self.field('ob_size')
field_ob_sval = self.field('ob_sval') field_ob_sval = self.field('ob_sval')
return ''.join(struct.pack('b', field_ob_sval[i]) return ''.join(struct.pack('b', field_ob_sval[i])
for i in safe_range(field_ob_size)) for i in safe_range(field_ob_size))
def proxyval(self, visited): def proxyval(self, visited):
...@@ -1076,7 +1076,7 @@ class PyBytesObjectPtr(PyObjectPtr): ...@@ -1076,7 +1076,7 @@ class PyBytesObjectPtr(PyObjectPtr):
quote = "'" quote = "'"
if "'" in proxy and not '"' in proxy: if "'" in proxy and not '"' in proxy:
quote = '"' quote = '"'
if py3: if py3:
out.write('b') out.write('b')
...@@ -1221,7 +1221,7 @@ class PyUnicodeObjectPtr(PyObjectPtr): ...@@ -1221,7 +1221,7 @@ class PyUnicodeObjectPtr(PyObjectPtr):
else: else:
# Python 2, write the 'u' # Python 2, write the 'u'
out.write('u') out.write('u')
if "'" in proxy and '"' not in proxy: if "'" in proxy and '"' not in proxy:
quote = '"' quote = '"'
else: else:
...@@ -1686,11 +1686,11 @@ class PyLocals(gdb.Command): ...@@ -1686,11 +1686,11 @@ class PyLocals(gdb.Command):
namespace = self.get_namespace(pyop_frame) namespace = self.get_namespace(pyop_frame)
namespace = [(name.proxyval(set()), val) for name, val in namespace] namespace = [(name.proxyval(set()), val) for name, val in namespace]
if namespace: if namespace:
name, val = max(namespace, key=lambda (name, val): len(name)) name, val = max(namespace, key=lambda (name, val): len(name))
max_name_length = len(name) max_name_length = len(name)
for name, pyop_value in namespace: for name, pyop_value in namespace:
value = pyop_value.get_truncated_repr(MAX_OUTPUT_LEN) value = pyop_value.get_truncated_repr(MAX_OUTPUT_LEN)
print ('%-*s = %s' % (max_name_length, name, value)) print ('%-*s = %s' % (max_name_length, name, value))
...@@ -1701,7 +1701,7 @@ class PyLocals(gdb.Command): ...@@ -1701,7 +1701,7 @@ class PyLocals(gdb.Command):
class PyGlobals(PyLocals): class PyGlobals(PyLocals):
'List all the globals in the currently select Python frame' 'List all the globals in the currently select Python frame'
def get_namespace(self, pyop_frame): def get_namespace(self, pyop_frame):
return pyop_frame.iter_globals() return pyop_frame.iter_globals()
...@@ -1711,7 +1711,7 @@ PyGlobals("py-globals", gdb.COMMAND_DATA, gdb.COMPLETE_NONE) ...@@ -1711,7 +1711,7 @@ PyGlobals("py-globals", gdb.COMMAND_DATA, gdb.COMPLETE_NONE)
class PyNameEquals(gdb.Function): class PyNameEquals(gdb.Function):
def _get_pycurframe_attr(self, attr): def _get_pycurframe_attr(self, attr):
frame = Frame(gdb.selected_frame()) frame = Frame(gdb.selected_frame())
if frame.is_evalframeex(): if frame.is_evalframeex():
...@@ -1720,11 +1720,11 @@ class PyNameEquals(gdb.Function): ...@@ -1720,11 +1720,11 @@ class PyNameEquals(gdb.Function):
warnings.warn("Use a Python debug build, Python breakpoints " warnings.warn("Use a Python debug build, Python breakpoints "
"won't work otherwise.") "won't work otherwise.")
return None return None
return getattr(pyframe, attr).proxyval(set()) return getattr(pyframe, attr).proxyval(set())
return None return None
def invoke(self, funcname): def invoke(self, funcname):
attr = self._get_pycurframe_attr('co_name') attr = self._get_pycurframe_attr('co_name')
return attr is not None and attr == funcname.string() return attr is not None and attr == funcname.string()
...@@ -1733,7 +1733,7 @@ PyNameEquals("pyname_equals") ...@@ -1733,7 +1733,7 @@ PyNameEquals("pyname_equals")
class PyModEquals(PyNameEquals): class PyModEquals(PyNameEquals):
def invoke(self, modname): def invoke(self, modname):
attr = self._get_pycurframe_attr('co_filename') attr = self._get_pycurframe_attr('co_filename')
if attr is not None: if attr is not None:
...@@ -1747,20 +1747,20 @@ PyModEquals("pymod_equals") ...@@ -1747,20 +1747,20 @@ PyModEquals("pymod_equals")
class PyBreak(gdb.Command): class PyBreak(gdb.Command):
""" """
Set a Python breakpoint. Examples: Set a Python breakpoint. Examples:
Break on any function or method named 'func' in module 'modname' Break on any function or method named 'func' in module 'modname'
py-break modname.func py-break modname.func
Break on any function or method named 'func' Break on any function or method named 'func'
py-break func py-break func
""" """
def invoke(self, funcname, from_tty): def invoke(self, funcname, from_tty):
if '.' in funcname: if '.' in funcname:
modname, dot, funcname = funcname.rpartition('.') modname, dot, funcname = funcname.rpartition('.')
cond = '$pyname_equals("%s") && $pymod_equals("%s")' % (funcname, cond = '$pyname_equals("%s") && $pymod_equals("%s")' % (funcname,
modname) modname)
else: else:
cond = '$pyname_equals("%s")' % funcname cond = '$pyname_equals("%s")' % funcname
...@@ -1774,31 +1774,31 @@ class _LoggingState(object): ...@@ -1774,31 +1774,31 @@ class _LoggingState(object):
""" """
State that helps to provide a reentrant gdb.execute() function. State that helps to provide a reentrant gdb.execute() function.
""" """
def __init__(self): def __init__(self):
self.fd, self.filename = tempfile.mkstemp() self.fd, self.filename = tempfile.mkstemp()
self.file = os.fdopen(self.fd, 'r+') self.file = os.fdopen(self.fd, 'r+')
_execute("set logging file %s" % self.filename) _execute("set logging file %s" % self.filename)
self.file_position_stack = [] self.file_position_stack = []
atexit.register(os.close, self.fd) atexit.register(os.close, self.fd)
atexit.register(os.remove, self.filename) atexit.register(os.remove, self.filename)
def __enter__(self): def __enter__(self):
if not self.file_position_stack: if not self.file_position_stack:
_execute("set logging redirect on") _execute("set logging redirect on")
_execute("set logging on") _execute("set logging on")
_execute("set pagination off") _execute("set pagination off")
self.file_position_stack.append(os.fstat(self.fd).st_size) self.file_position_stack.append(os.fstat(self.fd).st_size)
return self return self
def getoutput(self): def getoutput(self):
gdb.flush() gdb.flush()
self.file.seek(self.file_position_stack[-1]) self.file.seek(self.file_position_stack[-1])
result = self.file.read() result = self.file.read()
return result return result
def __exit__(self, exc_type, exc_val, tb): def __exit__(self, exc_type, exc_val, tb):
startpos = self.file_position_stack.pop() startpos = self.file_position_stack.pop()
self.file.seek(startpos) self.file.seek(startpos)
...@@ -1812,7 +1812,7 @@ class _LoggingState(object): ...@@ -1812,7 +1812,7 @@ class _LoggingState(object):
def execute(command, from_tty=False, to_string=False): def execute(command, from_tty=False, to_string=False):
""" """
Replace gdb.execute() with this function and have it accept a 'to_string' Replace gdb.execute() with this function and have it accept a 'to_string'
argument (new in 7.2). Have it properly capture stderr also. Ensure argument (new in 7.2). Have it properly capture stderr also. Ensure
reentrancy. reentrancy.
""" """
if to_string: if to_string:
...@@ -1835,9 +1835,9 @@ def get_selected_inferior(): ...@@ -1835,9 +1835,9 @@ def get_selected_inferior():
# Woooh, another bug in gdb! Is there an end in sight? # Woooh, another bug in gdb! Is there an end in sight?
# http://sourceware.org/bugzilla/show_bug.cgi?id=12212 # http://sourceware.org/bugzilla/show_bug.cgi?id=12212
return gdb.inferiors()[0] return gdb.inferiors()[0]
selected_thread = gdb.selected_thread() selected_thread = gdb.selected_thread()
for inferior in gdb.inferiors(): for inferior in gdb.inferiors():
for thread in inferior.threads(): for thread in inferior.threads():
if thread == selected_thread: if thread == selected_thread:
...@@ -1847,7 +1847,7 @@ def source_gdb_script(script_contents, to_string=False): ...@@ -1847,7 +1847,7 @@ def source_gdb_script(script_contents, to_string=False):
""" """
Source a gdb script with script_contents passed as a string. This is useful Source a gdb script with script_contents passed as a string. This is useful
to provide defines for py-step and py-next to make them repeatable (this is to provide defines for py-step and py-next to make them repeatable (this is
not possible with gdb.execute()). See not possible with gdb.execute()). See
http://sourceware.org/bugzilla/show_bug.cgi?id=12216 http://sourceware.org/bugzilla/show_bug.cgi?id=12216
""" """
fd, filename = tempfile.mkstemp() fd, filename = tempfile.mkstemp()
...@@ -1862,20 +1862,20 @@ def register_defines(): ...@@ -1862,20 +1862,20 @@ def register_defines():
define py-step define py-step
-py-step -py-step
end end
define py-next define py-next
-py-next -py-next
end end
document py-step document py-step
%s %s
end end
document py-next document py-next
%s %s
end end
""") % (PyStep.__doc__, PyNext.__doc__)) """) % (PyStep.__doc__, PyNext.__doc__))
def stackdepth(frame): def stackdepth(frame):
"Tells the stackdepth of a gdb frame." "Tells the stackdepth of a gdb frame."
...@@ -1883,16 +1883,16 @@ def stackdepth(frame): ...@@ -1883,16 +1883,16 @@ def stackdepth(frame):
while frame: while frame:
frame = frame.older() frame = frame.older()
depth += 1 depth += 1
return depth return depth
class ExecutionControlCommandBase(gdb.Command): class ExecutionControlCommandBase(gdb.Command):
""" """
Superclass for language specific execution control. Language specific Superclass for language specific execution control. Language specific
features should be implemented by lang_info using the LanguageInfo features should be implemented by lang_info using the LanguageInfo
interface. 'name' is the name of the command. interface. 'name' is the name of the command.
""" """
def __init__(self, name, lang_info): def __init__(self, name, lang_info):
super(ExecutionControlCommandBase, self).__init__( super(ExecutionControlCommandBase, self).__init__(
name, gdb.COMMAND_RUNNING, gdb.COMPLETE_NONE) name, gdb.COMMAND_RUNNING, gdb.COMPLETE_NONE)
...@@ -1902,40 +1902,40 @@ class ExecutionControlCommandBase(gdb.Command): ...@@ -1902,40 +1902,40 @@ class ExecutionControlCommandBase(gdb.Command):
all_locations = itertools.chain( all_locations = itertools.chain(
self.lang_info.static_break_functions(), self.lang_info.static_break_functions(),
self.lang_info.runtime_break_functions()) self.lang_info.runtime_break_functions())
for location in all_locations: for location in all_locations:
result = gdb.execute('break %s' % location, to_string=True) result = gdb.execute('break %s' % location, to_string=True)
yield re.search(r'Breakpoint (\d+)', result).group(1) yield re.search(r'Breakpoint (\d+)', result).group(1)
def delete_breakpoints(self, breakpoint_list): def delete_breakpoints(self, breakpoint_list):
for bp in breakpoint_list: for bp in breakpoint_list:
gdb.execute("delete %s" % bp) gdb.execute("delete %s" % bp)
def filter_output(self, result): def filter_output(self, result):
output = [] output = []
match_finish = re.search(r'^Value returned is \$\d+ = (.*)', result, match_finish = re.search(r'^Value returned is \$\d+ = (.*)', result,
re.MULTILINE) re.MULTILINE)
if match_finish: if match_finish:
output.append('Value returned: %s' % match_finish.group(1)) output.append('Value returned: %s' % match_finish.group(1))
reflags = re.MULTILINE reflags = re.MULTILINE
regexes = [ regexes = [
(r'^Program received signal .*', reflags|re.DOTALL), (r'^Program received signal .*', reflags|re.DOTALL),
(r'.*[Ww]arning.*', 0), (r'.*[Ww]arning.*', 0),
(r'^Program exited .*', reflags), (r'^Program exited .*', reflags),
] ]
for regex, flags in regexes: for regex, flags in regexes:
match = re.search(regex, result, flags) match = re.search(regex, result, flags)
if match: if match:
output.append(match.group(0)) output.append(match.group(0))
return '\n'.join(output) return '\n'.join(output)
def stopped(self): def stopped(self):
return get_selected_inferior().pid == 0 return get_selected_inferior().pid == 0
def finish_executing(self, result): def finish_executing(self, result):
""" """
After doing some kind of code running in the inferior, print the line After doing some kind of code running in the inferior, print the line
...@@ -1943,7 +1943,7 @@ class ExecutionControlCommandBase(gdb.Command): ...@@ -1943,7 +1943,7 @@ class ExecutionControlCommandBase(gdb.Command):
in as the `result` argument). in as the `result` argument).
""" """
result = self.filter_output(result) result = self.filter_output(result)
if self.stopped(): if self.stopped():
print result.strip() print result.strip()
else: else:
...@@ -1955,10 +1955,10 @@ class ExecutionControlCommandBase(gdb.Command): ...@@ -1955,10 +1955,10 @@ class ExecutionControlCommandBase(gdb.Command):
print self.lang_info.get_source_line(frame) or result print self.lang_info.get_source_line(frame) or result
else: else:
print result print result
def _finish(self): def _finish(self):
""" """
Execute until the function returns (or until something else makes it Execute until the function returns (or until something else makes it
stop) stop)
""" """
if gdb.selected_frame().older() is not None: if gdb.selected_frame().older() is not None:
...@@ -1966,83 +1966,83 @@ class ExecutionControlCommandBase(gdb.Command): ...@@ -1966,83 +1966,83 @@ class ExecutionControlCommandBase(gdb.Command):
else: else:
# outermost frame, continue # outermost frame, continue
return gdb.execute('cont', to_string=True) return gdb.execute('cont', to_string=True)
def _finish_frame(self): def _finish_frame(self):
""" """
Execute until the function returns to a relevant caller. Execute until the function returns to a relevant caller.
""" """
while True: while True:
result = self._finish() result = self._finish()
try: try:
frame = gdb.selected_frame() frame = gdb.selected_frame()
except RuntimeError: except RuntimeError:
break break
hitbp = re.search(r'Breakpoint (\d+)', result) hitbp = re.search(r'Breakpoint (\d+)', result)
is_relevant = self.lang_info.is_relevant_function(frame) is_relevant = self.lang_info.is_relevant_function(frame)
if hitbp or is_relevant or self.stopped(): if hitbp or is_relevant or self.stopped():
break break
return result return result
def finish(self, *args): def finish(self, *args):
"Implements the finish command." "Implements the finish command."
result = self._finish_frame() result = self._finish_frame()
self.finish_executing(result) self.finish_executing(result)
def step(self, stepinto, stepover_command='next'): def step(self, stepinto, stepover_command='next'):
""" """
Do a single step or step-over. Returns the result of the last gdb Do a single step or step-over. Returns the result of the last gdb
command that made execution stop. command that made execution stop.
This implementation, for stepping, sets (conditional) breakpoints for This implementation, for stepping, sets (conditional) breakpoints for
all functions that are deemed relevant. It then does a step over until all functions that are deemed relevant. It then does a step over until
either something halts execution, or until the next line is reached. either something halts execution, or until the next line is reached.
If, however, stepover_command is given, it should be a string gdb If, however, stepover_command is given, it should be a string gdb
command that continues execution in some way. The idea is that the command that continues execution in some way. The idea is that the
caller has set a (conditional) breakpoint or watchpoint that can work caller has set a (conditional) breakpoint or watchpoint that can work
more efficiently than the step-over loop. For Python this means setting more efficiently than the step-over loop. For Python this means setting
a watchpoint for f->f_lasti, which means we can then subsequently a watchpoint for f->f_lasti, which means we can then subsequently
"finish" frames. "finish" frames.
We want f->f_lasti instead of f->f_lineno, because the latter only We want f->f_lasti instead of f->f_lineno, because the latter only
works properly with local trace functions, see works properly with local trace functions, see
PyFrameObjectPtr.current_line_num and PyFrameObjectPtr.addr2line. PyFrameObjectPtr.current_line_num and PyFrameObjectPtr.addr2line.
""" """
if stepinto: if stepinto:
breakpoint_list = list(self.install_breakpoints()) breakpoint_list = list(self.install_breakpoints())
beginframe = gdb.selected_frame() beginframe = gdb.selected_frame()
if self.lang_info.is_relevant_function(beginframe): if self.lang_info.is_relevant_function(beginframe):
# If we start in a relevant frame, initialize stuff properly. If # If we start in a relevant frame, initialize stuff properly. If
# we don't start in a relevant frame, the loop will halt # we don't start in a relevant frame, the loop will halt
# immediately. So don't call self.lang_info.lineno() as it may # immediately. So don't call self.lang_info.lineno() as it may
# raise for irrelevant frames. # raise for irrelevant frames.
beginline = self.lang_info.lineno(beginframe) beginline = self.lang_info.lineno(beginframe)
if not stepinto: if not stepinto:
depth = stackdepth(beginframe) depth = stackdepth(beginframe)
newframe = beginframe newframe = beginframe
while True: while True:
if self.lang_info.is_relevant_function(newframe): if self.lang_info.is_relevant_function(newframe):
result = gdb.execute(stepover_command, to_string=True) result = gdb.execute(stepover_command, to_string=True)
else: else:
result = self._finish_frame() result = self._finish_frame()
if self.stopped(): if self.stopped():
break break
newframe = gdb.selected_frame() newframe = gdb.selected_frame()
is_relevant_function = self.lang_info.is_relevant_function(newframe) is_relevant_function = self.lang_info.is_relevant_function(newframe)
try: try:
framename = newframe.name() framename = newframe.name()
except RuntimeError: except RuntimeError:
framename = None framename = None
m = re.search(r'Breakpoint (\d+)', result) m = re.search(r'Breakpoint (\d+)', result)
if m: if m:
if is_relevant_function and m.group(1) in breakpoint_list: if is_relevant_function and m.group(1) in breakpoint_list:
...@@ -2050,16 +2050,16 @@ class ExecutionControlCommandBase(gdb.Command): ...@@ -2050,16 +2050,16 @@ class ExecutionControlCommandBase(gdb.Command):
# that the function, in case hit by a runtime breakpoint, # that the function, in case hit by a runtime breakpoint,
# is in the right context # is in the right context
break break
if newframe != beginframe: if newframe != beginframe:
# new function # new function
if not stepinto: if not stepinto:
# see if we returned to the caller # see if we returned to the caller
newdepth = stackdepth(newframe) newdepth = stackdepth(newframe)
is_relevant_function = (newdepth < depth and is_relevant_function = (newdepth < depth and
is_relevant_function) is_relevant_function)
if is_relevant_function: if is_relevant_function:
break break
else: else:
...@@ -2068,15 +2068,15 @@ class ExecutionControlCommandBase(gdb.Command): ...@@ -2068,15 +2068,15 @@ class ExecutionControlCommandBase(gdb.Command):
lineno = self.lang_info.lineno(newframe) lineno = self.lang_info.lineno(newframe)
if lineno and lineno != beginline: if lineno and lineno != beginline:
break break
if stepinto: if stepinto:
self.delete_breakpoints(breakpoint_list) self.delete_breakpoints(breakpoint_list)
self.finish_executing(result) self.finish_executing(result)
def run(self, *args): def run(self, *args):
self.finish_executing(gdb.execute('run', to_string=True)) self.finish_executing(gdb.execute('run', to_string=True))
def cont(self, *args): def cont(self, *args):
self.finish_executing(gdb.execute('cont', to_string=True)) self.finish_executing(gdb.execute('cont', to_string=True))
...@@ -2085,32 +2085,32 @@ class LanguageInfo(object): ...@@ -2085,32 +2085,32 @@ class LanguageInfo(object):
""" """
This class defines the interface that ExecutionControlCommandBase needs to This class defines the interface that ExecutionControlCommandBase needs to
provide language-specific execution control. provide language-specific execution control.
Classes that implement this interface should implement: Classes that implement this interface should implement:
lineno(frame) lineno(frame)
Tells the current line number (only called for a relevant frame). Tells the current line number (only called for a relevant frame).
If lineno is a false value it is not checked for a difference. If lineno is a false value it is not checked for a difference.
is_relevant_function(frame) is_relevant_function(frame)
tells whether we care about frame 'frame' tells whether we care about frame 'frame'
get_source_line(frame) get_source_line(frame)
get the line of source code for the current line (only called for a get the line of source code for the current line (only called for a
relevant frame). If the source code cannot be retrieved this relevant frame). If the source code cannot be retrieved this
function should return None function should return None
exc_info(frame) -- optional exc_info(frame) -- optional
tells whether an exception was raised, if so, it should return a tells whether an exception was raised, if so, it should return a
string representation of the exception value, None otherwise. string representation of the exception value, None otherwise.
static_break_functions() static_break_functions()
returns an iterable of function names that are considered relevant returns an iterable of function names that are considered relevant
and should halt step-into execution. This is needed to provide a and should halt step-into execution. This is needed to provide a
performing step-into performing step-into
runtime_break_functions() -- optional runtime_break_functions() -- optional
list of functions that we should break into depending on the list of functions that we should break into depending on the
context context
""" """
...@@ -2119,13 +2119,13 @@ class LanguageInfo(object): ...@@ -2119,13 +2119,13 @@ class LanguageInfo(object):
def runtime_break_functions(self): def runtime_break_functions(self):
""" """
Implement this if the list of step-into functions depends on the Implement this if the list of step-into functions depends on the
context. context.
""" """
return () return ()
class PythonInfo(LanguageInfo): class PythonInfo(LanguageInfo):
def pyframe(self, frame): def pyframe(self, frame):
pyframe = Frame(frame).get_pyop() pyframe = Frame(frame).get_pyop()
if pyframe: if pyframe:
...@@ -2134,21 +2134,21 @@ class PythonInfo(LanguageInfo): ...@@ -2134,21 +2134,21 @@ class PythonInfo(LanguageInfo):
raise gdb.RuntimeError( raise gdb.RuntimeError(
"Unable to find the Python frame, run your code with a debug " "Unable to find the Python frame, run your code with a debug "
"build (configure with --with-pydebug or compile with -g).") "build (configure with --with-pydebug or compile with -g).")
def lineno(self, frame): def lineno(self, frame):
return self.pyframe(frame).current_line_num() return self.pyframe(frame).current_line_num()
def is_relevant_function(self, frame): def is_relevant_function(self, frame):
return Frame(frame).is_evalframeex() return Frame(frame).is_evalframeex()
def get_source_line(self, frame): def get_source_line(self, frame):
try: try:
pyframe = self.pyframe(frame) pyframe = self.pyframe(frame)
return '%4d %s' % (pyframe.current_line_num(), return '%4d %s' % (pyframe.current_line_num(),
pyframe.current_line().rstrip()) pyframe.current_line().rstrip())
except IOError, e: except IOError, e:
return None return None
def exc_info(self, frame): def exc_info(self, frame):
try: try:
tstate = frame.read_var('tstate').dereference() tstate = frame.read_var('tstate').dereference()
...@@ -2157,26 +2157,26 @@ class PythonInfo(LanguageInfo): ...@@ -2157,26 +2157,26 @@ class PythonInfo(LanguageInfo):
inf_type = tstate['curexc_type'] inf_type = tstate['curexc_type']
inf_value = tstate['curexc_value'] inf_value = tstate['curexc_value']
if inf_type: if inf_type:
return 'An exception was raised: %s(%s)' % (inf_type, return 'An exception was raised: %s(%s)' % (inf_type,
inf_value) inf_value)
except (ValueError, RuntimeError), e: except (ValueError, RuntimeError), e:
# Could not read the variable tstate or it's memory, it's ok # Could not read the variable tstate or it's memory, it's ok
pass pass
def static_break_functions(self): def static_break_functions(self):
yield 'PyEval_EvalFrameEx' yield 'PyEval_EvalFrameEx'
class PythonStepperMixin(object): class PythonStepperMixin(object):
""" """
Make this a mixin so CyStep can also inherit from this and use a Make this a mixin so CyStep can also inherit from this and use a
CythonCodeStepper at the same time. CythonCodeStepper at the same time.
""" """
def python_step(self, stepinto): def python_step(self, stepinto):
frame = gdb.selected_frame() frame = gdb.selected_frame()
framewrapper = Frame(frame) framewrapper = Frame(frame)
output = gdb.execute('watch f->f_lasti', to_string=True) output = gdb.execute('watch f->f_lasti', to_string=True)
watchpoint = int(re.search(r'[Ww]atchpoint (\d+):', output).group(1)) watchpoint = int(re.search(r'[Ww]atchpoint (\d+):', output).group(1))
self.step(stepinto=stepinto, stepover_command='finish') self.step(stepinto=stepinto, stepover_command='finish')
...@@ -2185,36 +2185,36 @@ class PythonStepperMixin(object): ...@@ -2185,36 +2185,36 @@ class PythonStepperMixin(object):
class PyStep(ExecutionControlCommandBase, PythonStepperMixin): class PyStep(ExecutionControlCommandBase, PythonStepperMixin):
"Step through Python code." "Step through Python code."
stepinto = True stepinto = True
def invoke(self, args, from_tty): def invoke(self, args, from_tty):
self.python_step(stepinto=self.stepinto) self.python_step(stepinto=self.stepinto)
class PyNext(PyStep): class PyNext(PyStep):
"Step-over Python code." "Step-over Python code."
stepinto = False stepinto = False
class PyFinish(ExecutionControlCommandBase): class PyFinish(ExecutionControlCommandBase):
"Execute until function returns to a caller." "Execute until function returns to a caller."
invoke = ExecutionControlCommandBase.finish invoke = ExecutionControlCommandBase.finish
class PyRun(ExecutionControlCommandBase): class PyRun(ExecutionControlCommandBase):
"Run the program." "Run the program."
invoke = ExecutionControlCommandBase.run invoke = ExecutionControlCommandBase.run
class PyCont(ExecutionControlCommandBase): class PyCont(ExecutionControlCommandBase):
invoke = ExecutionControlCommandBase.cont invoke = ExecutionControlCommandBase.cont
def _pointervalue(gdbval): def _pointervalue(gdbval):
""" """
Return the value of the pionter as a Python int. Return the value of the pionter as a Python int.
gdbval.type must be a pointer type gdbval.type must be a pointer type
""" """
# don't convert with int() as it will raise a RuntimeError # don't convert with int() as it will raise a RuntimeError
...@@ -2235,14 +2235,14 @@ def pointervalue(gdbval): ...@@ -2235,14 +2235,14 @@ def pointervalue(gdbval):
# work around yet another bug in gdb where you get random behaviour # work around yet another bug in gdb where you get random behaviour
# and tracebacks # and tracebacks
pass pass
return pointer return pointer
def get_inferior_unicode_postfix(): def get_inferior_unicode_postfix():
try: try:
gdb.parse_and_eval('PyUnicode_FromEncodedObject') gdb.parse_and_eval('PyUnicode_FromEncodedObject')
except RuntimeError: except RuntimeError:
try: try:
gdb.parse_and_eval('PyUnicodeUCS2_FromEncodedObject') gdb.parse_and_eval('PyUnicodeUCS2_FromEncodedObject')
except RuntimeError: except RuntimeError:
return 'UCS4' return 'UCS4'
...@@ -2250,37 +2250,37 @@ def get_inferior_unicode_postfix(): ...@@ -2250,37 +2250,37 @@ def get_inferior_unicode_postfix():
return 'UCS2' return 'UCS2'
else: else:
return '' return ''
class PythonCodeExecutor(object): class PythonCodeExecutor(object):
Py_single_input = 256 Py_single_input = 256
Py_file_input = 257 Py_file_input = 257
Py_eval_input = 258 Py_eval_input = 258
def malloc(self, size): def malloc(self, size):
chunk = (gdb.parse_and_eval("(void *) malloc((size_t) %d)" % size)) chunk = (gdb.parse_and_eval("(void *) malloc((size_t) %d)" % size))
pointer = pointervalue(chunk) pointer = pointervalue(chunk)
if pointer == 0: if pointer == 0:
raise gdb.GdbError("No memory could be allocated in the inferior.") raise gdb.GdbError("No memory could be allocated in the inferior.")
return pointer return pointer
def alloc_string(self, string): def alloc_string(self, string):
pointer = self.malloc(len(string)) pointer = self.malloc(len(string))
get_selected_inferior().write_memory(pointer, string) get_selected_inferior().write_memory(pointer, string)
return pointer return pointer
def alloc_pystring(self, string): def alloc_pystring(self, string):
stringp = self.alloc_string(string) stringp = self.alloc_string(string)
PyString_FromStringAndSize = 'PyString_FromStringAndSize' PyString_FromStringAndSize = 'PyString_FromStringAndSize'
try: try:
gdb.parse_and_eval(PyString_FromStringAndSize) gdb.parse_and_eval(PyString_FromStringAndSize)
except RuntimeError: except RuntimeError:
# Python 3 # Python 3
PyString_FromStringAndSize = ('PyUnicode%s_FromStringAndSize' % PyString_FromStringAndSize = ('PyUnicode%s_FromStringAndSize' %
(get_inferior_unicode_postfix,)) (get_inferior_unicode_postfix,))
try: try:
...@@ -2289,59 +2289,59 @@ class PythonCodeExecutor(object): ...@@ -2289,59 +2289,59 @@ class PythonCodeExecutor(object):
PyString_FromStringAndSize, stringp, len(string))) PyString_FromStringAndSize, stringp, len(string)))
finally: finally:
self.free(stringp) self.free(stringp)
pointer = pointervalue(result) pointer = pointervalue(result)
if pointer == 0: if pointer == 0:
raise gdb.GdbError("Unable to allocate Python string in " raise gdb.GdbError("Unable to allocate Python string in "
"the inferior.") "the inferior.")
return pointer return pointer
def free(self, pointer): def free(self, pointer):
gdb.parse_and_eval("free((void *) %d)" % pointer) gdb.parse_and_eval("free((void *) %d)" % pointer)
def incref(self, pointer): def incref(self, pointer):
"Increment the reference count of a Python object in the inferior." "Increment the reference count of a Python object in the inferior."
gdb.parse_and_eval('Py_IncRef((PyObject *) %d)' % pointer) gdb.parse_and_eval('Py_IncRef((PyObject *) %d)' % pointer)
def decref(self, pointer): def decref(self, pointer):
"Decrement the reference count of a Python object in the inferior." "Decrement the reference count of a Python object in the inferior."
# Py_DecRef is like Py_XDECREF, but a function. So we don't have # Py_DecRef is like Py_XDECREF, but a function. So we don't have
# to check for NULL. This should also decref all our allocated # to check for NULL. This should also decref all our allocated
# Python strings. # Python strings.
gdb.parse_and_eval('Py_DecRef((PyObject *) %d)' % pointer) gdb.parse_and_eval('Py_DecRef((PyObject *) %d)' % pointer)
def evalcode(self, code, input_type, global_dict=None, local_dict=None): def evalcode(self, code, input_type, global_dict=None, local_dict=None):
""" """
Evaluate python code `code` given as a string in the inferior and Evaluate python code `code` given as a string in the inferior and
return the result as a gdb.Value. Returns a new reference in the return the result as a gdb.Value. Returns a new reference in the
inferior. inferior.
Of course, executing any code in the inferior may be dangerous and may Of course, executing any code in the inferior may be dangerous and may
leave the debuggee in an unsafe state or terminate it alltogether. leave the debuggee in an unsafe state or terminate it alltogether.
""" """
if '\0' in code: if '\0' in code:
raise gdb.GdbError("String contains NUL byte.") raise gdb.GdbError("String contains NUL byte.")
code += '\0' code += '\0'
pointer = self.alloc_string(code) pointer = self.alloc_string(code)
globalsp = pointervalue(global_dict) globalsp = pointervalue(global_dict)
localsp = pointervalue(local_dict) localsp = pointervalue(local_dict)
if globalsp == 0 or localsp == 0: if globalsp == 0 or localsp == 0:
raise gdb.GdbError("Unable to obtain or create locals or globals.") raise gdb.GdbError("Unable to obtain or create locals or globals.")
code = """ code = """
PyRun_String( PyRun_String(
(char *) %(code)d, (char *) %(code)d,
(int) %(start)d, (int) %(start)d,
(PyObject *) %(globals)s, (PyObject *) %(globals)s,
(PyObject *) %(locals)d) (PyObject *) %(locals)d)
""" % dict(code=pointer, start=input_type, """ % dict(code=pointer, start=input_type,
globals=globalsp, locals=localsp) globals=globalsp, locals=localsp)
with FetchAndRestoreError(): with FetchAndRestoreError():
try: try:
self.decref(gdb.parse_and_eval(code)) self.decref(gdb.parse_and_eval(code))
...@@ -2358,25 +2358,25 @@ class FetchAndRestoreError(PythonCodeExecutor): ...@@ -2358,25 +2358,25 @@ class FetchAndRestoreError(PythonCodeExecutor):
def __init__(self): def __init__(self):
self.sizeof_PyObjectPtr = gdb.lookup_type('PyObject').pointer().sizeof self.sizeof_PyObjectPtr = gdb.lookup_type('PyObject').pointer().sizeof
self.pointer = self.malloc(self.sizeof_PyObjectPtr * 3) self.pointer = self.malloc(self.sizeof_PyObjectPtr * 3)
type = self.pointer type = self.pointer
value = self.pointer + self.sizeof_PyObjectPtr value = self.pointer + self.sizeof_PyObjectPtr
traceback = self.pointer + self.sizeof_PyObjectPtr * 2 traceback = self.pointer + self.sizeof_PyObjectPtr * 2
self.errstate = type, value, traceback self.errstate = type, value, traceback
def __enter__(self): def __enter__(self):
gdb.parse_and_eval("PyErr_Fetch(%d, %d, %d)" % self.errstate) gdb.parse_and_eval("PyErr_Fetch(%d, %d, %d)" % self.errstate)
def __exit__(self, *args): def __exit__(self, *args):
if gdb.parse_and_eval("(int) PyErr_Occurred()"): if gdb.parse_and_eval("(int) PyErr_Occurred()"):
gdb.parse_and_eval("PyErr_Print()") gdb.parse_and_eval("PyErr_Print()")
pyerr_restore = ("PyErr_Restore(" pyerr_restore = ("PyErr_Restore("
"(PyObject *) *%d," "(PyObject *) *%d,"
"(PyObject *) *%d," "(PyObject *) *%d,"
"(PyObject *) *%d)") "(PyObject *) *%d)")
try: try:
gdb.parse_and_eval(pyerr_restore % self.errstate) gdb.parse_and_eval(pyerr_restore % self.errstate)
finally: finally:
...@@ -2389,15 +2389,15 @@ class FixGdbCommand(gdb.Command): ...@@ -2389,15 +2389,15 @@ class FixGdbCommand(gdb.Command):
super(FixGdbCommand, self).__init__(command, gdb.COMMAND_DATA, super(FixGdbCommand, self).__init__(command, gdb.COMMAND_DATA,
gdb.COMPLETE_NONE) gdb.COMPLETE_NONE)
self.actual_command = actual_command self.actual_command = actual_command
def fix_gdb(self): def fix_gdb(self):
""" """
So, you must be wondering what the story is this time! Yeeees, indeed, So, you must be wondering what the story is this time! Yeeees, indeed,
I have quite the story for you! It seems that invoking either 'cy exec' I have quite the story for you! It seems that invoking either 'cy exec'
and 'py-exec' work perfectly fine, but after this gdb's python API is and 'py-exec' work perfectly fine, but after this gdb's python API is
entirely broken. Some unset exception value is still set? entirely broken. Some unset exception value is still set?
sys.exc_clear() didn't help. A demonstration: sys.exc_clear() didn't help. A demonstration:
(gdb) cy exec 'hello' (gdb) cy exec 'hello'
'hello' 'hello'
(gdb) python gdb.execute('cont') (gdb) python gdb.execute('cont')
...@@ -2405,17 +2405,17 @@ class FixGdbCommand(gdb.Command): ...@@ -2405,17 +2405,17 @@ class FixGdbCommand(gdb.Command):
Error while executing Python code. Error while executing Python code.
(gdb) python gdb.execute('cont') (gdb) python gdb.execute('cont')
[15148 refs] [15148 refs]
Program exited normally. Program exited normally.
""" """
warnings.filterwarnings('ignore', r'.*', RuntimeWarning, warnings.filterwarnings('ignore', r'.*', RuntimeWarning,
re.escape(__name__)) re.escape(__name__))
try: try:
long(gdb.parse_and_eval("(void *) 0")) == 0 long(gdb.parse_and_eval("(void *) 0")) == 0
except RuntimeError: except RuntimeError:
pass pass
# warnings.resetwarnings() # warnings.resetwarnings()
def invoke(self, args, from_tty): def invoke(self, args, from_tty):
self.fix_gdb() self.fix_gdb()
try: try:
...@@ -2426,7 +2426,7 @@ class FixGdbCommand(gdb.Command): ...@@ -2426,7 +2426,7 @@ class FixGdbCommand(gdb.Command):
class PyExec(gdb.Command): class PyExec(gdb.Command):
def readcode(self, expr): def readcode(self, expr):
if expr: if expr:
return expr, PythonCodeExecutor.Py_single_input return expr, PythonCodeExecutor.Py_single_input
...@@ -2440,23 +2440,23 @@ class PyExec(gdb.Command): ...@@ -2440,23 +2440,23 @@ class PyExec(gdb.Command):
else: else:
if line.rstrip() == 'end': if line.rstrip() == 'end':
break break
lines.append(line) lines.append(line)
return '\n'.join(lines), Py_file_input return '\n'.join(lines), Py_file_input
def invoke(self, expr, from_tty): def invoke(self, expr, from_tty):
expr, input_type = self.readcode(expr) expr, input_type = self.readcode(expr)
executor = PythonCodeExecutor() executor = PythonCodeExecutor()
global_dict = gdb.parse_and_eval('PyEval_GetGlobals()') global_dict = gdb.parse_and_eval('PyEval_GetGlobals()')
local_dict = gdb.parse_and_eval('PyEval_GetLocals()') local_dict = gdb.parse_and_eval('PyEval_GetLocals()')
if pointervalue(global_dict) == 0 or pointervalue(local_dict) == 0: if pointervalue(global_dict) == 0 or pointervalue(local_dict) == 0:
raise gdb.GdbError("Unable to find the locals or globals of the " raise gdb.GdbError("Unable to find the locals or globals of the "
"most recent Python function (relative to the " "most recent Python function (relative to the "
"selected frame).") "selected frame).")
executor.evalcode(expr, input_type, global_dict, local_dict) executor.evalcode(expr, input_type, global_dict, local_dict)
...@@ -2474,4 +2474,4 @@ if hasattr(gdb, 'GdbError'): ...@@ -2474,4 +2474,4 @@ if hasattr(gdb, 'GdbError'):
py_exec = FixGdbCommand('py-exec', '-py-exec') py_exec = FixGdbCommand('py-exec', '-py-exec')
_py_exec = PyExec("-py-exec", gdb.COMMAND_DATA, gdb.COMPLETE_NONE) _py_exec = PyExec("-py-exec", gdb.COMMAND_DATA, gdb.COMPLETE_NONE)
else: else:
warnings.warn("Use gdb 7.2 or higher to use the py-exec command.") warnings.warn("Use gdb 7.2 or higher to use the py-exec command.")
\ No newline at end of file
...@@ -85,7 +85,7 @@ class build_ext(_build_ext): ...@@ -85,7 +85,7 @@ class build_ext(_build_ext):
def build_extension(self, ext): def build_extension(self, ext):
if ext.language == 'c++': if ext.language == 'c++':
try: try:
try: # Py2.7+ & Py3.2+ try: # Py2.7+ & Py3.2+
compiler_obj = self.compiler_obj compiler_obj = self.compiler_obj
except AttributeError: except AttributeError:
compiler_obj = self.compiler compiler_obj = self.compiler
...@@ -353,17 +353,17 @@ class CythonCompileTestCase(unittest.TestCase): ...@@ -353,17 +353,17 @@ class CythonCompileTestCase(unittest.TestCase):
source = self.find_module_source_file( source = self.find_module_source_file(
os.path.join(test_directory, module + '.pyx')) os.path.join(test_directory, module + '.pyx'))
target = os.path.join(targetdir, self.build_target_filename(module)) target = os.path.join(targetdir, self.build_target_filename(module))
if extra_compile_options is None: if extra_compile_options is None:
extra_compile_options = {} extra_compile_options = {}
try: try:
CompilationOptions CompilationOptions
except NameError: except NameError:
from Cython.Compiler.Main import CompilationOptions from Cython.Compiler.Main import CompilationOptions
from Cython.Compiler.Main import compile as cython_compile from Cython.Compiler.Main import compile as cython_compile
from Cython.Compiler.Main import default_options from Cython.Compiler.Main import default_options
options = CompilationOptions( options = CompilationOptions(
default_options, default_options,
include_path = include_dirs, include_path = include_dirs,
...@@ -379,7 +379,7 @@ class CythonCompileTestCase(unittest.TestCase): ...@@ -379,7 +379,7 @@ class CythonCompileTestCase(unittest.TestCase):
cython_compile(source, options=options, cython_compile(source, options=options,
full_module_name=module) full_module_name=module)
def run_distutils(self, test_directory, module, workdir, incdir, def run_distutils(self, test_directory, module, workdir, incdir,
extra_extension_args=None): extra_extension_args=None):
cwd = os.getcwd() cwd = os.getcwd()
os.chdir(workdir) os.chdir(workdir)
...@@ -394,10 +394,10 @@ class CythonCompileTestCase(unittest.TestCase): ...@@ -394,10 +394,10 @@ class CythonCompileTestCase(unittest.TestCase):
if match(module): if match(module):
ext_include_dirs += get_additional_include_dirs() ext_include_dirs += get_additional_include_dirs()
self.copy_related_files(test_directory, workdir, module) self.copy_related_files(test_directory, workdir, module)
if extra_extension_args is None: if extra_extension_args is None:
extra_extension_args = {} extra_extension_args = {}
extension = Extension( extension = Extension(
module, module,
sources = self.find_source_files(workdir, module), sources = self.find_source_files(workdir, module),
...@@ -676,9 +676,9 @@ class CythonPyregrTestCase(CythonRunTestCase): ...@@ -676,9 +676,9 @@ class CythonPyregrTestCase(CythonRunTestCase):
result.addSkip(self, 'ok') result.addSkip(self, 'ok')
# Someone wrapped this in a: # Someone wrapped this in a:
# 'try: import gdb; ... except: include_debugger = False' thing, but don't do # 'try: import gdb; ... except: include_debugger = False' thing, but don't do
# this, it doesn't work as gdb is a builtin module in GDB. The tests themselves # this, it doesn't work as gdb is a builtin module in GDB. The tests themselves
# are doing the skipping. If there's a problem with the tests, please file an # are doing the skipping. If there's a problem with the tests, please file an
# issue. # issue.
include_debugger = sys.version_info[:2] > (2, 5) include_debugger = sys.version_info[:2] > (2, 5)
...@@ -690,7 +690,7 @@ def collect_unittests(path, module_prefix, suite, selectors): ...@@ -690,7 +690,7 @@ def collect_unittests(path, module_prefix, suite, selectors):
return dirname == "Tests" return dirname == "Tests"
loader = unittest.TestLoader() loader = unittest.TestLoader()
if include_debugger: if include_debugger:
skipped_dirs = [] skipped_dirs = []
else: else:
...@@ -729,7 +729,7 @@ def collect_doctests(path, module_prefix, suite, selectors): ...@@ -729,7 +729,7 @@ def collect_doctests(path, module_prefix, suite, selectors):
return dirname not in ("Mac", "Distutils", "Plex") return dirname not in ("Mac", "Distutils", "Plex")
def file_matches(filename): def file_matches(filename):
filename, ext = os.path.splitext(filename) filename, ext = os.path.splitext(filename)
blacklist = ['libcython', 'libpython', 'test_libcython_in_gdb', blacklist = ['libcython', 'libpython', 'test_libcython_in_gdb',
'TestLibCython'] 'TestLibCython']
return (ext == '.py' and not return (ext == '.py' and not
'~' in filename and not '~' in filename and not
...@@ -766,7 +766,7 @@ class EndToEndTest(unittest.TestCase): ...@@ -766,7 +766,7 @@ class EndToEndTest(unittest.TestCase):
directory structure and its header gives a list of commands to run. directory structure and its header gives a list of commands to run.
""" """
cython_root = os.path.dirname(os.path.abspath(__file__)) cython_root = os.path.dirname(os.path.abspath(__file__))
def __init__(self, treefile, workdir, cleanup_workdir=True): def __init__(self, treefile, workdir, cleanup_workdir=True):
self.treefile = treefile self.treefile = treefile
self.workdir = os.path.join(workdir, os.path.splitext(treefile)[0]) self.workdir = os.path.join(workdir, os.path.splitext(treefile)[0])
...@@ -797,7 +797,7 @@ class EndToEndTest(unittest.TestCase): ...@@ -797,7 +797,7 @@ class EndToEndTest(unittest.TestCase):
if self.cleanup_workdir: if self.cleanup_workdir:
shutil.rmtree(self.workdir) shutil.rmtree(self.workdir)
os.chdir(self.old_dir) os.chdir(self.old_dir)
def runTest(self): def runTest(self):
commands = (self.commands commands = (self.commands
.replace("CYTHON", "PYTHON %s" % os.path.join(self.cython_root, 'cython.py')) .replace("CYTHON", "PYTHON %s" % os.path.join(self.cython_root, 'cython.py'))
...@@ -832,15 +832,15 @@ class EndToEndTest(unittest.TestCase): ...@@ -832,15 +832,15 @@ class EndToEndTest(unittest.TestCase):
# TODO: Windows support. # TODO: Windows support.
class EmbedTest(unittest.TestCase): class EmbedTest(unittest.TestCase):
working_dir = "Demos/embed" working_dir = "Demos/embed"
def setUp(self): def setUp(self):
self.old_dir = os.getcwd() self.old_dir = os.getcwd()
os.chdir(self.working_dir) os.chdir(self.working_dir)
os.system( os.system(
"make PYTHON='%s' clean > /dev/null" % sys.executable) "make PYTHON='%s' clean > /dev/null" % sys.executable)
def tearDown(self): def tearDown(self):
try: try:
os.system( os.system(
...@@ -848,7 +848,7 @@ class EmbedTest(unittest.TestCase): ...@@ -848,7 +848,7 @@ class EmbedTest(unittest.TestCase):
except: except:
pass pass
os.chdir(self.old_dir) os.chdir(self.old_dir)
def test_embed(self): def test_embed(self):
from distutils import sysconfig from distutils import sysconfig
libname = sysconfig.get_config_var('LIBRARY') libname = sysconfig.get_config_var('LIBRARY')
...@@ -912,7 +912,7 @@ class FileListExcluder: ...@@ -912,7 +912,7 @@ class FileListExcluder:
self.excludes[line.split()[0]] = True self.excludes[line.split()[0]] = True
finally: finally:
f.close() f.close()
def __call__(self, testname): def __call__(self, testname):
return testname in self.excludes or testname.split('.')[-1] in self.excludes return testname in self.excludes or testname.split('.')[-1] in self.excludes
...@@ -996,7 +996,7 @@ def main(): ...@@ -996,7 +996,7 @@ def main():
help="do not run the file based tests") help="do not run the file based tests")
parser.add_option("--no-pyregr", dest="pyregr", parser.add_option("--no-pyregr", dest="pyregr",
action="store_false", default=True, action="store_false", default=True,
help="do not run the regression tests of CPython in tests/pyregr/") help="do not run the regression tests of CPython in tests/pyregr/")
parser.add_option("--cython-only", dest="cython_only", parser.add_option("--cython-only", dest="cython_only",
action="store_true", default=False, action="store_true", default=False,
help="only compile pyx to c, do not run C compiler or run the tests") help="only compile pyx to c, do not run C compiler or run the tests")
...@@ -1146,16 +1146,16 @@ def main(): ...@@ -1146,16 +1146,16 @@ def main():
# Chech which external modules are not present and exclude tests # Chech which external modules are not present and exclude tests
# which depends on them (by prefix) # which depends on them (by prefix)
missing_dep_excluder = MissingDependencyExcluder(EXT_DEP_MODULES) missing_dep_excluder = MissingDependencyExcluder(EXT_DEP_MODULES)
version_dep_excluder = VersionDependencyExcluder(VER_DEP_MODULES) version_dep_excluder = VersionDependencyExcluder(VER_DEP_MODULES)
exclude_selectors = [missing_dep_excluder, version_dep_excluder] # want to pring msg at exit exclude_selectors = [missing_dep_excluder, version_dep_excluder] # want to pring msg at exit
if options.exclude: if options.exclude:
exclude_selectors += [ re.compile(r, re.I|re.U).search for r in options.exclude ] exclude_selectors += [ re.compile(r, re.I|re.U).search for r in options.exclude ]
if not test_bugs: if not test_bugs:
exclude_selectors += [ FileListExcluder("tests/bugs.txt") ] exclude_selectors += [ FileListExcluder("tests/bugs.txt") ]
if sys.platform in ['win32', 'cygwin'] and sys.version_info < (2,6): if sys.platform in ['win32', 'cygwin'] and sys.version_info < (2,6):
exclude_selectors += [ lambda x: x == "run.specialfloat" ] exclude_selectors += [ lambda x: x == "run.specialfloat" ]
...@@ -1206,7 +1206,7 @@ def main(): ...@@ -1206,7 +1206,7 @@ def main():
ignored_modules = ('Options', 'Version', 'DebugFlags', 'CmdLine') ignored_modules = ('Options', 'Version', 'DebugFlags', 'CmdLine')
modules = [ module for name, module in sys.modules.items() modules = [ module for name, module in sys.modules.items()
if module is not None and if module is not None and
name.startswith('Cython.Compiler.') and name.startswith('Cython.Compiler.') and
name[len('Cython.Compiler.'):] not in ignored_modules ] name[len('Cython.Compiler.'):] not in ignored_modules ]
if options.coverage: if options.coverage:
coverage.report(modules, show_missing=0) coverage.report(modules, show_missing=0)
......
...@@ -66,7 +66,7 @@ else: ...@@ -66,7 +66,7 @@ else:
'Cython' : [ p[7:] for p in pxd_include_patterns ], 'Cython' : [ p[7:] for p in pxd_include_patterns ],
} }
# This dict is used for passing extra arguments that are setuptools # This dict is used for passing extra arguments that are setuptools
# specific to setup # specific to setup
setuptools_extra_args = {} setuptools_extra_args = {}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment