def base_pycondition(target, ver, if_lt=None, if_ge=None, indent=None, newline=False, fallback=""): """Produce code that depends on the Python version for the given target.""" internal_assert(isinstance(ver, tuple), "invalid pycondition version") internal_assert(if_lt or if_ge, "either if_lt or if_ge must be specified") if if_lt: if_lt = if_lt.strip() if if_ge: if_ge = if_ge.strip() target_supported_vers = get_vers_for_target(target) if all(tar_ver < ver for tar_ver in target_supported_vers): if not if_lt: return fallback out = if_lt elif all(tar_ver >= ver for tar_ver in target_supported_vers): if not if_ge: return fallback out = if_ge else: if if_lt and if_ge: out = """if _coconut_sys.version_info < {ver}: {lt_block} else: {ge_block}""".format( ver=repr(ver), lt_block=_indent(if_lt, by=1), ge_block=_indent(if_ge, by=1), ) elif if_lt: out = """if _coconut_sys.version_info < {ver}: {lt_block}""".format( ver=repr(ver), lt_block=_indent(if_lt, by=1), ) else: out = """if _coconut_sys.version_info >= {ver}: {ge_block}""".format( ver=repr(ver), ge_block=_indent(if_ge, by=1), ) if indent is not None: out = _indent(out, by=indent) if newline: out += "\n" return out
def process_header_args(which, target, use_hash, no_tco, strict): """Create the dictionary passed to str.format in the header, target_startswith, and target_info.""" target_startswith = one_num_ver(target) target_info = get_target_info(target) try_backport_lru_cache = r'''try: from backports.functools_lru_cache import lru_cache functools.lru_cache = lru_cache except ImportError: pass ''' try_import_trollius = r'''try: import trollius as asyncio except ImportError: class you_need_to_install_trollius: pass asyncio = you_need_to_install_trollius() ''' format_dict = dict( comment=comment(), empty_dict="{}", target_startswith=target_startswith, default_encoding=default_encoding, hash_line=hash_prefix + use_hash + "\n" if use_hash is not None else "", typing_line="# type: ignore\n" if which == "__coconut__" else "", VERSION_STR=VERSION_STR, module_docstring='"""Built-in Coconut utilities."""\n\n' if which == "__coconut__" else "", object="(object)" if target_startswith != "3" else "", import_asyncio=_indent( "" if not target or target_info >= (3, 5) else "import asyncio\n" if target_info >= (3, 4) else r'''if _coconut_sys.version_info >= (3, 4): import asyncio else: ''' + _indent(try_import_trollius) if target_info >= (3, ) else try_import_trollius, ), import_pickle=_indent(r'''if _coconut_sys.version_info < (3,): import cPickle as pickle else: import pickle''' if not target else "import cPickle as pickle" if target_info < (3, ) else "import pickle"), import_OrderedDict=_indent( r'''if _coconut_sys.version_info >= (2, 7): OrderedDict = collections.OrderedDict else: OrderedDict = dict''' if not target else "OrderedDict = collections.OrderedDict" if target_info >= ( 2, 7) else "OrderedDict = dict"), import_collections_abc=_indent( r'''if _coconut_sys.version_info < (3, 3): abc = collections else: import collections.abc as abc''' if target_startswith != "2" else "abc = collections"), bind_lru_cache=_indent(r'''if _coconut_sys.version_info < (3, 2): ''' + _indent(try_backport_lru_cache) if not target else try_backport_lru_cache if target_startswith == "2" else ""), comma_bytearray=", bytearray" if target_startswith != "3" else "", static_repr="staticmethod(repr)" if target_startswith != "3" else "repr", with_ThreadPoolExecutor= (r'''from multiprocessing import cpu_count # cpu_count() * 5 is the default Python 3.5 thread count with ThreadPoolExecutor(cpu_count() * 5)''' if target_info < (3, 5) else '''with ThreadPoolExecutor()'''), def_tco_func=r'''def _coconut_tco_func(self, *args, **kwargs): for func in self.patterns[:-1]: try: with _coconut_FunctionMatchErrorContext(self.FunctionMatchError): return func(*args, **kwargs) except self.FunctionMatchError: pass return _coconut_tail_call(self.patterns[-1], *args, **kwargs) ''', def_prepattern=(r'''def prepattern(base_func, **kwargs): """DEPRECATED: Use addpattern instead.""" def pattern_prepender(func): return addpattern(func, **kwargs)(base_func) return pattern_prepender ''' if not strict else ""), def_datamaker=(r'''def datamaker(data_type): """DEPRECATED: Use makedata instead.""" return _coconut.functools.partial(makedata, data_type) ''' if not strict else ""), comma_tco=", _coconut_tail_call, _coconut_tco" if not no_tco else "", ) # when anything is added to this list it must also be added to the stub file format_dict[ "underscore_imports"] = "_coconut, _coconut_MatchError{comma_tco}, _coconut_igetitem, _coconut_base_compose, _coconut_forward_compose, _coconut_back_compose, _coconut_forward_star_compose, _coconut_back_star_compose, _coconut_forward_dubstar_compose, _coconut_back_dubstar_compose, _coconut_pipe, _coconut_back_pipe, _coconut_star_pipe, _coconut_back_star_pipe, _coconut_dubstar_pipe, _coconut_back_dubstar_pipe, _coconut_bool_and, _coconut_bool_or, _coconut_none_coalesce, _coconut_minus, _coconut_map, _coconut_partial, _coconut_get_function_match_error, _coconut_base_pattern_func, _coconut_addpattern, _coconut_sentinel, _coconut_assert, _coconut_mark_as_match".format( **format_dict) format_dict["import_typing_NamedTuple"] = _indent( "import typing" if target_info >= (3, 6) else '''class typing{object}: @staticmethod def NamedTuple(name, fields): return _coconut.collections.namedtuple(name, [x for x, t in fields])''' .format(**format_dict), ) # ._coconut_tco_func is used in main.coco, so don't remove it # here without replacing its usage there format_dict[ "def_tco"] = "" if no_tco else '''class _coconut_tail_call{object}: __slots__ = ("func", "args", "kwargs") def __init__(self, func, *args, **kwargs): self.func, self.args, self.kwargs = func, args, kwargs _coconut_tco_func_dict = {empty_dict} def _coconut_tco(func): @_coconut.functools.wraps(func) def tail_call_optimized_func(*args, **kwargs): call_func = func while True:{comment.weakrefs_necessary_for_ignoring_bound_methods} wkref = _coconut_tco_func_dict.get(_coconut.id(call_func)) if (wkref is not None and wkref() is call_func) or _coconut.isinstance(call_func, _coconut_base_pattern_func): call_func = call_func._coconut_tco_func result = call_func(*args, **kwargs) # pass --no-tco to clean up your traceback if not isinstance(result, _coconut_tail_call): return result call_func, args, kwargs = result.func, result.args, result.kwargs tail_call_optimized_func._coconut_tco_func = func tail_call_optimized_func.__module__ = _coconut.getattr(func, "__module__", None) tail_call_optimized_func.__name__ = _coconut.getattr(func, "__name__", "<coconut tco function (pass --no-tco to remove)>") tail_call_optimized_func.__qualname__ = _coconut.getattr(func, "__qualname__", tail_call_optimized_func.__name__) _coconut_tco_func_dict[_coconut.id(tail_call_optimized_func)] = _coconut.weakref.ref(tail_call_optimized_func) return tail_call_optimized_func '''.format(**format_dict) return format_dict, target_startswith, target_info
def process_header_args(which, target, use_hash, no_tco, strict): """Create the dictionary passed to str.format in the header, target_startswith, and target_info.""" target_startswith = one_num_ver(target) target_info = get_target_info(target) try_backport_lru_cache = r'''try: from backports.functools_lru_cache import lru_cache functools.lru_cache = lru_cache except ImportError: pass ''' try_import_trollius = r'''try: import trollius as asyncio except ImportError: class you_need_to_install_trollius: pass asyncio = you_need_to_install_trollius() ''' format_dict = dict( comment=comment(), empty_dict="{}", target_startswith=target_startswith, default_encoding=default_encoding, hash_line=hash_prefix + use_hash + "\n" if use_hash is not None else "", typing_line="# type: ignore\n" if which == "__coconut__" else "", VERSION_STR=VERSION_STR, module_docstring='"""Built-in Coconut utilities."""\n\n' if which == "__coconut__" else "", object="(object)" if target_startswith != "3" else "", import_asyncio=_indent( "" if not target or target_info >= (3, 5) else "import asyncio\n" if target_info >= (3, 4) else r'''if _coconut_sys.version_info >= (3, 4): import asyncio else: ''' + _indent(try_import_trollius) if target_info >= (3,) else try_import_trollius, ), import_pickle=_indent( r'''if _coconut_sys.version_info < (3,): import cPickle as pickle else: import pickle''' if not target else "import cPickle as pickle" if target_info < (3,) else "import pickle" ), import_OrderedDict=_indent( r'''if _coconut_sys.version_info >= (2, 7): OrderedDict = collections.OrderedDict else: OrderedDict = dict''' if not target else "OrderedDict = collections.OrderedDict" if target_info >= (2, 7) else "OrderedDict = dict" ), import_collections_abc=_indent( r'''if _coconut_sys.version_info < (3, 3): abc = collections else: import collections.abc as abc''' if target_startswith != "2" else "abc = collections" ), bind_lru_cache=_indent( r'''if _coconut_sys.version_info < (3, 2): ''' + _indent(try_backport_lru_cache) if not target else try_backport_lru_cache if target_startswith == "2" else "" ), comma_bytearray=", bytearray" if target_startswith != "3" else "", static_repr="staticmethod(repr)" if target_startswith != "3" else "repr", with_ThreadPoolExecutor=( r'''from multiprocessing import cpu_count # cpu_count() * 5 is the default Python 3.5 thread count with ThreadPoolExecutor(cpu_count() * 5)''' if target_info < (3, 5) else '''with ThreadPoolExecutor()''' ), tco_decorator="@_coconut_tco\n" + " " * 8 if not no_tco else "", tail_call_func_args_kwargs="func(*args, **kwargs)" if no_tco else "_coconut_tail_call(func, *args, **kwargs)", comma_tco=", _coconut_tail_call, _coconut_tco" if not no_tco else "", def_coconut_NamedTuple=( r'''def _coconut_NamedTuple(name, fields): return _coconut.collections.namedtuple(name, [x for x, t in fields])''' if target_info < (3, 6) else "from typing import NamedTuple as _coconut_NamedTuple" ), def_prepattern=( r'''def prepattern(base_func): """DEPRECATED: Use addpattern instead.""" def pattern_prepender(func): return addpattern(func)(base_func) return pattern_prepender ''' if not strict else "" ), def_datamaker=( r'''def datamaker(data_type): """DEPRECATED: Use makedata instead.""" return _coconut.functools.partial(makedata, data_type) ''' if not strict else "" ), __coconut__=( '"__coconut__"' if target_startswith == "3" else 'b"__coconut__"' if target_startswith == "2" else 'str("__coconut__")' ), ) format_dict["underscore_imports"] = "_coconut, _coconut_NamedTuple, _coconut_MatchError{comma_tco}, _coconut_igetitem, _coconut_base_compose, _coconut_forward_compose, _coconut_back_compose, _coconut_forward_star_compose, _coconut_back_star_compose, _coconut_pipe, _coconut_star_pipe, _coconut_back_pipe, _coconut_back_star_pipe, _coconut_bool_and, _coconut_bool_or, _coconut_none_coalesce, _coconut_minus, _coconut_map, _coconut_partial".format(**format_dict) # ._coconut_tco_func is used in main.coco, so don't remove it # here without replacing its usage there format_dict["def_tco"] = "" if no_tco else '''class _coconut_tail_call{object}: __slots__ = ("func", "args", "kwargs") def __init__(self, func, *args, **kwargs): self.func, self.args, self.kwargs = func, args, kwargs _coconut_tco_func_dict = {empty_dict} def _coconut_tco(func): @_coconut.functools.wraps(func) def tail_call_optimized_func(*args, **kwargs): call_func = func while True: wkref = _coconut_tco_func_dict.get(_coconut.id(call_func)) if wkref is not None and wkref() is call_func: call_func = call_func._coconut_tco_func result = call_func(*args, **kwargs) # pass --no-tco to clean up your traceback if not isinstance(result, _coconut_tail_call): return result call_func, args, kwargs = result.func, result.args, result.kwargs tail_call_optimized_func._coconut_tco_func = func _coconut_tco_func_dict[_coconut.id(tail_call_optimized_func)] = _coconut.weakref.ref(tail_call_optimized_func) return tail_call_optimized_func '''.format(**format_dict) return format_dict, target_startswith, target_info
def process_header_args(which, target, use_hash, no_tco, strict, no_wrap): """Create the dictionary passed to str.format in the header.""" target_startswith = one_num_ver(target) target_info = get_target_info(target) pycondition = partial(base_pycondition, target) format_dict = dict( COMMENT=COMMENT, empty_dict="{}", lbrace="{", rbrace="}", target_startswith=target_startswith, default_encoding=default_encoding, hash_line=hash_prefix + use_hash + "\n" if use_hash is not None else "", typing_line="# type: ignore\n" if which == "__coconut__" else "", VERSION_STR=VERSION_STR, module_docstring='"""Built-in Coconut utilities."""\n\n' if which == "__coconut__" else "", object="" if target_startswith == "3" else "(object)", report_this_text=report_this_text, import_pickle=pycondition( (3, ), if_lt=r''' import cPickle as pickle ''', if_ge=r''' import pickle ''', indent=1, ), import_OrderedDict=_indent( r'''OrderedDict = collections.OrderedDict if _coconut_sys.version_info >= (2, 7) else dict''' if not target else "OrderedDict = collections.OrderedDict" if target_info >= (2, 7) else "OrderedDict = dict", by=1, ), import_collections_abc=pycondition( (3, 3), if_lt=r''' abc = collections ''', if_ge=r''' import collections.abc as abc ''', indent=1, ), set_zip_longest=_indent( r'''zip_longest = itertools.zip_longest if _coconut_sys.version_info >= (3,) else itertools.izip_longest''' if not target else "zip_longest = itertools.zip_longest" if target_info >= (3, ) else "zip_longest = itertools.izip_longest", by=1, ), comma_bytearray=", bytearray" if target_startswith != "3" else "", lstatic="staticmethod(" if target_startswith != "3" else "", rstatic=")" if target_startswith != "3" else "", zip_iter=_indent( r'''for items in _coconut.iter(_coconut.zip(*self.iters, strict=self.strict) if _coconut_sys.version_info >= (3, 10) else _coconut.zip_longest(*self.iters, fillvalue=_coconut_sentinel) if self.strict else _coconut.zip(*self.iters)): if self.strict and _coconut_sys.version_info < (3, 10) and _coconut.any(x is _coconut_sentinel for x in items): raise _coconut.ValueError("zip(..., strict=True) arguments have mismatched lengths") yield items''' if not target else r'''for items in _coconut.iter(_coconut.zip(*self.iters, strict=self.strict)): yield items''' if target_info >= (3, 10) else r'''for items in _coconut.iter(_coconut.zip_longest(*self.iters, fillvalue=_coconut_sentinel) if self.strict else _coconut.zip(*self.iters)): if self.strict and _coconut.any(x is _coconut_sentinel for x in items): raise _coconut.ValueError("zip(..., strict=True) arguments have mismatched lengths") yield items''', by=2, ), # disabled mocks must have different docstrings so the # interpreter can tell them apart from the real thing def_prepattern=(r'''def prepattern(base_func, **kwargs): """DEPRECATED: use addpattern instead.""" def pattern_prepender(func): return addpattern(func, **kwargs)(base_func) return pattern_prepender''' if not strict else r'''def prepattern(*args, **kwargs): """Deprecated feature 'prepattern' disabled by --strict compilation; use 'addpattern' instead.""" raise _coconut.NameError("deprecated feature 'prepattern' disabled by --strict compilation; use 'addpattern' instead")''' ), def_datamaker=(r'''def datamaker(data_type): """DEPRECATED: use makedata instead.""" return _coconut.functools.partial(makedata, data_type)''' if not strict else r'''def datamaker(*args, **kwargs): """Deprecated feature 'datamaker' disabled by --strict compilation; use 'makedata' instead.""" raise _coconut.NameError("deprecated feature 'datamaker' disabled by --strict compilation; use 'makedata' instead")''' ), return_method_of_self=pycondition( (3, ), if_lt=r''' return _coconut.types.MethodType(self, obj, objtype) ''', if_ge=r''' return _coconut.types.MethodType(self, obj) ''', indent=2, ), return_method_of_self_func=pycondition( (3, ), if_lt=r''' return _coconut.types.MethodType(self.func, obj, objtype) ''', if_ge=r''' return _coconut.types.MethodType(self.func, obj) ''', indent=2, ), def_call_set_names=( r'''def _coconut_call_set_names(cls): for k, v in _coconut.vars(cls).items(): set_name = _coconut.getattr(v, "__set_name__", None) if set_name is not None: set_name(cls, k)''' if target_startswith == "2" else r'''def _coconut_call_set_names(cls): pass''' if target_info >= (3, 6) else r'''def _coconut_call_set_names(cls): if _coconut_sys.version_info < (3, 6): for k, v in _coconut.vars(cls).items(): set_name = _coconut.getattr(v, "__set_name__", None) if set_name is not None: set_name(cls, k)'''), pattern_func_slots=pycondition( (3, 7), if_lt=r''' __slots__ = ("FunctionMatchError", "patterns", "__doc__", "__name__") ''', if_ge=r''' __slots__ = ("FunctionMatchError", "patterns", "__doc__", "__name__", "__qualname__") ''', indent=1, ), set_qualname_none=pycondition( (3, 7), if_ge=r''' self.__qualname__ = None ''', indent=2, ), set_qualname_func=pycondition( (3, 7), if_ge=r''' self.__qualname__ = _coconut.getattr(func, "__qualname__", self.__qualname__) ''', indent=2, ), tco_comma="_coconut_tail_call, _coconut_tco, " if not no_tco else "", call_set_names_comma="_coconut_call_set_names, " if target_info < (3, 6) else "", handle_cls_args_comma= "_coconut_handle_cls_kwargs, _coconut_handle_cls_stargs, " if target_startswith != "3" else "", ) # second round for format dict elements that use the format dict format_dict.update( dict( # when anything is added to this list it must also be added to *both* __coconut__.pyi stub files underscore_imports= "{tco_comma}{call_set_names_comma}{handle_cls_args_comma}_coconut, _coconut_MatchError, _coconut_igetitem, _coconut_base_compose, _coconut_forward_compose, _coconut_back_compose, _coconut_forward_star_compose, _coconut_back_star_compose, _coconut_forward_dubstar_compose, _coconut_back_dubstar_compose, _coconut_pipe, _coconut_star_pipe, _coconut_dubstar_pipe, _coconut_back_pipe, _coconut_back_star_pipe, _coconut_back_dubstar_pipe, _coconut_none_pipe, _coconut_none_star_pipe, _coconut_none_dubstar_pipe, _coconut_bool_and, _coconut_bool_or, _coconut_none_coalesce, _coconut_minus, _coconut_map, _coconut_partial, _coconut_get_function_match_error, _coconut_base_pattern_func, _coconut_addpattern, _coconut_sentinel, _coconut_assert, _coconut_mark_as_match, _coconut_reiterable, _coconut_self_match_types, _coconut_dict_merge, _coconut_exec" .format(**format_dict), import_typing_NamedTuple=pycondition( (3, 6), if_lt=''' class typing{object}: @staticmethod def NamedTuple(name, fields): return _coconut.collections.namedtuple(name, [x for x, t in fields]) '''.format(**format_dict), if_ge=''' import typing ''', indent=1, ), import_asyncio=pycondition( (3, 4), if_lt=''' try: import trollius as asyncio except ImportError: class you_need_to_install_trollius{object}: pass asyncio = you_need_to_install_trollius() '''.format(**format_dict), if_ge=''' import asyncio ''', indent=1, ), maybe_bind_lru_cache=pycondition( (3, 2), if_lt=''' try: from backports.functools_lru_cache import lru_cache functools.lru_cache = lru_cache except ImportError: class you_need_to_install_backports_functools_lru_cache{object}: pass functools.lru_cache = you_need_to_install_backports_functools_lru_cache() '''.format(**format_dict), if_ge=None, indent=1, newline=True, ), ), ) return format_dict