Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
cython
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Gwenaël Samain
cython
Commits
c5e16a3f
Commit
c5e16a3f
authored
Jan 13, 2011
by
Robert Bradshaw
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'master' of
https://github.com/markflorisson88/cython
into markflorisson88-master
parents
b4c160b5
05533ff0
Changes
10
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
1039 additions
and
748 deletions
+1039
-748
Cython/Compiler/Main.py
Cython/Compiler/Main.py
+33
-28
Cython/Compiler/ParseTreeTransforms.py
Cython/Compiler/ParseTreeTransforms.py
+163
-84
Cython/Compiler/Tests/TestParseTreeTransforms.py
Cython/Compiler/Tests/TestParseTreeTransforms.py
+16
-15
Cython/Debugger/Tests/TestLibCython.py
Cython/Debugger/Tests/TestLibCython.py
+11
-0
Cython/Debugger/Tests/codefile
Cython/Debugger/Tests/codefile
+15
-4
Cython/Debugger/Tests/test_libcython_in_gdb.py
Cython/Debugger/Tests/test_libcython_in_gdb.py
+69
-7
Cython/Debugger/libcython.py
Cython/Debugger/libcython.py
+305
-245
Cython/Debugger/libpython.py
Cython/Debugger/libpython.py
+396
-335
runtests.py
runtests.py
+28
-28
setup.py
setup.py
+3
-2
No files found.
Cython/Compiler/Main.py
View file @
c5e16a3f
...
@@ -18,7 +18,11 @@ from time import time
...
@@ -18,7 +18,11 @@ from time import time
import
Code
import
Code
import
Errors
import
Errors
import
Parsing
# Do not import Parsing here, import it when needed, because Parsing imports
# Nodes, which globally needs debug command line options initialized to set a
# conditional metaclass. These options are processed by CmdLine called from
# main() in this file.
# import Parsing
import
Version
import
Version
from
Scanning
import
PyrexScanner
,
FileSourceDescriptor
from
Scanning
import
PyrexScanner
,
FileSourceDescriptor
from
Errors
import
PyrexError
,
CompileError
,
InternalError
,
AbortError
,
error
,
warning
from
Errors
import
PyrexError
,
CompileError
,
InternalError
,
AbortError
,
error
,
warning
...
@@ -68,7 +72,7 @@ class Context(object):
...
@@ -68,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
}
...
@@ -85,7 +89,7 @@ class Context(object):
...
@@ -85,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
):
...
@@ -120,12 +124,12 @@ class Context(object):
...
@@ -120,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
),
...
@@ -190,7 +194,7 @@ class Context(object):
...
@@ -190,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
),
...
@@ -214,7 +218,7 @@ class Context(object):
...
@@ -214,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
)
...
@@ -223,7 +227,7 @@ class Context(object):
...
@@ -223,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
)
...
@@ -253,7 +257,7 @@ class Context(object):
...
@@ -253,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
...
@@ -323,7 +327,7 @@ class Context(object):
...
@@ -323,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.
...
@@ -358,7 +362,7 @@ class Context(object):
...
@@ -358,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.
...
@@ -367,7 +371,7 @@ class Context(object):
...
@@ -367,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
...
@@ -448,15 +452,15 @@ class Context(object):
...
@@ -448,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
):
...
@@ -482,7 +486,7 @@ class Context(object):
...
@@ -482,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
...
@@ -496,6 +500,7 @@ class Context(object):
...
@@ -496,6 +500,7 @@ class Context(object):
try
:
try
:
f
=
Utils
.
open_source_file
(
source_filename
,
"rU"
)
f
=
Utils
.
open_source_file
(
source_filename
,
"rU"
)
try
:
try
:
import
Parsing
s
=
PyrexScanner
(
f
,
source_desc
,
source_encoding
=
f
.
encoding
,
s
=
PyrexScanner
(
f
,
source_desc
,
source_encoding
=
f
.
encoding
,
scope
=
scope
,
context
=
self
)
scope
=
scope
,
context
=
self
)
tree
=
Parsing
.
p_module
(
s
,
pxd
,
full_module_name
)
tree
=
Parsing
.
p_module
(
s
,
pxd
,
full_module_name
)
...
@@ -601,7 +606,7 @@ def run_pipeline(source, options, full_module_name = None):
...
@@ -601,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
)
...
@@ -612,7 +617,7 @@ def run_pipeline(source, options, full_module_name = None):
...
@@ -612,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
#------------------------------------------------------------------------
#------------------------------------------------------------------------
#
#
...
@@ -633,7 +638,7 @@ class CompilationSource(object):
...
@@ -633,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
...
@@ -648,10 +653,10 @@ class CompilationOptions(object):
...
@@ -648,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
:
...
@@ -670,7 +675,7 @@ class CompilationOptions(object):
...
@@ -670,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
...
@@ -681,7 +686,7 @@ class CompilationResult(object):
...
@@ -681,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
...
@@ -698,10 +703,10 @@ class CompilationResultSet(dict):
...
@@ -698,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
):
...
@@ -712,7 +717,7 @@ class CompilationResultSet(dict):
...
@@ -712,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.
...
@@ -723,7 +728,7 @@ def compile_single(source, options, full_module_name = None):
...
@@ -723,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.
...
@@ -761,7 +766,7 @@ def compile_multiple(sources, options):
...
@@ -761,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
...
...
Cython/Compiler/ParseTreeTransforms.py
View file @
c5e16a3f
...
@@ -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,67 +1581,88 @@ class DebugTransform(CythonTransform):
...
@@ -1581,67 +1581,88 @@ 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
# never nested
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...
self
.
visitchildren
(
node
)
self
.
visitchildren
(
node
)
# ... then, serialize nested functions
for
nested_funcdef
in
self
.
nested_funcdefs
:
self
.
visit_FuncDefNode
(
nested_funcdef
)
self
.
register_stepinto
=
True
self
.
serialize_modulenode_as_function
(
node
)
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
):
return
node
if
self
.
register_stepinto
:
self
.
nested_funcdefs
.
append
(
node
)
return
node
# node.entry.visibility = 'extern'
# node.entry.visibility = 'extern'
if
node
.
py_func
is
None
:
if
node
.
py_func
is
None
:
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'
)
...
@@ -1662,32 +1683,90 @@ class DebugTransform(CythonTransform):
...
@@ -1662,32 +1683,90 @@ 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
):
"""
Serialize the module-level code as a function so the debugger will know
it's a "relevant frame" and it will know where to set the breakpoint
for 'break modulename'.
"""
name
=
node
.
full_module_name
.
rpartition
(
'.'
)[
-
1
]
cname_py2
=
'init'
+
name
cname_py3
=
'PyInit_'
+
name
py2_attrs
=
dict
(
name
=
name
,
cname
=
cname_py2
,
pf_cname
=
''
,
# Ignore the qualified_name, breakpoints should be set using
# `cy break modulename:lineno` for module-level breakpoints.
qualified_name
=
''
,
lineno
=
'1'
,
is_initmodule_function
=
"True"
,
)
py3_attrs
=
dict
(
py2_attrs
,
cname
=
cname_py3
)
self
.
_serialize_modulenode_as_function
(
node
,
py2_attrs
)
self
.
_serialize_modulenode_as_function
(
node
,
py3_attrs
)
def
_serialize_modulenode_as_function
(
self
,
node
,
attrs
):
self
.
tb
.
start
(
'Function'
,
attrs
=
attrs
)
self
.
tb
.
start
(
'Locals'
)
self
.
serialize_local_variables
(
node
.
scope
.
entries
)
self
.
tb
.
end
(
'Locals'
)
self
.
tb
.
start
(
'Arguments'
)
self
.
tb
.
end
(
'Arguments'
)
self
.
tb
.
start
(
'StepIntoFunctions'
)
self
.
register_stepinto
=
True
self
.
visitchildren
(
node
)
self
.
register_stepinto
=
False
self
.
tb
.
end
(
'StepIntoFunctions'
)
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'
cname
=
entry
.
cname
if
entry
.
from_closure
:
# if entry.type.is_extension_type:
# We're dealing with a closure where a variable from an outer
# cname = entry.type.typeptr_cname
# scope is accessed, get it from the scope object.
cname
=
'%s->%s'
%
(
Naming
.
cur_scope_cname
,
entry
.
outer_entry
.
cname
)
qname
=
'%s.%s.%s'
%
(
entry
.
scope
.
outer_scope
.
qualified_name
,
entry
.
scope
.
name
,
entry
.
name
)
elif
entry
.
in_closure
:
cname
=
'%s->%s'
%
(
Naming
.
cur_scope_cname
,
entry
.
cname
)
qname
=
entry
.
qualified_name
else
:
cname
=
entry
.
cname
qname
=
entry
.
qualified_name
if
not
entry
.
pos
:
if
not
entry
.
pos
:
# this happens for variables that are not in the user's code,
# this happens for variables that are not in the user's code,
...
@@ -1696,14 +1775,14 @@ class DebugTransform(CythonTransform):
...
@@ -1696,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
=
entry
.
qualified_
name
,
qualified_name
=
q
name
,
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'
)
Cython/Compiler/Tests/TestParseTreeTransforms.py
View file @
c5e16a3f
...
@@ -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,22 +171,23 @@ class TestDebugTransform(DebuggerTestCase):
...
@@ -171,22 +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'
)
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
)
...
@@ -198,12 +199,12 @@ class TestDebugTransform(DebuggerTestCase):
...
@@ -198,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
]
...
@@ -214,10 +215,10 @@ class TestDebugTransform(DebuggerTestCase):
...
@@ -214,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
...
...
Cython/Debugger/Tests/TestLibCython.py
View file @
c5e16a3f
...
@@ -16,6 +16,7 @@ from distutils import ccompiler
...
@@ -16,6 +16,7 @@ from distutils import ccompiler
import
runtests
import
runtests
import
Cython.Distutils.extension
import
Cython.Distutils.extension
import
Cython.Distutils.build_ext
from
Cython.Debugger
import
Cygdb
as
cygdb
from
Cython.Debugger
import
Cygdb
as
cygdb
root
=
os
.
path
.
dirname
(
os
.
path
.
abspath
(
__file__
))
root
=
os
.
path
.
dirname
(
os
.
path
.
abspath
(
__file__
))
...
@@ -24,6 +25,10 @@ cfuncs_file = os.path.join(root, 'cfuncs.c')
...
@@ -24,6 +25,10 @@ cfuncs_file = os.path.join(root, 'cfuncs.c')
with
open
(
codefile
)
as
f
:
with
open
(
codefile
)
as
f
:
source_to_lineno
=
dict
((
line
.
strip
(),
i
+
1
)
for
i
,
line
in
enumerate
(
f
))
source_to_lineno
=
dict
((
line
.
strip
(),
i
+
1
)
for
i
,
line
in
enumerate
(
f
))
# Cython.Distutils.__init__ imports build_ext from build_ext which means we
# can't access the module anymore. Get it from sys.modules instead.
build_ext
=
sys
.
modules
[
'Cython.Distutils.build_ext'
]
class
DebuggerTestCase
(
unittest
.
TestCase
):
class
DebuggerTestCase
(
unittest
.
TestCase
):
def
setUp
(
self
):
def
setUp
(
self
):
...
@@ -52,6 +57,9 @@ class DebuggerTestCase(unittest.TestCase):
...
@@ -52,6 +57,9 @@ class DebuggerTestCase(unittest.TestCase):
module
=
'codefile'
,
module
=
'codefile'
,
)
)
optimization_disabler
=
build_ext
.
Optimization
()
optimization_disabler
.
disable_optimization
()
cython_compile_testcase
=
runtests
.
CythonCompileTestCase
(
cython_compile_testcase
=
runtests
.
CythonCompileTestCase
(
workdir
=
self
.
tempdir
,
workdir
=
self
.
tempdir
,
# we clean up everything (not only compiled files)
# we clean up everything (not only compiled files)
...
@@ -77,6 +85,8 @@ class DebuggerTestCase(unittest.TestCase):
...
@@ -77,6 +85,8 @@ class DebuggerTestCase(unittest.TestCase):
**
opts
**
opts
)
)
optimization_disabler
.
restore_state
()
# ext = Cython.Distutils.extension.Extension(
# ext = Cython.Distutils.extension.Extension(
# 'codefile',
# 'codefile',
# ['codefile.pyx'],
# ['codefile.pyx'],
...
@@ -95,6 +105,7 @@ class DebuggerTestCase(unittest.TestCase):
...
@@ -95,6 +105,7 @@ class DebuggerTestCase(unittest.TestCase):
class
GdbDebuggerTestCase
(
DebuggerTestCase
):
class
GdbDebuggerTestCase
(
DebuggerTestCase
):
def
setUp
(
self
):
def
setUp
(
self
):
super
(
GdbDebuggerTestCase
,
self
).
setUp
()
super
(
GdbDebuggerTestCase
,
self
).
setUp
()
...
...
Cython/Debugger/Tests/codefile
View file @
c5e16a3f
...
@@ -21,16 +21,27 @@ def spam(a=0):
...
@@ -21,16 +21,27 @@ def spam(a=0):
puts("spam")
puts("spam")
os.path.join("foo", "bar")
os.path.join("foo", "bar")
some_c_function()
some_c_function()
cpdef eggs():
pass
cdef ham():
cdef ham():
pass
pass
cpdef eggs():
pass
cdef class SomeClass(object):
cdef class SomeClass(object):
def spam(self):
def spam(self):
pass
pass
def outer():
cdef object a = "an object"
def inner():
b = 2
# access closed over variables
print a, b
return inner
outer()()
spam()
spam()
print "bye!"
print "bye!"
\ No newline at end of file
Cython/Debugger/Tests/test_libcython_in_gdb.py
View file @
c5e16a3f
...
@@ -14,6 +14,7 @@ import warnings
...
@@ -14,6 +14,7 @@ import warnings
import
unittest
import
unittest
import
textwrap
import
textwrap
import
tempfile
import
tempfile
import
functools
import
traceback
import
traceback
import
itertools
import
itertools
from
test
import
test_support
from
test
import
test_support
...
@@ -28,12 +29,35 @@ from Cython.Debugger.Tests import TestLibCython as test_libcython
...
@@ -28,12 +29,35 @@ from Cython.Debugger.Tests import TestLibCython as test_libcython
sys
.
argv
=
[
'gdb'
]
sys
.
argv
=
[
'gdb'
]
def
print_on_call_decorator
(
func
):
@
functools
.
wraps
(
func
)
def
wrapper
(
self
,
*
args
,
**
kwargs
):
_debug
(
type
(
self
).
__name__
,
func
.
__name__
)
try
:
return
func
(
self
,
*
args
,
**
kwargs
)
except
Exception
,
e
:
_debug
(
"An exception occurred:"
,
traceback
.
format_exc
(
e
))
raise
return
wrapper
class
TraceMethodCallMeta
(
type
):
def
__init__
(
self
,
name
,
bases
,
dict
):
for
func_name
,
func
in
dict
.
iteritems
():
if
inspect
.
isfunction
(
func
):
setattr
(
self
,
func_name
,
print_on_call_decorator
(
func
))
class
DebugTestCase
(
unittest
.
TestCase
):
class
DebugTestCase
(
unittest
.
TestCase
):
"""
"""
Base class for test cases. On teardown it kills the inferior and unsets
Base class for test cases. On teardown it kills the inferior and unsets
all breakpoints.
all breakpoints.
"""
"""
__metaclass__
=
TraceMethodCallMeta
def
__init__
(
self
,
name
):
def
__init__
(
self
,
name
):
super
(
DebugTestCase
,
self
).
__init__
(
name
)
super
(
DebugTestCase
,
self
).
__init__
(
name
)
self
.
cy
=
libcython
.
cy
self
.
cy
=
libcython
.
cy
...
@@ -58,7 +82,7 @@ class DebugTestCase(unittest.TestCase):
...
@@ -58,7 +82,7 @@ class DebugTestCase(unittest.TestCase):
if
source_line
is
not
None
:
if
source_line
is
not
None
:
lineno
=
test_libcython
.
source_to_lineno
[
source_line
]
lineno
=
test_libcython
.
source_to_lineno
[
source_line
]
frame
=
gdb
.
selected_frame
()
frame
=
gdb
.
selected_frame
()
self
.
assertEqual
(
libcython
.
cy
.
step
.
lineno
(
frame
),
lineno
)
self
.
assertEqual
(
libcython
.
cy
thon_info
.
lineno
(
frame
),
lineno
)
def
break_and_run
(
self
,
source_line
):
def
break_and_run
(
self
,
source_line
):
break_lineno
=
test_libcython
.
source_to_lineno
[
source_line
]
break_lineno
=
test_libcython
.
source_to_lineno
[
source_line
]
...
@@ -74,9 +98,6 @@ class DebugTestCase(unittest.TestCase):
...
@@ -74,9 +98,6 @@ class DebugTestCase(unittest.TestCase):
gdb
.
execute
(
'set args -c "import codefile"'
)
gdb
.
execute
(
'set args -c "import codefile"'
)
libcython
.
cy
.
step
.
static_breakpoints
.
clear
()
libcython
.
cy
.
step
.
runtime_breakpoints
.
clear
()
libcython
.
cy
.
step
.
init_breakpoints
()
class
TestDebugInformationClasses
(
DebugTestCase
):
class
TestDebugInformationClasses
(
DebugTestCase
):
...
@@ -101,7 +122,7 @@ class TestDebugInformationClasses(DebugTestCase):
...
@@ -101,7 +122,7 @@ class TestDebugInformationClasses(DebugTestCase):
'codefile.SomeClass.spam'
)
'codefile.SomeClass.spam'
)
self
.
assertEqual
(
self
.
spam_func
.
module
,
self
.
module
)
self
.
assertEqual
(
self
.
spam_func
.
module
,
self
.
module
)
assert
self
.
eggs_func
.
pf_cname
assert
self
.
eggs_func
.
pf_cname
,
(
self
.
eggs_func
,
self
.
eggs_func
.
pf_cname
)
assert
not
self
.
ham_func
.
pf_cname
assert
not
self
.
ham_func
.
pf_cname
assert
not
self
.
spam_func
.
pf_cname
assert
not
self
.
spam_func
.
pf_cname
assert
not
self
.
spam_meth
.
pf_cname
assert
not
self
.
spam_meth
.
pf_cname
...
@@ -130,7 +151,7 @@ class TestParameters(unittest.TestCase):
...
@@ -130,7 +151,7 @@ class TestParameters(unittest.TestCase):
class
TestBreak
(
DebugTestCase
):
class
TestBreak
(
DebugTestCase
):
def
test_break
(
self
):
def
test_break
(
self
):
breakpoint_amount
=
len
(
gdb
.
breakpoints
())
breakpoint_amount
=
len
(
gdb
.
breakpoints
()
or
()
)
gdb
.
execute
(
'cy break codefile.spam'
)
gdb
.
execute
(
'cy break codefile.spam'
)
self
.
assertEqual
(
len
(
gdb
.
breakpoints
()),
breakpoint_amount
+
1
)
self
.
assertEqual
(
len
(
gdb
.
breakpoints
()),
breakpoint_amount
+
1
)
...
@@ -143,6 +164,16 @@ class TestBreak(DebugTestCase):
...
@@ -143,6 +164,16 @@ class TestBreak(DebugTestCase):
gdb
.
execute
(
'cy break -p join'
)
gdb
.
execute
(
'cy break -p join'
)
assert
'def join('
in
gdb
.
execute
(
'cy run'
,
to_string
=
True
)
assert
'def join('
in
gdb
.
execute
(
'cy run'
,
to_string
=
True
)
def
test_break_lineno
(
self
):
beginline
=
'import os'
nextline
=
'cdef int c_var = 12'
self
.
break_and_run
(
beginline
)
self
.
lineno_equals
(
beginline
)
step_result
=
gdb
.
execute
(
'cy step'
,
to_string
=
True
)
self
.
lineno_equals
(
nextline
)
assert
step_result
.
rstrip
().
endswith
(
nextline
)
class
TestKilled
(
DebugTestCase
):
class
TestKilled
(
DebugTestCase
):
...
@@ -151,6 +182,7 @@ class TestKilled(DebugTestCase):
...
@@ -151,6 +182,7 @@ class TestKilled(DebugTestCase):
output
=
gdb
.
execute
(
'cy run'
,
to_string
=
True
)
output
=
gdb
.
execute
(
'cy run'
,
to_string
=
True
)
assert
'abort'
in
output
.
lower
()
assert
'abort'
in
output
.
lower
()
class
DebugStepperTestCase
(
DebugTestCase
):
class
DebugStepperTestCase
(
DebugTestCase
):
def
step
(
self
,
varnames_and_values
,
source_line
=
None
,
lineno
=
None
):
def
step
(
self
,
varnames_and_values
,
source_line
=
None
,
lineno
=
None
):
...
@@ -262,7 +294,7 @@ class TestBacktrace(DebugTestCase):
...
@@ -262,7 +294,7 @@ class TestBacktrace(DebugTestCase):
gdb
.
execute
(
'cy bt'
)
gdb
.
execute
(
'cy bt'
)
result
=
gdb
.
execute
(
'cy bt -a'
,
to_string
=
True
)
result
=
gdb
.
execute
(
'cy bt -a'
,
to_string
=
True
)
assert
re
.
search
(
r'\
#
0 *0x.* in main\
(
\)
at
'
,
result
),
result
assert
re
.
search
(
r'\
#
0 *0x.* in main\
(
\)'
,
result
),
result
class
TestFunctions
(
DebugTestCase
):
class
TestFunctions
(
DebugTestCase
):
...
@@ -344,6 +376,36 @@ class TestExec(DebugTestCase):
...
@@ -344,6 +376,36 @@ class TestExec(DebugTestCase):
gdb
.
execute
(
'cy exec some_random_var = 14'
)
gdb
.
execute
(
'cy exec some_random_var = 14'
)
self
.
assertEqual
(
'14'
,
self
.
eval_command
(
'some_random_var'
))
self
.
assertEqual
(
'14'
,
self
.
eval_command
(
'some_random_var'
))
class
TestClosure
(
DebugTestCase
):
def
break_and_run_func
(
self
,
funcname
):
gdb
.
execute
(
'cy break '
+
funcname
)
gdb
.
execute
(
'cy run'
)
def
test_inner
(
self
):
self
.
break_and_run_func
(
'inner'
)
self
.
assertEqual
(
''
,
gdb
.
execute
(
'cy locals'
,
to_string
=
True
))
# Allow the Cython-generated code to initialize the scope variable
gdb
.
execute
(
'cy step'
)
self
.
assertEqual
(
str
(
self
.
read_var
(
'a'
)),
"'an object'"
)
print_result
=
gdb
.
execute
(
'cy print a'
,
to_string
=
True
).
strip
()
self
.
assertEqual
(
print_result
,
"a = 'an object'"
)
def
test_outer
(
self
):
self
.
break_and_run_func
(
'outer'
)
self
.
assertEqual
(
''
,
gdb
.
execute
(
'cy locals'
,
to_string
=
True
))
# Initialize scope with 'a' uninitialized
gdb
.
execute
(
'cy step'
)
self
.
assertEqual
(
''
,
gdb
.
execute
(
'cy locals'
,
to_string
=
True
))
# Initialize 'a' to 1
gdb
.
execute
(
'cy step'
)
print_result
=
gdb
.
execute
(
'cy print a'
,
to_string
=
True
).
strip
()
self
.
assertEqual
(
print_result
,
"a = 'an object'"
)
_do_debug
=
os
.
environ
.
get
(
'GDB_DEBUG'
)
_do_debug
=
os
.
environ
.
get
(
'GDB_DEBUG'
)
if
_do_debug
:
if
_do_debug
:
...
...
Cython/Debugger/libcython.py
View file @
c5e16a3f
...
@@ -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,10 +153,7 @@ class CythonModule(object):
...
@@ -153,10 +153,7 @@ class CythonModule(object):
# {c_lineno: cython_lineno}
# {c_lineno: cython_lineno}
self
.
lineno_c2cy
=
{}
self
.
lineno_c2cy
=
{}
self
.
functions
=
{}
self
.
functions
=
{}
def
qualified_name
(
self
,
varname
):
return
'.'
.
join
(
self
.
name
,
varname
)
class
CythonVariable
(
object
):
class
CythonVariable
(
object
):
def
__init__
(
self
,
name
,
cname
,
qualified_name
,
type
,
lineno
):
def
__init__
(
self
,
name
,
cname
,
qualified_name
,
type
,
lineno
):
...
@@ -167,21 +164,23 @@ class CythonVariable(object):
...
@@ -167,21 +164,23 @@ 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
,
super
(
CythonFunction
,
self
).
__init__
(
name
,
is_initmodule_function
=
"False"
):
cname
,
super
(
CythonFunction
,
self
).
__init__
(
name
,
qualified_name
,
cname
,
qualified_name
,
type
,
type
,
lineno
)
lineno
)
self
.
module
=
module
self
.
module
=
module
self
.
pf_cname
=
pf_cname
self
.
pf_cname
=
pf_cname
self
.
is_initmodule_function
=
is_initmodule_function
==
"True"
self
.
locals
=
{}
self
.
locals
=
{}
self
.
arguments
=
[]
self
.
arguments
=
[]
self
.
step_into_functions
=
set
()
self
.
step_into_functions
=
set
()
...
@@ -190,7 +189,7 @@ class CythonFunction(CythonVariable):
...
@@ -190,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
...
@@ -205,7 +204,7 @@ class CythonBase(object):
...
@@ -205,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
()
...
@@ -213,24 +212,24 @@ class CythonBase(object):
...
@@ -213,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
...
@@ -243,11 +242,12 @@ class CythonBase(object):
...
@@ -243,11 +242,12 @@ class CythonBase(object):
pyframeobject
=
libpython
.
Frame
(
frame
).
get_pyop
()
pyframeobject
=
libpython
.
Frame
(
frame
).
get_pyop
()
if
not
pyframeobject
:
if
not
pyframeobject
:
raise
gdb
.
GdbError
(
'Unable to read information on python frame'
)
raise
gdb
.
GdbError
(
'Unable to read information on python frame'
)
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
:
...
@@ -256,18 +256,18 @@ class CythonBase(object):
...
@@ -256,18 +256,18 @@ class CythonBase(object):
filename
=
None
filename
=
None
lineno
=
0
lineno
=
0
else
:
else
:
filename
=
symbol_and_line_obj
.
symtab
.
f
ilename
filename
=
symbol_and_line_obj
.
symtab
.
f
ullname
()
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,18 +381,28 @@ class CythonBase(object):
...
@@ -381,18 +381,28 @@ 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
):
islocal
=
local_name
in
cython_func
.
locals
if
islocal
:
cyvar
=
cython_func
.
locals
[
local_name
]
if
'->'
in
cyvar
.
cname
:
# Closed over free variable
if
self
.
get_cython_lineno
()
>=
cython_func
.
lineno
+
1
:
if
cyvar
.
type
==
PythonObject
:
return
long
(
gdb
.
parse_and_eval
(
cyvar
.
cname
))
return
True
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
(
local_name
in
cython_func
.
locals
and
(
islocal
and
cur_lineno
>
cyvar
.
lineno
))
cur_lineno
>
cython_func
.
locals
[
local_name
].
lineno
))
class
SourceFileDescriptor
(
object
):
class
SourceFileDescriptor
(
object
):
def
__init__
(
self
,
filename
,
lexer
,
formatter
=
None
):
def
__init__
(
self
,
filename
,
lexer
,
formatter
=
None
):
...
@@ -420,30 +430,30 @@ class SourceFileDescriptor(object):
...
@@ -420,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
...
@@ -461,21 +471,21 @@ class CyGDBError(gdb.GdbError):
...
@@ -461,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 '
...
@@ -488,23 +498,23 @@ class CythonParameter(gdb.Parameter):
...
@@ -488,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
):
"""
"""
...
@@ -521,7 +531,7 @@ class CythonParameters(object):
...
@@ -521,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'
,
...
@@ -538,7 +548,7 @@ class CythonParameters(object):
...
@@ -538,7 +548,7 @@ class CythonParameters(object):
gdb
.
COMMAND_FILES
,
gdb
.
COMMAND_FILES
,
gdb
.
PARAM_STRING
,
gdb
.
PARAM_STRING
,
"dark"
)
"dark"
)
parameters
=
CythonParameters
()
parameters
=
CythonParameters
()
...
@@ -548,30 +558,30 @@ class CythonCommand(gdb.Command, CythonBase):
...
@@ -548,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
...
@@ -589,16 +599,16 @@ class CyCy(CythonCommand):
...
@@ -589,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
(),
...
@@ -621,24 +631,24 @@ class CyCy(CythonCommand):
...
@@ -621,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
)
...
@@ -648,46 +658,46 @@ class CyImport(CythonCommand):
...
@@ -648,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
)
...
@@ -695,7 +705,7 @@ class CyImport(CythonCommand):
...
@@ -695,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'
))
...
@@ -706,36 +716,34 @@ class CyImport(CythonCommand):
...
@@ -706,36 +716,34 @@ class CyImport(CythonCommand):
for
c_lineno
in
c_linenos
:
for
c_lineno
in
c_linenos
:
cython_module
.
lineno_c2cy
[
c_lineno
]
=
cython_lineno
cython_module
.
lineno_c2cy
[
c_lineno
]
=
cython_lineno
self
.
cy
.
step
.
init_breakpoints
()
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
)
...
@@ -751,23 +759,29 @@ class CyBreak(CythonCommand):
...
@@ -751,23 +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
:
func
=
None
break_funcs
=
[
func
]
break_funcs
=
[
func
]
if
not
func
:
if
not
func
:
funcs
=
self
.
cy
.
functions_by_name
.
get
(
funcname
)
funcs
=
self
.
cy
.
functions_by_name
.
get
(
funcname
)
or
[]
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
(
...
@@ -781,7 +795,7 @@ class CyBreak(CythonCommand):
...
@@ -781,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
...
@@ -789,12 +803,12 @@ class CyBreak(CythonCommand):
...
@@ -789,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'
):
...
@@ -802,7 +816,7 @@ class CyBreak(CythonCommand):
...
@@ -802,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
)
...
@@ -810,37 +824,46 @@ class CyBreak(CythonCommand):
...
@@ -810,37 +824,46 @@ 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
):
names
=
self
.
cy
.
functions_by_qualified_name
# Filter init-module functions (breakpoints can be set using
# modulename:linenumber).
names
=
[
n
for
n
,
L
in
self
.
cy
.
functions_by_name
.
iteritems
()
if
any
(
not
f
.
is_initmodule_function
for
f
in
L
)]
qnames
=
[
n
for
n
,
f
in
self
.
cy
.
functions_by_qualified_name
.
iteritems
()
if
not
f
.
is_initmodule_function
]
if
parameters
.
complete_unqualified
:
if
parameters
.
complete_unqualified
:
names
=
itertools
.
chain
(
names
,
self
.
cy
.
functions_by_name
)
all_names
=
itertools
.
chain
(
qnames
,
names
)
else
:
all_names
=
qnames
words
=
text
.
strip
().
split
()
words
=
text
.
strip
().
split
()
if
words
and
'.'
in
words
[
-
1
]:
if
not
words
or
'.'
not
in
words
[
-
1
]:
lastword
=
words
[
-
1
]
# complete unqualified
compl
=
[
n
for
n
in
self
.
cy
.
functions_by_qualified_name
if
n
.
startswith
(
lastword
)]
else
:
seen
=
set
(
text
[:
-
len
(
word
)].
split
())
seen
=
set
(
text
[:
-
len
(
word
)].
split
())
return
[
n
for
n
in
names
if
n
.
startswith
(
word
)
and
n
not
in
seen
]
return
[
n
for
n
in
all_names
if
n
.
startswith
(
word
)
and
n
not
in
seen
]
# complete qualified name
lastword
=
words
[
-
1
]
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
class
Cython
CodeStepper
(
CythonCommand
,
libpython
.
GenericCodeStepper
):
class
Cython
Info
(
CythonBase
,
libpython
.
PythonInfo
):
"""
"""
Base class for CyStep and CyNext. It implements the interface dictated by
Implementation of the interface dictated by libpython.LanguageInfo.
libpython.GenericCodeStepper.
"""
"""
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
...
@@ -848,84 +871,94 @@ class CythonCodeStepper(CythonCommand, libpython.GenericCodeStepper):
...
@@ -848,84 +871,94 @@ class CythonCodeStepper(CythonCommand, libpython.GenericCodeStepper):
# related code. The C level should be dispatched to the 'step' command.
# related code. The C level should be dispatched to the 'step' command.
if
self
.
is_cython_function
(
frame
):
if
self
.
is_cython_function
(
frame
):
return
self
.
get_cython_lineno
(
frame
)
return
self
.
get_cython_lineno
(
frame
)
else
:
return
super
(
CythonInfo
,
self
).
lineno
(
frame
)
return
libpython
.
py_step
.
lineno
(
frame
)
def
get_source_line
(
self
,
frame
):
def
get_source_line
(
self
,
frame
):
try
:
try
:
line
=
super
(
Cython
CodeStepper
,
self
).
get_source_line
(
frame
)
line
=
super
(
Cython
Info
,
self
).
get_source_line
(
frame
)
except
gdb
.
GdbError
:
except
gdb
.
GdbError
:
return
None
return
None
else
:
else
:
return
line
.
strip
()
or
None
return
line
.
strip
()
or
None
@
classmethod
def
exc_info
(
self
,
frame
):
def
register
(
cls
)
:
if
self
.
is_python_function
:
return
cls
(
cls
.
name
,
stepinto
=
getattr
(
cls
,
'stepinto'
,
False
)
)
return
super
(
CythonInfo
,
self
).
exc_info
(
frame
)
def
runtime_break_functions
(
self
):
def
runtime_break_functions
(
self
):
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
()
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
,
libpython
.
ExecutionControlCommandBase
):
@
classmethod
def
register
(
cls
):
return
cls
(
cls
.
name
,
cython_info
)
class
CyStep
(
CythonExecutionControlCommand
,
libpython
.
PythonStepperMixin
):
"Step through Cython, Python or C code."
name
=
'cy -step'
stepinto
=
True
def
invoke
(
self
,
args
,
from_tty
):
def
invoke
(
self
,
args
,
from_tty
):
if
not
self
.
is_cython_function
()
and
not
self
.
is_python_function
():
if
self
.
is_python_function
():
self
.
python_step
(
self
.
stepinto
)
elif
not
self
.
is_cython_function
():
if
self
.
stepinto
:
if
self
.
stepinto
:
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
()
self
.
step
(
stepinto
=
self
.
stepinto
)
class
CyStep
(
CythonCodeStepper
):
class
CyNext
(
CyStep
):
"Step through Cython, Python or C code."
"Step-over Cython, Python or C code."
name
=
'cy step'
stepinto
=
True
name
=
'cy -next'
class
CyNext
(
CythonCodeStepper
):
"Step-over Python code."
name
=
'cy next'
stepinto
=
False
stepinto
=
False
class
CyRun
(
Cython
CodeStepper
):
class
CyRun
(
Cython
ExecutionControlCommand
):
"""
"""
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
=
CythonCodeStepper
.
run
class
CyCont
(
CythonExecutionControlCommand
):
class
CyCont
(
CyRun
):
"""
"""
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
=
Cython
CodeStepper
.
cont
invoke
=
Cython
ExecutionControlCommand
.
cont
class
CyFinish
(
Cy
Run
):
class
CyFinish
(
Cy
thonExecutionControlCommand
):
"""
"""
Execute until the function returns.
Execute until the function returns.
"""
"""
name
=
'cy finish'
name
=
'cy finish'
invoke
=
Cython
CodeStepper
.
finish
invoke
=
Cython
ExecutionControlCommand
.
finish
class
CyUp
(
CythonCommand
):
class
CyUp
(
CythonCommand
):
...
@@ -934,7 +967,7 @@ class CyUp(CythonCommand):
...
@@ -934,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
)
...
@@ -942,13 +975,13 @@ class CyUp(CythonCommand):
...
@@ -942,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
)
...
@@ -956,31 +989,31 @@ class CyDown(CyUp):
...
@@ -956,31 +989,31 @@ 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'
class
CySelect
(
CythonCo
deStepper
):
class
CySelect
(
CythonCo
mmand
):
"""
"""
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
=
self
.
_
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
:
...
@@ -989,37 +1022,37 @@ class CySelect(CythonCodeStepper):
...
@@ -989,37 +1022,37 @@ class CySelect(CythonCodeStepper):
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
()
...
@@ -1028,15 +1061,15 @@ class CyList(CythonCommand):
...
@@ -1028,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
...
@@ -1045,10 +1078,10 @@ class CyPrint(CythonCommand):
...
@@ -1045,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
)
...
@@ -1059,11 +1092,11 @@ class CyPrint(CythonCommand):
...
@@ -1059,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
()
...
@@ -1078,20 +1111,26 @@ class CyLocals(CythonCommand):
...
@@ -1078,20 +1111,26 @@ 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
):
local_cython_vars
=
self
.
get_cython_function
().
locals
cython_function
=
self
.
get_cython_function
()
if
cython_function
.
is_initmodule_function
:
self
.
cy
.
globals
.
invoke
(
args
,
from_tty
)
return
local_cython_vars
=
cython_function
.
locals
max_name_length
=
len
(
max
(
local_cython_vars
,
key
=
len
))
max_name_length
=
len
(
max
(
local_cython_vars
,
key
=
len
))
for
name
,
cyvar
in
sorted
(
local_cython_vars
.
iteritems
(),
key
=
sortkey
):
for
name
,
cyvar
in
sorted
(
local_cython_vars
.
iteritems
(),
key
=
sortkey
):
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
,
''
)
...
@@ -1099,32 +1138,32 @@ class CyGlobals(CyLocals):
...
@@ -1099,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
:
...
@@ -1142,20 +1181,20 @@ class CyExec(CythonCommand, libpython.PyExec):
...
@@ -1142,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
:
...
@@ -1163,7 +1202,7 @@ class CyExec(CythonCommand, libpython.PyExec):
...
@@ -1163,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(
...
@@ -1179,38 +1218,38 @@ class CyExec(CythonCommand, libpython.PyExec):
...
@@ -1179,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
:
...
@@ -1223,18 +1262,18 @@ class CyCName(gdb.Function, CythonBase):
...
@@ -1223,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
:
...
@@ -1245,13 +1284,13 @@ class CyCName(gdb.Function, CythonBase):
...
@@ -1245,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
...
@@ -1259,31 +1298,52 @@ class CyCValue(CyCName):
...
@@ -1259,31 +1298,52 @@ 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
):
try
:
globals_dict
=
self
.
get_cython_globals_dict
()
cython_function
=
self
.
get_cython_function
(
frame
)
if
self
.
is_initialized
(
cython_function
,
cyname
):
cname
=
super
(
CyCValue
,
self
).
invoke
(
cyname
,
frame
=
frame
)
cname
=
super
(
CyCValue
,
self
).
invoke
(
cyname
,
frame
=
frame
)
return
gdb
.
parse_and_eval
(
cname
)
return
gdb
.
parse_and_eval
(
cname
)
except
(
gdb
.
GdbError
,
RuntimeError
),
e
:
elif
cyname
in
globals_dict
:
# variable exists but may not have been initialized yet, or may be
return
globals_dict
[
cyname
].
_gdbval
# in the globals dict of the Cython module
else
:
d
=
self
.
get_cython_globals_dict
()
raise
gdb
.
GdbError
(
"Variable %s is not initialized."
%
cyname
)
if
cyname
in
d
:
return
d
[
cyname
].
_gdbval
raise
gdb
.
GdbError
(
str
(
e
))
class
CyLine
(
gdb
.
Function
,
CythonBase
):
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
()
cython_info
=
CythonInfo
()
cy
=
CyCy
.
register
()
cy
=
CyCy
.
register
()
cython_info
.
cy
=
cy
def
register_defines
():
libpython
.
source_gdb_script
(
textwrap
.
dedent
(
"""
\
define cy step
cy -step
end
define cy next
cy -next
end
document cy step
%s
end
document cy next
%s
end
"""
)
%
(
CyStep
.
__doc__
,
CyNext
.
__doc__
))
register_defines
()
\ No newline at end of file
Cython/Debugger/libpython.py
View file @
c5e16a3f
...
@@ -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,9 +368,9 @@ class PyObjectPtr(object):
...
@@ -368,9 +368,9 @@ 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
:
if
tp_flags
&
(
Py_TPFLAGS_HEAPTYPE
|
Py_TPFLAGS_TYPE_SUBCLASS
)
:
return
Heap
TypeObjectPtr
return
Py
TypeObjectPtr
if
tp_flags
&
Py_TPFLAGS_INT_SUBCLASS
:
if
tp_flags
&
Py_TPFLAGS_INT_SUBCLASS
:
return
PyIntObjectPtr
return
PyIntObjectPtr
...
@@ -392,8 +392,6 @@ class PyObjectPtr(object):
...
@@ -392,8 +392,6 @@ class PyObjectPtr(object):
return
PyDictObjectPtr
return
PyDictObjectPtr
if
tp_flags
&
Py_TPFLAGS_BASE_EXC_SUBCLASS
:
if
tp_flags
&
Py_TPFLAGS_BASE_EXC_SUBCLASS
:
return
PyBaseExceptionObjectPtr
return
PyBaseExceptionObjectPtr
#if tp_flags & Py_TPFLAGS_TYPE_SUBCLASS:
# return PyTypeObjectPtr
# Use the base class:
# Use the base class:
return
cls
return
cls
...
@@ -484,9 +482,9 @@ def _PyObject_VAR_SIZE(typeobj, nitems):
...
@@ -484,9 +482,9 @@ def _PyObject_VAR_SIZE(typeobj, nitems):
)
&
~
(
SIZEOF_VOID_P
-
1
)
)
&
~
(
SIZEOF_VOID_P
-
1
)
).
cast
(
gdb
.
lookup_type
(
'size_t'
))
).
cast
(
gdb
.
lookup_type
(
'size_t'
))
class
Heap
TypeObjectPtr
(
PyObjectPtr
):
class
Py
TypeObjectPtr
(
PyObjectPtr
):
_typename
=
'PyObject'
_typename
=
'Py
Type
Object'
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
...
@@ -545,10 +543,17 @@ class HeapTypeObjectPtr(PyObjectPtr):
...
@@ -545,10 +543,17 @@ class HeapTypeObjectPtr(PyObjectPtr):
out
.
write
(
'<...>'
)
out
.
write
(
'<...>'
)
return
return
visited
.
add
(
self
.
as_address
())
visited
.
add
(
self
.
as_address
())
pyop_attrdict
=
self
.
get_attr_dict
()
try
:
_write_instance_repr
(
out
,
visited
,
tp_name
=
self
.
field
(
'tp_name'
).
string
()
self
.
safe_tp_name
(),
pyop_attrdict
,
self
.
as_address
())
except
RuntimeError
:
tp_name
=
'unknown'
out
.
write
(
'<type %s at remote 0x%x>'
%
(
tp_name
,
self
.
as_address
()))
# pyop_attrdict = self.get_attr_dict()
# _write_instance_repr(out, visited,
# self.safe_tp_name(), pyop_attrdict, self.as_address())
class
ProxyException
(
Exception
):
class
ProxyException
(
Exception
):
def
__init__
(
self
,
tp_name
,
args
):
def
__init__
(
self
,
tp_name
,
args
):
...
@@ -564,7 +569,7 @@ class PyBaseExceptionObjectPtr(PyObjectPtr):
...
@@ -564,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
:
...
@@ -677,7 +682,7 @@ class PyDictObjectPtr(PyObjectPtr):
...
@@ -677,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
:
...
@@ -711,7 +716,7 @@ class PyDictObjectPtr(PyObjectPtr):
...
@@ -711,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
:
...
@@ -756,7 +761,7 @@ class PyIntObjectPtr(PyObjectPtr):
...
@@ -756,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'
)
...
@@ -789,7 +794,7 @@ class PyListObjectPtr(PyObjectPtr):
...
@@ -789,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:
...
@@ -807,7 +812,7 @@ class PyLongObjectPtr(PyObjectPtr):
...
@@ -807,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
...
@@ -838,7 +843,7 @@ class PyBoolObjectPtr(PyLongObjectPtr):
...
@@ -838,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
)
...
@@ -1050,11 +1055,11 @@ class PySetObjectPtr(PyObjectPtr):
...
@@ -1050,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
):
...
@@ -1071,7 +1076,7 @@ class PyBytesObjectPtr(PyObjectPtr):
...
@@ -1071,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'
)
...
@@ -1136,9 +1141,6 @@ class PyTupleObjectPtr(PyObjectPtr):
...
@@ -1136,9 +1141,6 @@ class PyTupleObjectPtr(PyObjectPtr):
else
:
else
:
out
.
write
(
')'
)
out
.
write
(
')'
)
class
PyTypeObjectPtr
(
PyObjectPtr
):
_typename
=
'PyTypeObject'
def
_unichr_is_printable
(
char
):
def
_unichr_is_printable
(
char
):
# Logic adapted from Python 3's Tools/unicode/makeunicodedata.py
# Logic adapted from Python 3's Tools/unicode/makeunicodedata.py
...
@@ -1219,7 +1221,7 @@ class PyUnicodeObjectPtr(PyObjectPtr):
...
@@ -1219,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
:
...
@@ -1684,11 +1686,11 @@ class PyLocals(gdb.Command):
...
@@ -1684,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))
...
@@ -1699,7 +1701,7 @@ class PyLocals(gdb.Command):
...
@@ -1699,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()
...
@@ -1709,18 +1711,20 @@ PyGlobals("py-globals", gdb.COMMAND_DATA, gdb.COMPLETE_NONE)
...
@@ -1709,18 +1711,20 @@ 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():
pyframe = frame.get_pyop()
pyframe = frame.get_pyop()
if pyframe is None:
if pyframe is None:
warnings.warn("Use a Python debug build, Python breakpoints "
"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()
...
@@ -1729,7 +1733,7 @@ PyNameEquals("pyname_equals")
...
@@ -1729,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:
...
@@ -1743,20 +1747,20 @@ PyModEquals("pymod_equals")
...
@@ -1743,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
...
@@ -1770,31 +1774,31 @@ class _LoggingState(object):
...
@@ -1770,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)
...
@@ -1808,7 +1812,7 @@ class _LoggingState(object):
...
@@ -1808,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:
...
@@ -1831,177 +1835,130 @@ def get_selected_inferior():
...
@@ -1831,177 +1835,130 @@ 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:
return inferior
return inferior
def source_gdb_script(script_contents, to_string=False):
class GenericCodeStepper(gdb.Command):
"""
"""
Superclass for code stepping. Subclasses must implement the following
Source a gdb script with script_contents passed as a string. This is useful
methods:
to provide defines for py-step and py-next to make them repeatable (this is
not possible with gdb.execute()). See
lineno(frame)
http://sourceware.org/bugzilla/show_bug.cgi?id=12216
tells the current line number (only called for a relevant frame)
is_relevant_function(frame)
tells whether we care about frame '
frame
'
get_source_line(frame)
get the line of source code for the current line (only called for a
relevant frame). If the source code cannot be retrieved this
function should return None
static_break_functions()
returns an iterable of function names that are considered relevant
and should halt step-into execution. This is needed to provide a
performing step-into
runtime_break_functions
list of functions that we should break into depending on the
context
This class provides an '
invoke
' method that invokes a '
step
' or '
step
-
over
'
depending on the '
stepinto
' argument.
"""
"""
fd, filename = tempfile.mkstemp()
f = os.fdopen(fd, 'w')
f.write(script_contents)
f.close()
gdb.execute("
source
%
s
" % filename, to_string=to_string)
os.remove(filename)
def register_defines():
source_gdb_script(textwrap.dedent("""
\
define py-step
-py-step
end
define py-next
-py-next
end
document py-step
%s
end
document py-next
%s
end
""") % (PyStep.__doc__, PyNext.__doc__))
def stackdepth(frame):
"
Tells
the
stackdepth
of
a
gdb
frame
.
"
depth = 0
while frame:
frame = frame.older()
depth += 1
return depth
stepper = False
class ExecutionControlCommandBase(gdb.Command):
static_breakpoints = {}
"""
runtime_breakpoints = {}
Superclass for language specific execution control. Language specific
features should be implemented by lang_info using the LanguageInfo
def __init__(self, name, stepinto=False):
interface. 'name' is the name of the command.
super(GenericCodeStepper, self).__init__(name,
"""
gdb.COMMAND_RUNNING,
gdb.COMPLETE_NONE)
def __init__(self, name, lang_info):
self.stepinto = stepinto
super(ExecutionControlCommandBase, self).__init__(
name, gdb.COMMAND_RUNNING, gdb.COMPLETE_NONE)
def _break_func(self, funcname):
self.lang_info = lang_info
result = gdb.execute('
break
%
s
' % funcname, to_string=True)
return re.search(r'
Breakpoint
(
\
d
+
)
', result).group(1)
def install_breakpoints(self):
all_locations = itertools.chain(
def init_breakpoints(self):
self.lang_info.static_break_functions(),
"""
self.lang_info.runtime_break_functions())
Keep all breakpoints around and simply disable/enable them each time
we are stepping. We need this because if you set and delete a
for location in all_locations:
breakpoint, gdb will not repeat your command (this is due to '
delete
').
result = gdb.execute('break %s' % location, to_string=True)
We also can'
t
use
the
breakpoint
API
because
there
's no option to make
yield re.search(r'Breakpoint (
\
d+)
'
, result).group(1)
breakpoint setting silent.
def delete_breakpoints(self, breakpoint_list):
This method must be called whenever the list of functions we should
for bp in breakpoint_list:
step into changes. It can be called on any GenericCodeStepper instance.
gdb.execute("
delete
%
s
" % bp)
"""
break_funcs = set(self.static_break_functions())
def filter_output(self, result):
output = []
for funcname in break_funcs:
if funcname not in self.static_breakpoints:
match_finish = re.search(r'^Value returned is
\
$
\
d+ = (.*)', result,
try:
re.MULTILINE)
gdb.Breakpoint('', gdb.BP_BREAKPOINT, internal=True)
if match_finish:
except (AttributeError, TypeError):
output.append('Value returned: %s' % match_finish.group(1))
# gdb.Breakpoint does not take an '
internal
' argument, or
# gdb.Breakpoint does not exist.
reflags = re.MULTILINE
breakpoint = self._break_func(funcname)
regexes = [
except RuntimeError:
(r'^Program received signal .*', reflags|re.DOTALL),
# gdb.Breakpoint does take an '
internal
' argument, use it
(r'.*[Ww]arning.*', 0),
# and hide output
(r'^Program exited .*', reflags),
result = gdb.execute(textwrap.dedent("""
\
]
python bp = gdb.Breakpoint(%r, gdb.BP_BREAKPOINT,
\
internal=True);
\
for regex, flags in regexes:
print bp.number""",
match = re.search(regex, result, flags)
to_string=True))
if match:
output.append(match.group(0))
breakpoint = int(result)
return '
\
n
'.join(output)
self.static_breakpoints[funcname] = breakpoint
def stopped(self):
for bp in set(self.static_breakpoints) - break_funcs:
return get_selected_inferior().pid == 0
gdb.execute("delete " + self.static_breakpoints[bp])
self.disable_breakpoints()
def enable_breakpoints(self):
for bp in self.static_breakpoints.itervalues():
gdb.execute('
enable
' + bp)
runtime_break_functions = self.runtime_break_functions()
if runtime_break_functions is None:
return
for funcname in runtime_break_functions:
if (funcname not in self.static_breakpoints and
funcname not in self.runtime_breakpoints):
self.runtime_breakpoints[funcname] = self._break_func(funcname)
elif funcname in self.runtime_breakpoints:
gdb.execute('
enable
' + self.runtime_breakpoints[funcname])
def disable_breakpoints(self):
chain = itertools.chain(self.static_breakpoints.itervalues(),
self.runtime_breakpoints.itervalues())
for bp in chain:
gdb.execute('
disable
' + bp)
def runtime_break_functions(self):
"""
Implement this if the list of step-into functions depends on the
context.
"""
def stopped(self, result):
match = re.search('
^
Program
received
signal
.
*
', result, re.MULTILINE)
if match:
return match.group(0)
elif get_selected_inferior().pid == 0:
return result
else:
return None
def _stackdepth(self, frame):
depth = 0
while frame:
frame = frame.older()
depth += 1
return depth
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
of source code or the result of the last executed gdb command (passed
of source code or the result of the last executed gdb command (passed
in as the `result` argument).
in as the `result` argument).
"""
"""
result = self.stopped(result)
result = self.filter_output(result)
if result:
if self.stopped():
print result.strip()
print result.strip()
# check whether the program was killed by a signal, it should still
# have a stack.
try:
frame = gdb.selected_frame()
except RuntimeError:
pass
else:
print self.get_source_line(frame)
else:
else:
frame = gdb.selected_frame()
frame = gdb.selected_frame()
output = None
if self.lang_info.is_relevant_function(frame):
raised_exception = self.lang_info.exc_info(frame)
if self.is_relevant_function(frame):
if raised_exception:
output = self.get_source_line(frame)
print raised_exception
print self.lang_info.get_source_line(frame) or result
if output is None:
pframe = getattr(self, '
print_stackframe
', None)
if pframe:
pframe(frame, index=0)
else:
print result.strip()
else:
else:
print
outpu
t
print
resul
t
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:
...
@@ -2009,169 +1966,255 @@ class GenericCodeStepper(gdb.Command):
...
@@ -2009,169 +1966,255 @@ class GenericCodeStepper(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(self, *args
):
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_rel
avant = self
.is_relevant_function(frame)
is_rel
evant = self.lang_info
.is_relevant_function(frame)
if hitbp or is_rel
avant or self.stopped(result
):
if hitbp or is_rel
evant or self.stopped(
):
break
break
return result
def finish(self, *args):
"
Implements
the
finish
command
.
"
result = self._finish_frame()
self.finish_executing(result)
self.finish_executing(result)
def
_step(self
):
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
all functions that are deemed relevant. It then does a step over until
either something halts execution, or until the next line is reached.
If, however, stepover_command is given, it should be a string gdb
command that continues execution in some way. The idea is that the
caller has set a (conditional) breakpoint or watchpoint that can work
more efficiently than the step-over loop. For Python this means setting
a watchpoint for f->f_lasti, which means we can then subsequently
"
finish
" frames.
We want f->f_lasti instead of f->f_lineno, because the latter only
works properly with local trace functions, see
PyFrameObjectPtr.current_line_num and PyFrameObjectPtr.addr2line.
"""
"""
if s
elf.s
tepinto:
if stepinto:
self.enable_breakpoints(
)
breakpoint_list = list(self.install_breakpoints()
)
beginframe = gdb.selected_frame()
beginframe = gdb.selected_frame()
beginline = self.lineno(beginframe)
if not self.stepinto:
if self.lang_info.is_relevant_function(beginframe):
depth = self._stackdepth(beginframe)
# If we start in a relevant frame, initialize stuff properly. If
# we don't start in a relevant frame, the loop will halt
# immediately. So don't call self.lang_info.lineno() as it may
# raise for irrelevant frames.
beginline = self.lang_info.lineno(beginframe)
if not stepinto:
depth = stackdepth(beginframe)
newframe = beginframe
newframe = beginframe
result = ''
while True:
while True:
if self.is_relevant_function(newframe):
if self.
lang_info.
is_relevant_function(newframe):
result = gdb.execute(
'
next
'
, to_string=True)
result = gdb.execute(
stepover_command
, to_string=True)
else:
else:
result = self._finish()
result = self._finish
_frame
()
if self.stopped(
result
):
if self.stopped():
break
break
newframe = gdb.selected_frame()
newframe = gdb.selected_frame()
is_relevant_function = self.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:
bp = self.runtime_breakpoints.get(framename)
if is_relevant_function and m.group(1) in breakpoint_list:
if bp is None or (m.group(1) == bp and is_relevant_function):
# although we hit a breakpoint, we still need to check
# although we hit a breakpoint, we still need to check
# 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 s
elf.s
tepinto:
if not stepinto:
# see if we returned to the caller
# see if we returned to the caller
newdepth = s
elf._s
tackdepth(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:
if self.lineno(newframe) > beginline:
# newframe equals beginframe, check for a difference in the
# line number
lineno = self.lang_info.lineno(newframe)
if lineno and lineno != beginline:
break
break
if stepinto:
self.delete_breakpoints(breakpoint_list)
if self.stepinto:
self.finish_executing(result)
self.disable_breakpoints()
return result
def step(self, *args):
return self.finish_executing(self._step())
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))
class PythonCodeStepper(GenericCodeStepper):
class LanguageInfo(object):
"""
This class defines the interface that ExecutionControlCommandBase needs to
provide language-specific execution control.
Classes that implement this interface should implement:
lineno(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.
is_relevant_function(frame)
tells whether we care about frame 'frame'
get_source_line(frame)
get the line of source code for the current line (only called for a
relevant frame). If the source code cannot be retrieved this
function should return None
exc_info(frame) -- optional
tells whether an exception was raised, if so, it should return a
string representation of the exception value, None otherwise.
static_break_functions()
returns an iterable of function names that are considered relevant
and should halt step-into execution. This is needed to provide a
performing step-into
runtime_break_functions() -- optional
list of functions that we should break into depending on the
context
"""
def exc_info(self, frame):
"
See
this
class
' docstring."
def runtime_break_functions(self):
"""
Implement this if the list of step-into functions depends on the
context.
"""
return ()
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:
return pyframe
return pyframe
else:
else:
raise gdb.
Gdb
Error(
raise gdb.
Runtime
Error(
"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 '
%
4
d
%
s
' % (pyframe.current_line_num(),
return '
%
4
d
%
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):
try:
tstate = frame.read_var('
tstate
').dereference()
if gdb.parse_and_eval('
tstate
->
frame
==
f'):
# tstate local variable initialized
inf_type = tstate['
curexc_type
']
inf_value = tstate['
curexc_value
']
if inf_type:
return '
An
exception
was
raised
:
%
s
(
%
s
)
' % (inf_type,
inf_value)
except (ValueError, RuntimeError), e:
# Could not read the variable tstate or it'
s
memory
,
it
's ok
pass
def static_break_functions(self):
def static_break_functions(self):
yield '
PyEval_EvalFrameEx
'
yield '
PyEval_EvalFrameEx
'
class PyStep(PythonCodeStepper):
class PythonStepperMixin(object):
"""
Make this a mixin so CyStep can also inherit from this and use a
CythonCodeStepper at the same time.
"""
def python_step(self, stepinto):
frame = gdb.selected_frame()
framewrapper = Frame(frame)
output = gdb.execute('
watch
f
->
f_lasti
', to_string=True)
watchpoint = int(re.search(r'
[
Ww
]
atchpoint
(
\
d
+
):
', output).group(1))
self.step(stepinto=stepinto, stepover_command='
finish
')
gdb.execute('
delete
%
s
' % watchpoint)
class PyStep(ExecutionControlCommandBase, PythonStepperMixin):
"Step through Python code."
"Step through Python code."
invoke = PythonCodeStepper.step
stepinto = True
class PyNext(PythonCodeStepper):
def invoke(self, args, from_tty):
self.python_step(stepinto=self.stepinto)
class PyNext(PyStep):
"Step-over Python code."
"Step-over Python code."
invoke = PythonCodeStepper.step
stepinto = False
class PyFinish(
PythonCodeStepper
):
class PyFinish(
ExecutionControlCommandBase
):
"Execute until function returns to a caller."
"Execute until function returns to a caller."
invoke = ExecutionControlCommandBase.finish
invoke = PythonCodeStepper.finish
class PyRun(ExecutionControlCommandBase):
class PyRun(PythonCodeStepper):
"Run the program."
"Run the program."
invoke = ExecutionControlCommandBase.run
invoke = PythonCodeStepper.run
class PyCont(ExecutionControlCommandBase):
class PyCont(PythonCodeStepper):
invoke = ExecutionControlCommandBase.cont
invoke = PythonCodeStepper.cont
py_step = PyStep('
py
-
step
', stepinto=True)
py_next = PyNext('
py
-
next
', stepinto=False)
py_finish = PyFinish('
py
-
finish
')
py_run = PyRun('
py
-
run
')
py_cont = PyCont('
py
-
cont
')
gdb.execute('
set
breakpoint
pending
on
')
py_step.init_breakpoints()
Py_single_input = 256
Py_file_input = 257
Py_eval_input = 258
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
...
@@ -2192,14 +2235,14 @@ def pointervalue(gdbval):
...
@@ -2192,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'
...
@@ -2207,33 +2250,37 @@ def get_inferior_unicode_postfix():
...
@@ -2207,33 +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_file_input
=
257
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
:
...
@@ -2242,59 +2289,59 @@ class PythonCodeExecutor(object):
...
@@ -2242,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
))
...
@@ -2311,25 +2358,25 @@ class FetchAndRestoreError(PythonCodeExecutor):
...
@@ -2311,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
:
...
@@ -2342,15 +2389,15 @@ class FixGdbCommand(gdb.Command):
...
@@ -2342,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')
...
@@ -2358,17 +2405,17 @@ class FixGdbCommand(gdb.Command):
...
@@ -2358,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
:
...
@@ -2379,10 +2426,10 @@ class FixGdbCommand(gdb.Command):
...
@@ -2379,10 +2426,10 @@ 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
,
Py_single_input
return
expr
,
Py
thonCodeExecutor
.
Py
_single_input
else
:
else
:
lines
=
[]
lines
=
[]
while
True
:
while
True
:
...
@@ -2393,24 +2440,38 @@ class PyExec(gdb.Command):
...
@@ -2393,24 +2440,38 @@ 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
)
py_exec
=
FixGdbCommand
(
'py-exec'
,
'-py-exec'
)
_py_exec
=
PyExec
(
"-py-exec"
,
gdb
.
COMMAND_DATA
,
gdb
.
COMPLETE_NONE
)
gdb
.
execute
(
'set breakpoint pending on'
)
if
hasattr
(
gdb
,
'GdbError'
):
# Wrap py-step and py-next in gdb defines to make them repeatable.
py_step
=
PyStep
(
'-py-step'
,
PythonInfo
())
py_next
=
PyNext
(
'-py-next'
,
PythonInfo
())
register_defines
()
py_finish
=
PyFinish
(
'py-finish'
,
PythonInfo
())
py_run
=
PyRun
(
'py-run'
,
PythonInfo
())
py_cont
=
PyCont
(
'py-cont'
,
PythonInfo
())
py_exec
=
FixGdbCommand
(
'py-exec'
,
'-py-exec'
)
_py_exec
=
PyExec
(
"-py-exec"
,
gdb
.
COMMAND_DATA
,
gdb
.
COMPLETE_NONE
)
else
:
warnings
.
warn
(
"Use gdb 7.2 or higher to use the py-exec command."
)
\ No newline at end of file
runtests.py
View file @
c5e16a3f
...
@@ -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
),
...
@@ -675,12 +675,12 @@ class CythonPyregrTestCase(CythonRunTestCase):
...
@@ -675,12 +675,12 @@ class CythonPyregrTestCase(CythonRunTestCase):
except
(
unittest
.
SkipTest
,
support
.
ResourceDenied
):
except
(
unittest
.
SkipTest
,
support
.
ResourceDenied
):
result
.
addSkip
(
self
,
'ok'
)
result
.
addSkip
(
self
,
'ok'
)
# Someone wrapped this in a:
try
:
# 'try: import gdb; ... except: include_debugger = False' thing, but don't do
import
gdb
# this, it doesn't work as gdb is a builtin module in GDB. The tests themselves
include_debugger
=
sys
.
version_info
[:
2
]
>
(
2
,
5
)
# are doing the skipping. If there's a problem with the tests, please file an
except
:
# issue.
include_debugger
=
False
include_debugger
=
sys
.
version_info
[:
2
]
>
(
2
,
5
)
def
collect_unittests
(
path
,
module_prefix
,
suite
,
selectors
):
def
collect_unittests
(
path
,
module_prefix
,
suite
,
selectors
):
def
file_matches
(
filename
):
def
file_matches
(
filename
):
...
@@ -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
)
...
...
setup.py
View file @
c5e16a3f
...
@@ -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
=
{}
...
@@ -100,7 +100,8 @@ def compile_cython_modules(profile=False, compile_more=False, cython_with_refnan
...
@@ -100,7 +100,8 @@ def compile_cython_modules(profile=False, compile_more=False, cython_with_refnan
"Cython.Compiler.Parsing"
,
"Cython.Compiler.Parsing"
,
"Cython.Compiler.Visitor"
,
"Cython.Compiler.Visitor"
,
"Cython.Compiler.Code"
,
"Cython.Compiler.Code"
,
"Cython.Runtime.refnanny"
]
"Cython.Runtime.refnanny"
,
"Cython.Debugger.do_repeat"
,]
if
compile_more
:
if
compile_more
:
compiled_modules
.
extend
([
compiled_modules
.
extend
([
"Cython.Compiler.ParseTreeTransforms"
,
"Cython.Compiler.ParseTreeTransforms"
,
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment