diff options
author | alexv-smirnov <alex@ydb.tech> | 2023-03-15 19:59:12 +0300 |
---|---|---|
committer | alexv-smirnov <alex@ydb.tech> | 2023-03-15 19:59:12 +0300 |
commit | 056bb284ccf8dd6793ec3a54ffa36c4fb2b9ad11 (patch) | |
tree | 4740980126f32e3af7937ba0ca5f83e59baa4ab0 /contrib/tools/cython/Cython/Compiler/Options.py | |
parent | 269126dcced1cc8b53eb4398b4a33e5142f10290 (diff) | |
download | ydb-056bb284ccf8dd6793ec3a54ffa36c4fb2b9ad11.tar.gz |
add library/cpp/actors, ymake build to ydb oss export
Diffstat (limited to 'contrib/tools/cython/Cython/Compiler/Options.py')
-rw-r--r-- | contrib/tools/cython/Cython/Compiler/Options.py | 555 |
1 files changed, 555 insertions, 0 deletions
diff --git a/contrib/tools/cython/Cython/Compiler/Options.py b/contrib/tools/cython/Cython/Compiler/Options.py new file mode 100644 index 0000000000..6c9103bb14 --- /dev/null +++ b/contrib/tools/cython/Cython/Compiler/Options.py @@ -0,0 +1,555 @@ +# +# Cython - Compilation-wide options and pragma declarations +# + +from __future__ import absolute_import + + +class ShouldBeFromDirective(object): + + known_directives = [] + + def __init__(self, options_name, directive_name=None, disallow=False): + self.options_name = options_name + self.directive_name = directive_name or options_name + self.disallow = disallow + self.known_directives.append(self) + + def __nonzero__(self): + self._bad_access() + + def __int__(self): + self._bad_access() + + def _bad_access(self): + raise RuntimeError(repr(self)) + + def __repr__(self): + return ( + "Illegal access of '%s' from Options module rather than directive '%s'" + % (self.options_name, self.directive_name)) + + +""" +The members of this module are documented using autodata in +Cython/docs/src/reference/compilation.rst. +See http://www.sphinx-doc.org/en/master/ext/autodoc.html#directive-autoattribute +for how autodata works. +Descriptions of those members should start with a #: +Donc forget to keep the docs in sync by removing and adding +the members in both this file and the .rst file. +""" + +#: Whether or not to include docstring in the Python extension. If False, the binary size +#: will be smaller, but the ``__doc__`` attribute of any class or function will be an +#: empty string. +docstrings = True + +#: Embed the source code position in the docstrings of functions and classes. +embed_pos_in_docstring = False + +#: Copy the original source code line by line into C code comments +#: in the generated code file to help with understanding the output. +#: This is also required for coverage analysis. +emit_code_comments = True + +# undocumented +pre_import = None + +#: Decref global variables in each module on exit for garbage collection. +#: 0: None, 1+: interned objects, 2+: cdef globals, 3+: types objects +#: Mostly for reducing noise in Valgrind as it typically executes at process exit +#: (when all memory will be reclaimed anyways). +#: Note that directly or indirectly executed cleanup code that makes use of global +#: variables or types may no longer be safe when enabling the respective level since +#: there is no guaranteed order in which the (reference counted) objects will +#: be cleaned up. The order can change due to live references and reference cycles. +generate_cleanup_code = False + +#: Should tp_clear() set object fields to None instead of clearing them to NULL? +clear_to_none = True + +#: Generate an annotated HTML version of the input source files for debugging and optimisation purposes. +#: This has the same effect as the ``annotate`` argument in :func:`cythonize`. +annotate = False + +# When annotating source files in HTML, include coverage information from +# this file. +annotate_coverage_xml = None + +#: This will abort the compilation on the first error occurred rather than trying +#: to keep going and printing further error messages. +fast_fail = False + +#: Turn all warnings into errors. +warning_errors = False + +#: Make unknown names an error. Python raises a NameError when +#: encountering unknown names at runtime, whereas this option makes +#: them a compile time error. If you want full Python compatibility, +#: you should disable this option and also 'cache_builtins'. +error_on_unknown_names = True + +#: Make uninitialized local variable reference a compile time error. +#: Python raises UnboundLocalError at runtime, whereas this option makes +#: them a compile time error. Note that this option affects only variables +#: of "python object" type. +error_on_uninitialized = True + +#: This will convert statements of the form ``for i in range(...)`` +#: to ``for i from ...`` when ``i`` is a C integer type, and the direction +#: (i.e. sign of step) can be determined. +#: WARNING: This may change the semantics if the range causes assignment to +#: i to overflow. Specifically, if this option is set, an error will be +#: raised before the loop is entered, whereas without this option the loop +#: will execute until an overflowing value is encountered. +convert_range = True + +#: Perform lookups on builtin names only once, at module initialisation +#: time. This will prevent the module from getting imported if a +#: builtin name that it uses cannot be found during initialisation. +#: Default is True. +#: Note that some legacy builtins are automatically remapped +#: from their Python 2 names to their Python 3 names by Cython +#: when building in Python 3.x, +#: so that they do not get in the way even if this option is enabled. +cache_builtins = True + +#: Generate branch prediction hints to speed up error handling etc. +gcc_branch_hints = True + +#: Enable this to allow one to write ``your_module.foo = ...`` to overwrite the +#: definition if the cpdef function foo, at the cost of an extra dictionary +#: lookup on every call. +#: If this is false it generates only the Python wrapper and no override check. +lookup_module_cpdef = False + +#: Whether or not to embed the Python interpreter, for use in making a +#: standalone executable or calling from external libraries. +#: This will provide a C function which initialises the interpreter and +#: executes the body of this module. +#: See `this demo <https://github.com/cython/cython/tree/master/Demos/embed>`_ +#: for a concrete example. +#: If true, the initialisation function is the C main() function, but +#: this option can also be set to a non-empty string to provide a function name explicitly. +#: Default is False. +embed = None + +# In previous iterations of Cython, globals() gave the first non-Cython module +# globals in the call stack. Sage relies on this behavior for variable injection. +old_style_globals = ShouldBeFromDirective('old_style_globals') + +#: Allows cimporting from a pyx file without a pxd file. +cimport_from_pyx = False + +#: Maximum number of dimensions for buffers -- set lower than number of +#: dimensions in numpy, as +#: slices are passed by value and involve a lot of copying. +buffer_max_dims = 8 + +#: Number of function closure instances to keep in a freelist (0: no freelists) +closure_freelist_size = 8 + +# Arcadia specific +source_root = None + + +def get_directive_defaults(): + # To add an item to this list, all accesses should be changed to use the new + # directive, and the global option itself should be set to an instance of + # ShouldBeFromDirective. + for old_option in ShouldBeFromDirective.known_directives: + value = globals().get(old_option.options_name) + assert old_option.directive_name in _directive_defaults + if not isinstance(value, ShouldBeFromDirective): + if old_option.disallow: + raise RuntimeError( + "Option '%s' must be set from directive '%s'" % ( + old_option.option_name, old_option.directive_name)) + else: + # Warn? + _directive_defaults[old_option.directive_name] = value + return _directive_defaults + +# Declare compiler directives +_directive_defaults = { + 'boundscheck' : True, + 'nonecheck' : False, + 'initializedcheck' : True, + 'embedsignature' : False, + 'auto_cpdef': False, + 'auto_pickle': None, + 'cdivision': False, # was True before 0.12 + 'cdivision_warnings': False, + 'c_api_binop_methods': True, + 'cpow': True, + 'overflowcheck': False, + 'overflowcheck.fold': True, + 'always_allow_keywords': False, + 'allow_none_for_extension_args': True, + 'wraparound' : True, + 'ccomplex' : False, # use C99/C++ for complex types and arith + 'callspec' : "", + 'nogil' : False, + 'profile': False, + 'linetrace': False, + 'emit_code_comments': True, # copy original source code into C code comments + 'annotation_typing': True, # read type declarations from Python function annotations + 'infer_types': None, + 'infer_types.verbose': False, + 'autotestdict': True, + 'autotestdict.cdef': False, + 'autotestdict.all': False, + 'language_level': None, + 'fast_getattr': False, # Undocumented until we come up with a better way to handle this everywhere. + 'py2_import': False, # For backward compatibility of Cython's source code in Py3 source mode + 'preliminary_late_includes_cy28': False, # Temporary directive in 0.28, to be removed in a later version (see GH#2079). + 'iterable_coroutine': False, # Make async coroutines backwards compatible with the old asyncio yield-from syntax. + 'c_string_type': 'bytes', + 'c_string_encoding': '', + 'type_version_tag': True, # enables Py_TPFLAGS_HAVE_VERSION_TAG on extension types + 'unraisable_tracebacks': True, + 'old_style_globals': False, + 'np_pythran': False, + 'fast_gil': False, + + # set __file__ and/or __path__ to known source/target path at import time (instead of not having them available) + 'set_initial_path' : None, # SOURCEFILE or "/full/path/to/module" + + 'warn': None, + 'warn.undeclared': False, + 'warn.unreachable': True, + 'warn.maybe_uninitialized': False, + 'warn.unused': False, + 'warn.unused_arg': False, + 'warn.unused_result': False, + 'warn.multiple_declarators': True, + +# optimizations + 'optimize.inline_defnode_calls': True, + 'optimize.unpack_method_calls': True, # increases code size when True + 'optimize.unpack_method_calls_in_pyinit': False, # uselessly increases code size when True + 'optimize.use_switch': True, + +# remove unreachable code + 'remove_unreachable': True, + +# control flow debug directives + 'control_flow.dot_output': "", # Graphviz output filename + 'control_flow.dot_annotate_defs': False, # Annotate definitions + +# test support + 'test_assert_path_exists' : [], + 'test_fail_if_path_exists' : [], + +# experimental, subject to change + 'binding': None, + + 'formal_grammar': False, +} + +# Extra warning directives +extra_warnings = { + 'warn.maybe_uninitialized': True, + 'warn.unreachable': True, + 'warn.unused': True, +} + +def one_of(*args): + def validate(name, value): + if value not in args: + raise ValueError("%s directive must be one of %s, got '%s'" % ( + name, args, value)) + else: + return value + return validate + + +def normalise_encoding_name(option_name, encoding): + """ + >>> normalise_encoding_name('c_string_encoding', 'ascii') + 'ascii' + >>> normalise_encoding_name('c_string_encoding', 'AsCIi') + 'ascii' + >>> normalise_encoding_name('c_string_encoding', 'us-ascii') + 'ascii' + >>> normalise_encoding_name('c_string_encoding', 'utF8') + 'utf8' + >>> normalise_encoding_name('c_string_encoding', 'utF-8') + 'utf8' + >>> normalise_encoding_name('c_string_encoding', 'deFAuLT') + 'default' + >>> normalise_encoding_name('c_string_encoding', 'default') + 'default' + >>> normalise_encoding_name('c_string_encoding', 'SeriousLyNoSuch--Encoding') + 'SeriousLyNoSuch--Encoding' + """ + if not encoding: + return '' + if encoding.lower() in ('default', 'ascii', 'utf8'): + return encoding.lower() + import codecs + try: + decoder = codecs.getdecoder(encoding) + except LookupError: + return encoding # may exists at runtime ... + for name in ('ascii', 'utf8'): + if codecs.getdecoder(name) == decoder: + return name + return encoding + + +# Override types possibilities above, if needed +directive_types = { + 'language_level': str, # values can be None/2/3/'3str', where None == 2+warning + 'auto_pickle': bool, + 'locals': dict, + 'final' : bool, # final cdef classes and methods + 'nogil' : bool, + 'internal' : bool, # cdef class visibility in the module dict + 'infer_types' : bool, # values can be True/None/False + 'binding' : bool, + 'cfunc' : None, # decorators do not take directive value + 'ccall' : None, + 'inline' : None, + 'staticmethod' : None, + 'cclass' : None, + 'no_gc_clear' : bool, + 'no_gc' : bool, + 'returns' : type, + 'exceptval': type, # actually (type, check=True/False), but has its own parser + 'set_initial_path': str, + 'freelist': int, + 'c_string_type': one_of('bytes', 'bytearray', 'str', 'unicode'), + 'c_string_encoding': normalise_encoding_name, + 'cpow': bool +} + +for key, val in _directive_defaults.items(): + if key not in directive_types: + directive_types[key] = type(val) + +directive_scopes = { # defaults to available everywhere + # 'module', 'function', 'class', 'with statement' + 'auto_pickle': ('module', 'cclass'), + 'final' : ('cclass', 'function'), + 'nogil' : ('function', 'with statement'), + 'inline' : ('function',), + 'cfunc' : ('function', 'with statement'), + 'ccall' : ('function', 'with statement'), + 'returns' : ('function',), + 'exceptval' : ('function',), + 'locals' : ('function',), + 'staticmethod' : ('function',), # FIXME: analysis currently lacks more specific function scope + 'no_gc_clear' : ('cclass',), + 'no_gc' : ('cclass',), + 'internal' : ('cclass',), + 'cclass' : ('class', 'cclass', 'with statement'), + 'autotestdict' : ('module',), + 'autotestdict.all' : ('module',), + 'autotestdict.cdef' : ('module',), + 'set_initial_path' : ('module',), + 'test_assert_path_exists' : ('function', 'class', 'cclass'), + 'test_fail_if_path_exists' : ('function', 'class', 'cclass'), + 'freelist': ('cclass',), + 'emit_code_comments': ('module',), + 'annotation_typing': ('module',), # FIXME: analysis currently lacks more specific function scope + # Avoid scope-specific to/from_py_functions for c_string. + 'c_string_type': ('module',), + 'c_string_encoding': ('module',), + 'type_version_tag': ('module', 'cclass'), + 'language_level': ('module',), + # globals() could conceivably be controlled at a finer granularity, + # but that would complicate the implementation + 'old_style_globals': ('module',), + 'np_pythran': ('module',), + 'fast_gil': ('module',), + 'iterable_coroutine': ('module', 'function'), +} + + +def parse_directive_value(name, value, relaxed_bool=False): + """ + Parses value as an option value for the given name and returns + the interpreted value. None is returned if the option does not exist. + + >>> print(parse_directive_value('nonexisting', 'asdf asdfd')) + None + >>> parse_directive_value('boundscheck', 'True') + True + >>> parse_directive_value('boundscheck', 'true') + Traceback (most recent call last): + ... + ValueError: boundscheck directive must be set to True or False, got 'true' + + >>> parse_directive_value('c_string_encoding', 'us-ascii') + 'ascii' + >>> parse_directive_value('c_string_type', 'str') + 'str' + >>> parse_directive_value('c_string_type', 'bytes') + 'bytes' + >>> parse_directive_value('c_string_type', 'bytearray') + 'bytearray' + >>> parse_directive_value('c_string_type', 'unicode') + 'unicode' + >>> parse_directive_value('c_string_type', 'unnicode') + Traceback (most recent call last): + ValueError: c_string_type directive must be one of ('bytes', 'bytearray', 'str', 'unicode'), got 'unnicode' + """ + type = directive_types.get(name) + if not type: + return None + orig_value = value + if type is bool: + value = str(value) + if value == 'True': + return True + if value == 'False': + return False + if relaxed_bool: + value = value.lower() + if value in ("true", "yes"): + return True + elif value in ("false", "no"): + return False + raise ValueError("%s directive must be set to True or False, got '%s'" % ( + name, orig_value)) + elif type is int: + try: + return int(value) + except ValueError: + raise ValueError("%s directive must be set to an integer, got '%s'" % ( + name, orig_value)) + elif type is str: + return str(value) + elif callable(type): + return type(name, value) + else: + assert False + + +def parse_directive_list(s, relaxed_bool=False, ignore_unknown=False, + current_settings=None): + """ + Parses a comma-separated list of pragma options. Whitespace + is not considered. + + >>> parse_directive_list(' ') + {} + >>> (parse_directive_list('boundscheck=True') == + ... {'boundscheck': True}) + True + >>> parse_directive_list(' asdf') + Traceback (most recent call last): + ... + ValueError: Expected "=" in option "asdf" + >>> parse_directive_list('boundscheck=hey') + Traceback (most recent call last): + ... + ValueError: boundscheck directive must be set to True or False, got 'hey' + >>> parse_directive_list('unknown=True') + Traceback (most recent call last): + ... + ValueError: Unknown option: "unknown" + >>> warnings = parse_directive_list('warn.all=True') + >>> len(warnings) > 1 + True + >>> sum(warnings.values()) == len(warnings) # all true. + True + """ + if current_settings is None: + result = {} + else: + result = current_settings + for item in s.split(','): + item = item.strip() + if not item: + continue + if '=' not in item: + raise ValueError('Expected "=" in option "%s"' % item) + name, value = [s.strip() for s in item.strip().split('=', 1)] + if name not in _directive_defaults: + found = False + if name.endswith('.all'): + prefix = name[:-3] + for directive in _directive_defaults: + if directive.startswith(prefix): + found = True + parsed_value = parse_directive_value(directive, value, relaxed_bool=relaxed_bool) + result[directive] = parsed_value + if not found and not ignore_unknown: + raise ValueError('Unknown option: "%s"' % name) + else: + parsed_value = parse_directive_value(name, value, relaxed_bool=relaxed_bool) + result[name] = parsed_value + return result + + +def parse_variable_value(value): + """ + Parses value as an option value for the given name and returns + the interpreted value. + + >>> parse_variable_value('True') + True + >>> parse_variable_value('true') + 'true' + >>> parse_variable_value('us-ascii') + 'us-ascii' + >>> parse_variable_value('str') + 'str' + >>> parse_variable_value('123') + 123 + >>> parse_variable_value('1.23') + 1.23 + + """ + if value == "True": + return True + elif value == "False": + return False + elif value == "None": + return None + elif value.isdigit(): + return int(value) + else: + try: + value = float(value) + except Exception: + # Not a float + pass + return value + + +def parse_compile_time_env(s, current_settings=None): + """ + Parses a comma-separated list of pragma options. Whitespace + is not considered. + + >>> parse_compile_time_env(' ') + {} + >>> (parse_compile_time_env('HAVE_OPENMP=True') == + ... {'HAVE_OPENMP': True}) + True + >>> parse_compile_time_env(' asdf') + Traceback (most recent call last): + ... + ValueError: Expected "=" in option "asdf" + >>> parse_compile_time_env('NUM_THREADS=4') == {'NUM_THREADS': 4} + True + >>> parse_compile_time_env('unknown=anything') == {'unknown': 'anything'} + True + """ + if current_settings is None: + result = {} + else: + result = current_settings + for item in s.split(','): + item = item.strip() + if not item: + continue + if '=' not in item: + raise ValueError('Expected "=" in option "%s"' % item) + name, value = [s.strip() for s in item.split('=', 1)] + result[name] = parse_variable_value(value) + return result |