diff --git a/Cython/Compiler/Main.py b/Cython/Compiler/Main.py index 7dd15ce3d7f296f2f36b04c6ea7df77a625df3ac..2b91709d10b71ea334c45b3172a26933aff7a263 100644 --- a/Cython/Compiler/Main.py +++ b/Cython/Compiler/Main.py @@ -31,6 +31,7 @@ from Cython import Utils from Cython.Utils import open_new_file, replace_suffix import CythonScope import DebugFlags +import Options module_name_pattern = re.compile(r"[A-Za-z_][A-Za-z0-9_]*(\.[A-Za-z_][A-Za-z0-9_]*)*$") @@ -73,7 +74,7 @@ class Context(object): # 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): + def __init__(self, include_directories, compiler_directives, cpp=False, language_level=2, options=None): import Builtin, CythonScope self.modules = {"__builtin__" : Builtin.builtin_scope} self.modules["cython"] = CythonScope.create_cython_scope(self) @@ -81,6 +82,7 @@ class Context(object): self.future_directives = set() self.compiler_directives = compiler_directives self.cpp = cpp + self.options = options self.pxds = {} # full name -> node tree @@ -231,10 +233,39 @@ class Context(object): def create_py_pipeline(self, options, result): return self.create_pyx_pipeline(options, result, py=True) + def create_pyx_as_pxd_pipeline(self, source): + from ParseTreeTransforms import (AlignFunctionDefinitions, + MarkClosureVisitor, WithTransform, AnalyseDeclarationsTransform) + from Optimize import ConstantFolding, FlattenInListTransform + from Nodes import StatListNode + pipeline = [] + result = create_default_resultobj(source, self.options) + pyx_pipeline = self.create_pyx_pipeline(self.options, result) + for stage in pyx_pipeline: + if stage.__class__ in [ + AlignFunctionDefinitions, + MarkClosureVisitor, + ConstantFolding, + FlattenInListTransform, + WithTransform, + ]: + pass # continue + pipeline.append(stage) + if isinstance(stage, AnalyseDeclarationsTransform): + break + def fake_pxd(root): + return StatListNode(root.pos, stats=[]), root.scope + pipeline.append(fake_pxd) + return pipeline def process_pxd(self, source_desc, scope, module_name): - pipeline = self.create_pxd_pipeline(scope, module_name) - result = self.run_pipeline(pipeline, source_desc) + if isinstance(source_desc, FileSourceDescriptor) and source_desc._file_type == 'pyx': + source = CompilationSource(source_desc, module_name, os.getcwd()) + pipeline = self.create_pyx_as_pxd_pipeline(source) + result = self.run_pipeline(pipeline, source) + else: + pipeline = self.create_pxd_pipeline(scope, module_name) + result = self.run_pipeline(pipeline, source_desc) return result def nonfatal_error(self, exc): @@ -365,6 +396,8 @@ class Context(object): warning(pos, "'%s' is deprecated, use 'libc.%s'" % (name, name), 1) elif name in ('stl'): warning(pos, "'%s' is deprecated, use 'libcpp.*.*'" % name, 1) + if pxd is None and Options.cimport_from_pyx: + return self.find_pyx_file(qualified_name, pos) return pxd def find_pyx_file(self, qualified_name, pos): @@ -686,7 +719,7 @@ class CompilationOptions(object): def create_context(self): return Context(self.include_path, self.compiler_directives, - self.cplus, self.language_level) + self.cplus, self.language_level, options=self) class CompilationResult(object): diff --git a/Cython/Compiler/Options.py b/Cython/Compiler/Options.py index 98abdc4f28168338f3f60992a56c134fc4375d03..839f2c485707ef6425c83e1630bc4ad209365847 100644 --- a/Cython/Compiler/Options.py +++ b/Cython/Compiler/Options.py @@ -63,6 +63,10 @@ disable_function_redefinition = False # globals in the call stack. Sage relies on this behavior for variable injection. old_style_globals = False +# Allows cimporting from a pyx file without a pxd file. +cimport_from_pyx = True + + # Declare compiler directives directive_defaults = {