diff options
author | Anton Samokhvalov <pg83@yandex.ru> | 2022-02-10 16:45:15 +0300 |
---|---|---|
committer | Daniil Cherednik <dcherednik@yandex-team.ru> | 2022-02-10 16:45:15 +0300 |
commit | 72cb13b4aff9bc9cf22e49251bc8fd143f82538f (patch) | |
tree | da2c34829458c7d4e74bdfbdf85dff449e9e7fb8 /contrib/tools/cython/Cython/Compiler/Main.py | |
parent | 778e51ba091dc39e7b7fcab2b9cf4dbedfb6f2b5 (diff) | |
download | ydb-72cb13b4aff9bc9cf22e49251bc8fd143f82538f.tar.gz |
Restoring authorship annotation for Anton Samokhvalov <pg83@yandex.ru>. Commit 1 of 2.
Diffstat (limited to 'contrib/tools/cython/Cython/Compiler/Main.py')
-rw-r--r-- | contrib/tools/cython/Cython/Compiler/Main.py | 1138 |
1 files changed, 569 insertions, 569 deletions
diff --git a/contrib/tools/cython/Cython/Compiler/Main.py b/contrib/tools/cython/Cython/Compiler/Main.py index af873843b5..b7aac5ff5e 100644 --- a/contrib/tools/cython/Cython/Compiler/Main.py +++ b/contrib/tools/cython/Cython/Compiler/Main.py @@ -1,101 +1,101 @@ -# -# Cython Top Level -# - -from __future__ import absolute_import - -import os -import re -import sys +# +# Cython Top Level +# + +from __future__ import absolute_import + +import os +import re +import sys import io - + if sys.version_info[:2] < (2, 6) or (3, 0) <= sys.version_info[:2] < (3, 3): sys.stderr.write("Sorry, Cython requires Python 2.6+ or 3.3+, found %d.%d\n" % tuple(sys.version_info[:2])) - sys.exit(1) - + sys.exit(1) + try: from __builtin__ import basestring except ImportError: basestring = str -# 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 +# 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 from . import Errors from .StringEncoding import EncodedString -from .Scanning import PyrexScanner, FileSourceDescriptor -from .Errors import PyrexError, CompileError, error, warning -from .Symtab import ModuleScope -from .. import Utils -from . import Options - +from .Scanning import PyrexScanner, FileSourceDescriptor +from .Errors import PyrexError, CompileError, error, warning +from .Symtab import ModuleScope +from .. import Utils +from . import Options + from . import Version # legacy import needed by old PyTables versions version = Version.version # legacy attribute - use "Cython.__version__" instead -module_name_pattern = re.compile(r"[A-Za-z_][A-Za-z0-9_]*(\.[A-Za-z_][A-Za-z0-9_]*)*$") - -verbose = 0 - +module_name_pattern = re.compile(r"[A-Za-z_][A-Za-z0-9_]*(\.[A-Za-z_][A-Za-z0-9_]*)*$") + +verbose = 0 + standard_include_path = os.path.abspath(os.path.join(os.path.dirname(__file__), os.path.pardir, 'Includes')) -class CompilationData(object): - # Bundles the information that is passed from transform to transform. - # (For now, this is only) - - # While Context contains every pxd ever loaded, path information etc., - # this only contains the data related to a single compilation pass - # - # pyx ModuleNode Main code tree of this compilation. - # pxds {string : ModuleNode} Trees for the pxds used in the pyx. - # codewriter CCodeWriter Where to output final code. - # options CompilationOptions - # result CompilationResult - pass - - -class Context(object): - # This class encapsulates the context needed for compiling - # one or more Cython implementation files along with their - # associated and imported declaration files. It includes - # the root of the module import namespace and the list - # of directories to search for include files. - # - # modules {string : ModuleScope} - # include_directories [string] - # future_directives [object] - # language_level int currently 2 or 3 for Python 2/3 - - cython_scope = None +class CompilationData(object): + # Bundles the information that is passed from transform to transform. + # (For now, this is only) + + # While Context contains every pxd ever loaded, path information etc., + # this only contains the data related to a single compilation pass + # + # pyx ModuleNode Main code tree of this compilation. + # pxds {string : ModuleNode} Trees for the pxds used in the pyx. + # codewriter CCodeWriter Where to output final code. + # options CompilationOptions + # result CompilationResult + pass + + +class Context(object): + # This class encapsulates the context needed for compiling + # one or more Cython implementation files along with their + # associated and imported declaration files. It includes + # the root of the module import namespace and the list + # of directories to search for include files. + # + # modules {string : ModuleScope} + # include_directories [string] + # future_directives [object] + # language_level int currently 2 or 3 for Python 2/3 + + cython_scope = None language_level = None # warn when not set but default to Py2 - - def __init__(self, include_directories, compiler_directives, cpp=False, + + def __init__(self, include_directories, compiler_directives, cpp=False, language_level=None, options=None): - # cython_scope is a hack, set to False by subclasses, in order to break - # an infinite loop. - # Better code organization would fix it. - - from . import Builtin, CythonScope - self.modules = {"__builtin__" : Builtin.builtin_scope} - self.cython_scope = CythonScope.create_cython_scope(self) - self.modules["cython"] = self.cython_scope - self.include_directories = include_directories - self.future_directives = set() - self.compiler_directives = compiler_directives - self.cpp = cpp - self.options = options - + # cython_scope is a hack, set to False by subclasses, in order to break + # an infinite loop. + # Better code organization would fix it. + + from . import Builtin, CythonScope + self.modules = {"__builtin__" : Builtin.builtin_scope} + self.cython_scope = CythonScope.create_cython_scope(self) + self.modules["cython"] = self.cython_scope + self.include_directories = include_directories + self.future_directives = set() + self.compiler_directives = compiler_directives + self.cpp = cpp + self.options = options + self.pxds = {} # full name -> node tree self._interned = {} # (type(value), value, *key_args) -> interned_value - + if language_level is not None: self.set_language_level(language_level) - - self.gdb_debug_outputwriter = None - - def set_language_level(self, level): + + self.gdb_debug_outputwriter = None + + def set_language_level(self, level): from .Future import print_function, unicode_literals, absolute_import, division future_directives = set() if level == '3str': @@ -106,11 +106,11 @@ class Context(object): future_directives.add(unicode_literals) if level >= 3: future_directives.update([print_function, absolute_import, division]) - self.language_level = level + self.language_level = level self.future_directives = future_directives - if level >= 3: - self.modules['builtins'] = self.modules['__builtin__'] - + if level >= 3: + self.modules['builtins'] = self.modules['__builtin__'] + def intern_ustring(self, value, encoding=None): key = (EncodedString, value, encoding) try: @@ -132,40 +132,40 @@ class Context(object): self._interned[key] = value return value - # pipeline creation functions can now be found in Pipeline.py - - def process_pxd(self, source_desc, scope, module_name): - from . import Pipeline - if isinstance(source_desc, FileSourceDescriptor) and source_desc._file_type == 'pyx': - source = CompilationSource(source_desc, module_name, os.getcwd()) - result_sink = create_default_resultobj(source, self.options) - pipeline = Pipeline.create_pyx_as_pxd_pipeline(self, result_sink) - result = Pipeline.run_pipeline(pipeline, source) - else: - pipeline = Pipeline.create_pxd_pipeline(self, scope, module_name) - result = Pipeline.run_pipeline(pipeline, source_desc) - return result - - def nonfatal_error(self, exc): - return Errors.report_error(exc) - + # pipeline creation functions can now be found in Pipeline.py + + def process_pxd(self, source_desc, scope, module_name): + from . import Pipeline + if isinstance(source_desc, FileSourceDescriptor) and source_desc._file_type == 'pyx': + source = CompilationSource(source_desc, module_name, os.getcwd()) + result_sink = create_default_resultobj(source, self.options) + pipeline = Pipeline.create_pyx_as_pxd_pipeline(self, result_sink) + result = Pipeline.run_pipeline(pipeline, source) + else: + pipeline = Pipeline.create_pxd_pipeline(self, scope, module_name) + result = Pipeline.run_pipeline(pipeline, source_desc) + return result + + def nonfatal_error(self, exc): + return Errors.report_error(exc) + def find_module(self, module_name, relative_to=None, pos=None, need_pxd=1, absolute_fallback=True): - # Finds and returns the module scope corresponding to - # the given relative or absolute module name. If this - # is the first time the module has been requested, finds - # the corresponding .pxd file and process it. - # If relative_to is not None, it must be a module scope, - # and the module will first be searched for relative to - # that module, provided its name is not a dotted name. - debug_find_module = 0 - if debug_find_module: - print("Context.find_module: module_name = %s, relative_to = %s, pos = %s, need_pxd = %s" % ( + # Finds and returns the module scope corresponding to + # the given relative or absolute module name. If this + # is the first time the module has been requested, finds + # the corresponding .pxd file and process it. + # If relative_to is not None, it must be a module scope, + # and the module will first be searched for relative to + # that module, provided its name is not a dotted name. + debug_find_module = 0 + if debug_find_module: + print("Context.find_module: module_name = %s, relative_to = %s, pos = %s, need_pxd = %s" % ( module_name, relative_to, pos, need_pxd)) - - scope = None - pxd_pathname = None - if relative_to: + + scope = None + pxd_pathname = None + if relative_to: if module_name: # from .module import ... qualified_name = relative_to.qualify_name(module_name) @@ -182,111 +182,111 @@ class Context(object): "'%s' is not a valid module name" % module_name) if relative_to: - if debug_find_module: - print("...trying relative import") - scope = relative_to.lookup_submodule(module_name) - if not scope: - pxd_pathname = self.find_pxd_file(qualified_name, pos) - if pxd_pathname: - scope = relative_to.find_submodule(module_name) - if not scope: - if debug_find_module: - print("...trying absolute import") + if debug_find_module: + print("...trying relative import") + scope = relative_to.lookup_submodule(module_name) + if not scope: + pxd_pathname = self.find_pxd_file(qualified_name, pos) + if pxd_pathname: + scope = relative_to.find_submodule(module_name) + if not scope: + if debug_find_module: + print("...trying absolute import") if absolute_fallback: qualified_name = module_name - scope = self + scope = self for name in qualified_name.split("."): - scope = scope.find_submodule(name) - - if debug_find_module: - print("...scope = %s" % scope) - if not scope.pxd_file_loaded: - if debug_find_module: - print("...pxd not loaded") - if not pxd_pathname: - if debug_find_module: - print("...looking for pxd file") + scope = scope.find_submodule(name) + + if debug_find_module: + print("...scope = %s" % scope) + if not scope.pxd_file_loaded: + if debug_find_module: + print("...pxd not loaded") + if not pxd_pathname: + if debug_find_module: + print("...looking for pxd file") pxd_pathname = self.find_pxd_file(qualified_name, pos) - if debug_find_module: - print("......found %s" % pxd_pathname) - if not pxd_pathname and need_pxd: + if debug_find_module: + print("......found %s" % pxd_pathname) + if not pxd_pathname and need_pxd: # Set pxd_file_loaded such that we don't need to # look for the non-existing pxd file next time. scope.pxd_file_loaded = True package_pathname = self.search_include_directories(qualified_name, ".py", pos) - if package_pathname and package_pathname.endswith('__init__.py'): - pass - else: + if package_pathname and package_pathname.endswith('__init__.py'): + pass + else: error(pos, "'%s.pxd' not found" % qualified_name.replace('.', os.sep)) - if pxd_pathname: + if pxd_pathname: scope.pxd_file_loaded = True - try: - if debug_find_module: - print("Context.find_module: Parsing %s" % 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 + try: + if debug_find_module: + print("Context.find_module: Parsing %s" % 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 if Options.source_root: rel_path = os.path.relpath(pxd_pathname, Options.source_root) - source_desc = FileSourceDescriptor(pxd_pathname, rel_path) + source_desc = FileSourceDescriptor(pxd_pathname, rel_path) err, result = self.process_pxd(source_desc, scope, qualified_name) - if err: - raise err - (pxd_codenodes, pxd_scope) = result - self.pxds[module_name] = (pxd_codenodes, pxd_scope) - except CompileError: - pass - return scope - + if err: + raise err + (pxd_codenodes, pxd_scope) = result + self.pxds[module_name] = (pxd_codenodes, pxd_scope) + except CompileError: + pass + return scope + def find_pxd_file(self, qualified_name, pos, sys_path=False): # Search include path (and sys.path if sys_path is True) for # the .pxd file corresponding to the given fully-qualified # module name. - # Will find either a dotted filename or a file in a - # package directory. If a source file position is given, - # the directory containing the source file is searched first - # for a dotted filename, and its containing package root - # directory is searched first for a non-dotted filename. + # Will find either a dotted filename or a file in a + # package directory. If a source file position is given, + # the directory containing the source file is searched first + # for a dotted filename, and its containing package root + # directory is searched first for a non-dotted filename. pxd = self.search_include_directories(qualified_name, ".pxd", pos, sys_path=sys_path) - if pxd is None: # XXX Keep this until Includes/Deprecated is removed - if (qualified_name.startswith('python') or + if pxd is None: # XXX Keep this until Includes/Deprecated is removed + if (qualified_name.startswith('python') or qualified_name in ('stdlib', 'stdio', 'stl')): - standard_include_path = os.path.abspath(os.path.normpath( - os.path.join(os.path.dirname(__file__), os.path.pardir, 'Includes'))) - deprecated_include_path = os.path.join(standard_include_path, 'Deprecated') - self.include_directories.append(deprecated_include_path) - try: - pxd = self.search_include_directories(qualified_name, ".pxd", pos) - finally: - self.include_directories.pop() - if pxd: - name = qualified_name - if name.startswith('python'): - warning(pos, "'%s' is deprecated, use 'cpython'" % name, 1) - elif name in ('stdlib', 'stdio'): - 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): - # 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. - path = self.search_include_directories(filename, "", pos, - include=True) - if not path: - error(pos, "'%s' not found" % filename) - return path - - def search_include_directories(self, qualified_name, suffix, pos, - include=False, sys_path=False): + standard_include_path = os.path.abspath(os.path.normpath( + os.path.join(os.path.dirname(__file__), os.path.pardir, 'Includes'))) + deprecated_include_path = os.path.join(standard_include_path, 'Deprecated') + self.include_directories.append(deprecated_include_path) + try: + pxd = self.search_include_directories(qualified_name, ".pxd", pos) + finally: + self.include_directories.pop() + if pxd: + name = qualified_name + if name.startswith('python'): + warning(pos, "'%s' is deprecated, use 'cpython'" % name, 1) + elif name in ('stdlib', 'stdio'): + 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): + # 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. + path = self.search_include_directories(filename, "", pos, + include=True) + if not path: + error(pos, "'%s' not found" % filename) + return path + + def search_include_directories(self, qualified_name, suffix, pos, + include=False, sys_path=False): include_dirs = self.include_directories if sys_path: include_dirs = include_dirs + sys.path @@ -294,79 +294,79 @@ class Context(object): include_dirs = tuple(include_dirs + [standard_include_path]) return search_include_directories(include_dirs, qualified_name, suffix, pos, include) - - def find_root_package_dir(self, file_path): - return Utils.find_root_package_dir(file_path) - - def check_package_dir(self, dir, package_names): - return Utils.check_package_dir(dir, tuple(package_names)) - + + def find_root_package_dir(self, file_path): + return Utils.find_root_package_dir(file_path) + + def check_package_dir(self, dir, package_names): + return Utils.check_package_dir(dir, tuple(package_names)) + def c_file_out_of_date(self, source_path, output_path): if not os.path.exists(output_path): - return 1 + return 1 c_time = Utils.modification_time(output_path) - if Utils.file_newer_than(source_path, c_time): - return 1 - pos = [source_path] - pxd_path = Utils.replace_suffix(source_path, ".pxd") - if os.path.exists(pxd_path) and Utils.file_newer_than(pxd_path, c_time): - return 1 - for kind, name in self.read_dependency_file(source_path): - if kind == "cimport": - dep_path = self.find_pxd_file(name, pos) - elif kind == "include": - dep_path = self.search_include_directories(name, pos) - else: - continue - 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 Utils.is_package_dir(dir_path) - - def read_dependency_file(self, source_path): - dep_path = Utils.replace_suffix(source_path, ".dep") - if os.path.exists(dep_path): - f = open(dep_path, "rU") - chunks = [ line.strip().split(" ", 1) - for line in f.readlines() - if " " in line.strip() ] - f.close() - return chunks - else: - return () - - def lookup_submodule(self, name): - # Look up a top-level module. Returns None if not found. - return self.modules.get(name, None) - - def find_submodule(self, name): - # Find a top-level module, creating a new one if needed. - scope = self.lookup_submodule(name) - if not scope: - scope = ModuleScope(name, - parent_module = None, context = self) - self.modules[name] = scope - return scope - - def parse(self, source_desc, scope, pxd, full_module_name): - if not isinstance(source_desc, FileSourceDescriptor): - raise RuntimeError("Only file sources for code supported") - source_filename = source_desc.filename - scope.cpp = self.cpp - # Parse the given source file and return a parse tree. - num_errors = Errors.num_errors - try: + if Utils.file_newer_than(source_path, c_time): + return 1 + pos = [source_path] + pxd_path = Utils.replace_suffix(source_path, ".pxd") + if os.path.exists(pxd_path) and Utils.file_newer_than(pxd_path, c_time): + return 1 + for kind, name in self.read_dependency_file(source_path): + if kind == "cimport": + dep_path = self.find_pxd_file(name, pos) + elif kind == "include": + dep_path = self.search_include_directories(name, pos) + else: + continue + 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 Utils.is_package_dir(dir_path) + + def read_dependency_file(self, source_path): + dep_path = Utils.replace_suffix(source_path, ".dep") + if os.path.exists(dep_path): + f = open(dep_path, "rU") + chunks = [ line.strip().split(" ", 1) + for line in f.readlines() + if " " in line.strip() ] + f.close() + return chunks + else: + return () + + def lookup_submodule(self, name): + # Look up a top-level module. Returns None if not found. + return self.modules.get(name, None) + + def find_submodule(self, name): + # Find a top-level module, creating a new one if needed. + scope = self.lookup_submodule(name) + if not scope: + scope = ModuleScope(name, + parent_module = None, context = self) + self.modules[name] = scope + return scope + + def parse(self, source_desc, scope, pxd, full_module_name): + if not isinstance(source_desc, FileSourceDescriptor): + raise RuntimeError("Only file sources for code supported") + source_filename = source_desc.filename + scope.cpp = self.cpp + # Parse the given source file and return a parse tree. + num_errors = Errors.num_errors + try: with Utils.open_source_file(source_filename) as f: - from . import Parsing - s = PyrexScanner(f, source_desc, source_encoding = f.encoding, - scope = scope, context = self) - tree = Parsing.p_module(s, pxd, full_module_name) + from . import Parsing + s = PyrexScanner(f, source_desc, source_encoding = f.encoding, + scope = scope, context = self) + tree = Parsing.p_module(s, pxd, full_module_name) if self.options.formal_grammar: try: from ..Parser import ConcreteSyntaxTree @@ -375,14 +375,14 @@ class Context(object): "Formal grammar can only be used with compiled Cython with an available pgen.") ConcreteSyntaxTree.p_module(source_filename) except UnicodeDecodeError as e: - #import traceback - #traceback.print_exc() + #import traceback + #traceback.print_exc() raise self._report_decode_error(source_desc, e) - + if Errors.num_errors > num_errors: raise CompileError() return tree - + def _report_decode_error(self, source_desc, exc): msg = exc.args[-1] position = exc.args[2] @@ -395,53 +395,53 @@ class Context(object): idx += len(data) if idx >= position: column = position - (idx - len(data)) + 1 - break - + break + return error((source_desc, line, column), "Decoding error, missing or incorrect coding=<encoding-name> " "at top of source (cannot decode with encoding %r: %s)" % (encoding, msg)) - - def extract_module_name(self, path, options): - # Find fully_qualified module name from the full pathname - # of a source file. - dir, filename = os.path.split(path) - module_name, _ = os.path.splitext(filename) - if "." in module_name: - return module_name - names = [module_name] - while self.is_package_dir(dir): - parent, package_name = os.path.split(dir) - if parent == dir: - break - names.append(package_name) - dir = parent - names.reverse() - return ".".join(names) - - def setup_errors(self, options, result): + + def extract_module_name(self, path, options): + # Find fully_qualified module name from the full pathname + # of a source file. + dir, filename = os.path.split(path) + module_name, _ = os.path.splitext(filename) + if "." in module_name: + return module_name + names = [module_name] + while self.is_package_dir(dir): + parent, package_name = os.path.split(dir) + if parent == dir: + break + names.append(package_name) + dir = parent + names.reverse() + return ".".join(names) + + def setup_errors(self, options, result): Errors.reset() # clear any remaining error state - if options.use_listing_file: + if options.use_listing_file: path = result.listing_file = Utils.replace_suffix(result.main_source_file, ".lis") - else: - path = None - Errors.open_listing_file(path=path, - echo_to_stderr=options.errors_to_stderr) - - def teardown_errors(self, err, options, result): - source_desc = result.compilation_source.source_desc - if not isinstance(source_desc, FileSourceDescriptor): - raise RuntimeError("Only file sources for code supported") - Errors.close_listing_file() - result.num_errors = Errors.num_errors - if result.num_errors > 0: - err = True - if err and result.c_file: - try: - Utils.castrate_file(result.c_file, os.stat(source_desc.filename)) - except EnvironmentError: - pass - result.c_file = None - + else: + path = None + Errors.open_listing_file(path=path, + echo_to_stderr=options.errors_to_stderr) + + def teardown_errors(self, err, options, result): + source_desc = result.compilation_source.source_desc + if not isinstance(source_desc, FileSourceDescriptor): + raise RuntimeError("Only file sources for code supported") + Errors.close_listing_file() + result.num_errors = Errors.num_errors + if result.num_errors > 0: + err = True + if err and result.c_file: + try: + Utils.castrate_file(result.c_file, os.stat(source_desc.filename)) + except EnvironmentError: + pass + result.c_file = None + def get_output_filename(source_filename, cwd, options): if options.cplus: @@ -459,111 +459,111 @@ def get_output_filename(source_filename, cwd, options): return suggested_file_name -def create_default_resultobj(compilation_source, options): - result = CompilationResult() - result.main_source_file = compilation_source.source_desc.filename - result.compilation_source = compilation_source - source_desc = compilation_source.source_desc +def create_default_resultobj(compilation_source, options): + result = CompilationResult() + result.main_source_file = compilation_source.source_desc.filename + result.compilation_source = compilation_source + source_desc = compilation_source.source_desc result.c_file = get_output_filename(source_desc.filename, compilation_source.cwd, options) result.embedded_metadata = options.embedded_metadata - return result - - -def run_pipeline(source, options, full_module_name=None, context=None): - from . import Pipeline - - source_ext = os.path.splitext(source)[1] - options.configure_language_defaults(source_ext[1:]) # py/pyx - if context is None: - context = options.create_context() - - # Set up source object - cwd = os.getcwd() - abs_path = os.path.abspath(source) + return result + + +def run_pipeline(source, options, full_module_name=None, context=None): + from . import Pipeline + + source_ext = os.path.splitext(source)[1] + options.configure_language_defaults(source_ext[1:]) # py/pyx + if context is None: + context = options.create_context() + + # Set up source object + cwd = os.getcwd() + abs_path = os.path.abspath(source) full_module_name = full_module_name or options.module_name or context.extract_module_name(source, options) - + Utils.raise_error_if_module_name_forbidden(full_module_name) - 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 + 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 if Options.source_root: rel_path = os.path.relpath(abs_path, Options.source_root) - 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): + 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): with io.open(html_filename, "r", encoding="UTF-8") as html_file: if u'<!-- Generated by Cython' in html_file.read(100): options.annotate = True - - # Get pipeline - if source_ext.lower() == '.py' or not source_ext: - pipeline = Pipeline.create_py_pipeline(context, options, result) - else: - pipeline = Pipeline.create_pyx_pipeline(context, options, result) - - context.setup_errors(options, result) - err, enddata = Pipeline.run_pipeline(pipeline, source) - context.teardown_errors(err, options, result) - return result - - + + # Get pipeline + if source_ext.lower() == '.py' or not source_ext: + pipeline = Pipeline.create_py_pipeline(context, options, result) + else: + pipeline = Pipeline.create_pyx_pipeline(context, options, result) + + context.setup_errors(options, result) + err, enddata = Pipeline.run_pipeline(pipeline, source) + context.teardown_errors(err, options, result) + return result + + # ------------------------------------------------------------------------ -# -# Main Python entry points -# +# +# Main Python entry points +# # ------------------------------------------------------------------------ - -class CompilationSource(object): - """ + +class CompilationSource(object): + """ Contains the data necessary to start up a compilation pipeline for - a single compilation unit. - """ - def __init__(self, source_desc, full_module_name, cwd): - self.source_desc = source_desc - self.full_module_name = full_module_name - self.cwd = cwd - - -class CompilationOptions(object): + a single compilation unit. + """ + def __init__(self, source_desc, full_module_name, cwd): + self.source_desc = source_desc + self.full_module_name = full_module_name + self.cwd = cwd + + +class CompilationOptions(object): r""" See default_options at the end of this module for a list of all possible options and CmdLine.usage and CmdLine.parse_command_line() for their meaning. - """ - def __init__(self, defaults=None, **kw): - self.include_path = [] - if defaults: - if isinstance(defaults, CompilationOptions): - defaults = defaults.__dict__ - else: - defaults = default_options - - options = dict(defaults) - options.update(kw) - - # let's assume 'default_options' contains a value for most known compiler options - # and validate against them - unknown_options = set(options) - set(default_options) - # ignore valid options that are not in the defaults - unknown_options.difference_update(['include_path']) - if unknown_options: + """ + def __init__(self, defaults=None, **kw): + self.include_path = [] + if defaults: + if isinstance(defaults, CompilationOptions): + defaults = defaults.__dict__ + else: + defaults = default_options + + options = dict(defaults) + options.update(kw) + + # let's assume 'default_options' contains a value for most known compiler options + # and validate against them + unknown_options = set(options) - set(default_options) + # ignore valid options that are not in the defaults + unknown_options.difference_update(['include_path']) + if unknown_options: message = "got unknown compilation option%s, please remove: %s" % ( - 's' if len(unknown_options) > 1 else '', + 's' if len(unknown_options) > 1 else '', ', '.join(unknown_options)) raise ValueError(message) - + directive_defaults = Options.get_directive_defaults() directives = dict(options['compiler_directives']) # copy mutable field # check for invalid directives @@ -573,12 +573,12 @@ class CompilationOptions(object): 's' if len(unknown_directives) > 1 else '', ', '.join(unknown_directives)) raise ValueError(message) - options['compiler_directives'] = directives + options['compiler_directives'] = directives if directives.get('np_pythran', False) and not options['cplus']: import warnings warnings.warn("C++ mode forced when in Pythran mode!") options['cplus'] = True - if 'language_level' in directives and 'language_level' not in kw: + if 'language_level' in directives and 'language_level' not in kw: options['language_level'] = directives['language_level'] elif not options.get('language_level'): options['language_level'] = directive_defaults.get('language_level') @@ -586,25 +586,25 @@ class CompilationOptions(object): options['formal_grammar'] = directives['formal_grammar'] if options['cache'] is True: options['cache'] = os.path.join(Utils.get_cython_cache_dir(), 'compiler') - - self.__dict__.update(options) - - def configure_language_defaults(self, source_extension): - if source_extension == 'py': - if self.compiler_directives.get('binding') is None: - self.compiler_directives['binding'] = True - - def create_context(self): - return Context(self.include_path, self.compiler_directives, - self.cplus, self.language_level, options=self) - + + self.__dict__.update(options) + + def configure_language_defaults(self, source_extension): + if source_extension == 'py': + if self.compiler_directives.get('binding') is None: + self.compiler_directives['binding'] = True + + def create_context(self): + return Context(self.include_path, self.compiler_directives, + self.cplus, self.language_level, options=self) + def get_fingerprint(self): r""" Return a string that contains all the options that are relevant for cache invalidation. """ # Collect only the data that can affect the generated file(s). data = {} - + for key, value in self.__dict__.items(): if key in ['show_version', 'errors_to_stderr', 'verbose', 'quiet']: # verbosity flags have no influence on the compilation result @@ -676,111 +676,111 @@ class CompilationOptions(object): return to_fingerprint(data) -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 - api_file string or None The generated C API .h file - listing_file string or None File of error messages - object_file string or None Result of compiling the C file - extension_file string or None Result of linking the object file - num_errors integer Number of compilation errors - compilation_source CompilationSource - """ - - def __init__(self): - self.c_file = None - self.h_file = None - self.i_file = None - self.api_file = None - self.listing_file = None - self.object_file = None - self.extension_file = None - self.main_source_file = None - - -class CompilationResultSet(dict): - """ - 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): - self[source] = result - self.num_errors += result.num_errors - - -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. - """ - return run_pipeline(source, options, full_module_name) - - -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. - """ - # run_pipeline creates the context - # context = options.create_context() - sources = [os.path.abspath(source) for source in sources] - processed = set() - results = CompilationResultSet() - timestamps = options.timestamps - verbose = options.verbose - context = None +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 + api_file string or None The generated C API .h file + listing_file string or None File of error messages + object_file string or None Result of compiling the C file + extension_file string or None Result of linking the object file + num_errors integer Number of compilation errors + compilation_source CompilationSource + """ + + def __init__(self): + self.c_file = None + self.h_file = None + self.i_file = None + self.api_file = None + self.listing_file = None + self.object_file = None + self.extension_file = None + self.main_source_file = None + + +class CompilationResultSet(dict): + """ + 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): + self[source] = result + self.num_errors += result.num_errors + + +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. + """ + return run_pipeline(source, options, full_module_name) + + +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. + """ + # run_pipeline creates the context + # context = options.create_context() + sources = [os.path.abspath(source) for source in sources] + processed = set() + results = CompilationResultSet() + timestamps = options.timestamps + verbose = options.verbose + context = None cwd = os.getcwd() - for source in sources: - if source not in processed: - if context is None: - context = options.create_context() + for source in sources: + if source not in processed: + if context is None: + context = options.create_context() output_filename = get_output_filename(source, cwd, options) out_of_date = context.c_file_out_of_date(source, output_filename) if (not timestamps) or out_of_date: - if verbose: - sys.stderr.write("Compiling %s\n" % source) - - result = run_pipeline(source, options, context=context) - results.add(source, result) - # Compiling multiple sources in one context doesn't quite - # work properly yet. - context = None - processed.add(source) - return results - - -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 + if verbose: + sys.stderr.write("Compiling %s\n" % source) + + result = run_pipeline(source, options, context=context) + results.add(source, result) + # Compiling multiple sources in one context doesn't quite + # work properly yet. + context = None + processed.add(source) + return results + + +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 dependencies. The source argument may be a string or a sequence of strings. If it is a string and no recursion or timestamp - checking is requested, a CompilationResult is returned, otherwise a - CompilationResultSet is returned. - """ - options = CompilationOptions(defaults = options, **kwds) - if isinstance(source, basestring) and not options.timestamps: - return compile_single(source, options, full_module_name) - else: - return compile_multiple(source, options) - + checking is requested, a CompilationResult is returned, otherwise a + CompilationResultSet is returned. + """ + options = CompilationOptions(defaults = options, **kwds) + if isinstance(source, basestring) and not options.timestamps: + return compile_single(source, options, full_module_name) + else: + return compile_multiple(source, options) + @Utils.cached_function def search_include_directories(dirs, qualified_name, suffix, pos, include=False): @@ -848,76 +848,76 @@ def search_include_directories(dirs, qualified_name, suffix, pos, include=False) # ------------------------------------------------------------------------ -# -# Main command-line entry point -# +# +# Main command-line entry point +# # ------------------------------------------------------------------------ -def setuptools_main(): - return main(command_line = 1) - - -def main(command_line = 0): - args = sys.argv[1:] - any_failures = 0 - if command_line: - from .CmdLine import parse_command_line - options, sources = parse_command_line(args) - else: - options = CompilationOptions(default_options) - sources = args - - if options.show_version: - sys.stderr.write("Cython version %s\n" % version) - if options.working_path!="": - os.chdir(options.working_path) - try: - result = compile(sources, options) - if result.num_errors > 0: - any_failures = 1 +def setuptools_main(): + return main(command_line = 1) + + +def main(command_line = 0): + args = sys.argv[1:] + any_failures = 0 + if command_line: + from .CmdLine import parse_command_line + options, sources = parse_command_line(args) + else: + options = CompilationOptions(default_options) + sources = args + + if options.show_version: + sys.stderr.write("Cython version %s\n" % version) + if options.working_path!="": + os.chdir(options.working_path) + try: + result = compile(sources, options) + if result.num_errors > 0: + any_failures = 1 except (EnvironmentError, PyrexError) as e: - sys.stderr.write(str(e) + '\n') - any_failures = 1 - if any_failures: - sys.exit(1) - - + sys.stderr.write(str(e) + '\n') + any_failures = 1 + if any_failures: + sys.exit(1) + + # ------------------------------------------------------------------------ -# -# Set the default options depending on the platform -# +# +# Set the default options depending on the platform +# # ------------------------------------------------------------------------ - -default_options = dict( - show_version = 0, - use_listing_file = 0, - errors_to_stderr = 1, - cplus = 0, - output_file = None, - annotate = None, + +default_options = dict( + show_version = 0, + use_listing_file = 0, + errors_to_stderr = 1, + cplus = 0, + output_file = None, + annotate = None, annotate_coverage_xml = None, - generate_pxi = 0, - capi_reexport_cincludes = 0, - working_path = "", - timestamps = None, - verbose = 0, - quiet = 0, - compiler_directives = {}, + generate_pxi = 0, + capi_reexport_cincludes = 0, + working_path = "", + timestamps = None, + verbose = 0, + quiet = 0, + compiler_directives = {}, embedded_metadata = {}, - evaluate_tree_assertions = False, - emit_linenums = False, - relative_path_in_code_position_comments = True, - c_line_in_traceback = True, + evaluate_tree_assertions = False, + emit_linenums = False, + relative_path_in_code_position_comments = True, + c_line_in_traceback = True, language_level = None, # warn but default to 2 formal_grammar = False, - gdb_debug = False, + gdb_debug = False, module_name = None, init_suffix = None, - compile_time_env = None, - common_utility_include_dir = None, - output_dir=None, - build_dir=None, + compile_time_env = None, + common_utility_include_dir = None, + output_dir=None, + build_dir=None, cache=None, create_extension=None, np_pythran=False -) +) |