# Cython Top Level
#
-import os, sys, re
+import os, sys, re, codecs
if sys.version_info[:2] < (2, 3):
sys.stderr.write("Sorry, Cython requires Python 2.3 or later\n")
sys.exit(1)
import Code
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
from Scanning import PyrexScanner, FileSourceDescriptor
from Errors import PyrexError, CompileError, InternalError, AbortError, error, warning
# include_directories [string]
# future_directives [object]
# language_level int currently 2 or 3 for Python 2/3
-
+
def __init__(self, include_directories, compiler_directives, cpp=False, language_level=2):
- #self.modules = {"__builtin__" : BuiltinScope()}
import Builtin, CythonScope
self.modules = {"__builtin__" : Builtin.builtin_scope}
self.modules["cython"] = CythonScope.create_cython_scope(self)
self.include_directories = include_directories + [standard_include_path]
self.set_language_level(language_level)
-
+
self.gdb_debug_outputwriter = None
def set_language_level(self, level):
from Future import print_function, unicode_literals
self.future_directives.add(print_function)
self.future_directives.add(unicode_literals)
+ self.modules['builtins'] = self.modules['__builtin__']
def create_pipeline(self, pxd, py=False):
from Visitor import PrintTree
from ParseTreeTransforms import WithTransform, NormalizeTree, PostParse, PxdPostParse
from ParseTreeTransforms import AnalyseDeclarationsTransform, AnalyseExpressionsTransform
from ParseTreeTransforms import CreateClosureClasses, MarkClosureVisitor, DecoratorTransform
- from ParseTreeTransforms import MarkGeneratorVisitor
from ParseTreeTransforms import InterpretCompilerDirectives, TransformBuiltinMethods
from ParseTreeTransforms import ExpandInplaceOperators
from TypeInference import MarkAssignments, MarkOverflowingArithmetic
else:
_check_c_declarations = check_c_declarations
_specific_post_parse = None
-
+
if py and not pxd:
_align_function_definitions = AlignFunctionDefinitions(self)
else:
_align_function_definitions = None
-
+
return [
NormalizeTree(self),
PostParse(self),
_specific_post_parse,
InterpretCompilerDirectives(self, self.compiler_directives),
- _align_function_definitions,
MarkClosureVisitor(self),
- MarkGeneratorVisitor(self),
+ _align_function_definitions,
ConstantFolding(),
FlattenInListTransform(),
WithTransform(self),
debug_transform = [DebugTransform(self, options, result)]
else:
debug_transform = []
-
+
return list(itertools.chain(
[create_parse(self)],
self.create_pipeline(pxd=False, py=py),
return [parse_pxd] + self.create_pipeline(pxd=True) + [
ExtractPxdCode(self),
]
-
+
def create_py_pipeline(self, options, result):
return self.create_pyx_pipeline(options, result, py=True)
pipeline = self.create_pxd_pipeline(scope, module_name)
result = self.run_pipeline(pipeline, source_desc)
return result
-
+
def nonfatal_error(self, exc):
return Errors.report_error(exc)
error = err
return (error, data)
- def find_module(self, module_name,
+ def find_module(self, module_name,
relative_to = None, pos = None, need_pxd = 1):
# Finds and returns the module scope corresponding to
# the given relative or absolute module name. If this
try:
if debug_find_module:
print("Context.find_module: Parsing %s" % pxd_pathname)
- source_desc = FileSourceDescriptor(pxd_pathname)
+ rel_path = module_name.replace('.', os.sep) + os.path.splitext(pxd_pathname)[1]
+ if not pxd_pathname.endswith(rel_path):
+ rel_path = pxd_pathname # safety measure to prevent printing incorrect paths
+ source_desc = FileSourceDescriptor(pxd_pathname, rel_path)
err, result = self.process_pxd(source_desc, scope, module_name)
if err:
raise err
except CompileError:
pass
return scope
-
+
def find_pxd_file(self, qualified_name, pos):
# Search include path for the .pxd file corresponding to the
# given fully-qualified module name.
# Search include path for the .pyx file corresponding to the
# given fully-qualified module name, as for find_pxd_file().
return self.search_include_directories(qualified_name, ".pyx", pos)
-
+
def find_include_file(self, filename, pos):
# Search list of include directories for filename.
# Reports an error and returns None if not found.
if not path:
error(pos, "'%s' not found" % filename)
return path
-
+
def search_include_directories(self, qualified_name, suffix, pos,
include=False):
# Search the list of include directories for the given
if dep_path and Utils.file_newer_than(dep_path, c_time):
return 1
return 0
-
+
def find_cimported_module_names(self, source_path):
return [ name for kind, name in self.read_dependency_file(source_path)
if kind == "cimport" ]
def is_package_dir(self, dir_path):
# Return true if the given directory is a package directory.
- for filename in ("__init__.py",
- "__init__.pyx",
+ for filename in ("__init__.py",
+ "__init__.pyx",
"__init__.pxd"):
path = os.path.join(dir_path, filename)
if Utils.path_exists(path):
# Find a top-level module, creating a new one if needed.
scope = self.lookup_submodule(name)
if not scope:
- scope = ModuleScope(name,
+ scope = ModuleScope(name,
parent_module = None, context = self)
self.modules[name] = scope
return scope
try:
f = Utils.open_source_file(source_filename, "rU")
try:
+ import Parsing
s = PyrexScanner(f, source_desc, source_encoding = f.encoding,
scope = scope, context = self)
tree = Parsing.p_module(s, pxd, full_module_name)
# Set up source object
cwd = os.getcwd()
- source_desc = FileSourceDescriptor(os.path.join(cwd, source))
+ abs_path = os.path.abspath(source)
+ source_ext = os.path.splitext(source)[1]
full_module_name = full_module_name or context.extract_module_name(source, options)
+ if options.relative_path_in_code_position_comments:
+ rel_path = full_module_name.replace('.', os.sep) + source_ext
+ if not abs_path.endswith(rel_path):
+ rel_path = source # safety measure to prevent printing incorrect paths
+ else:
+ rel_path = abs_path
+ source_desc = FileSourceDescriptor(abs_path, rel_path)
source = CompilationSource(source_desc, full_module_name, cwd)
# Set up result object
result = create_default_resultobj(source, options)
-
+
+ if options.annotate is None:
+ # By default, decide based on whether an html file already exists.
+ html_filename = os.path.splitext(result.c_file)[0] + ".html"
+ if os.path.exists(html_filename):
+ line = codecs.open(html_filename, "r", encoding="UTF-8").readline()
+ if line.startswith(u'<!-- Generated by Cython'):
+ options.annotate = True
+
# Get pipeline
- if source_desc.filename.endswith(".py"):
+ if source_ext.lower() == '.py':
pipeline = context.create_py_pipeline(options, result)
else:
pipeline = context.create_pyx_pipeline(options, result)
err, enddata = context.run_pipeline(pipeline, source)
context.teardown_errors(err, options, result)
return result
-
+
#------------------------------------------------------------------------
#
class CompilationOptions(object):
"""
Options to the Cython compiler:
-
+
show_version boolean Display version number
use_listing_file boolean Generate a .lis file
errors_to_stderr boolean Echo errors to stderr when using .lis
compiler_directives dict Overrides for pragma options (see Options.py)
evaluate_tree_assertions boolean Test support: evaluate parse tree assertions
language_level integer The Python language level: 2 or 3
-
+
cplus boolean Compile as c++ code
"""
-
+
def __init__(self, defaults = None, **kw):
self.include_path = []
if defaults:
class CompilationResult(object):
"""
Results from the Cython compiler:
-
+
c_file string or None The generated C source file
h_file string or None The generated C header file
i_file string or None The generated .pxi file
num_errors integer Number of compilation errors
compilation_source CompilationSource
"""
-
+
def __init__(self):
self.c_file = None
self.h_file = None
Results from compiling multiple Pyrex source files. A mapping
from source file paths to CompilationResult instances. Also
has the following attributes:
-
+
num_errors integer Total number of compilation errors
"""
-
+
num_errors = 0
def add(self, source, result):
def compile_single(source, options, full_module_name = None):
"""
compile_single(source, options, full_module_name)
-
+
Compile the given Pyrex implementation file and return a CompilationResult.
Always compiles a single file; does not perform timestamp checking or
recursion.
def compile_multiple(sources, options):
"""
compile_multiple(sources, options)
-
+
Compiles the given sequence of Pyrex implementation files and returns
a CompilationResultSet. Performs timestamp checking and/or recursion
if these are specified in the options.
def compile(source, options = None, full_module_name = None, **kwds):
"""
compile(source [, options], [, <option> = <value>]...)
-
+
Compile one or more Pyrex implementation files, with optional timestamp
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
errors_to_stderr = 1,
cplus = 0,
output_file = None,
- annotate = False,
+ annotate = None,
generate_pxi = 0,
working_path = "",
recursive = 0,
compiler_directives = {},
evaluate_tree_assertions = False,
emit_linenums = False,
+ relative_path_in_code_position_comments = True,
+ c_line_in_traceback = True,
language_level = 2,
gdb_debug = False,
)