class RModelDriver(InterpretedModelDriver): # pragma: R r"""Base class for running R models. Args: name (str): Driver name. args (str or list): Argument(s) for running the model in matlab. Generally, this should be the full path to a Matlab script. **kwargs: Additional keyword arguments are passed to parent class's __init__ method. """ _schema_subtype_description = ('Model is written in R.') language = 'R' language_aliases = ['r'] language_ext = '.R' base_languages = ['python'] default_interpreter = 'Rscript' # Dynamically setting the interface library causes circular a import so # it is defined here statically. For dynamic import, use the following: # interface_library = PythonModelDriver.interface_library interface_library = 'yggdrasil' interface_dependencies = install.requirements_from_description() # The Batch version causes output to saved to a file rather than directed to # stdout so use Rscript instead. For the batch version, use the following: # default_interpreter_flags = ['CMD', 'BATCH' '--vanilla', '--silent'] default_interpreter_flags = ['--default-packages=methods,utils'] send_converters = {'table': serialize.consolidate_array} type_map = { 'int': 'integer, bit64::integer64', 'float': 'double', 'string': 'character', 'array': 'list', 'object': 'list', 'boolean': 'logical', 'null': 'NULL', 'uint': 'integer', 'complex': 'complex', 'bytes': 'char (utf-8)', 'unicode': 'char', '1darray': 'list', 'ndarray': 'list', 'ply': 'PlyDict', 'obj': 'ObjDict', 'schema': 'list' } function_param = { 'import': 'source(\"{filename}\")', 'interface': 'library(yggdrasil)', 'input': '{channel} <- YggInterface(\"YggInput\", \"{channel_name}\")', 'output': '{channel} <- YggInterface(\"YggOutput\", \"{channel_name}\")', 'table_input': ('{channel} <- YggInterface(\"YggAsciiTableInput\", ' '\"{channel_name}\")'), 'table_output': ('{channel} <- YggInterface(\"YggAsciiTableOutput\", ' '\"{channel_name}\", \"{format_str}\")'), 'recv': 'c({flag_var}, {recv_var}) %<-% {channel}$recv()', 'send': '{flag_var} <- {channel}$send({send_var})', 'function_call': '{output_var} <- {function_name}({input_var})', 'define': '{variable} <- {value}', 'true': 'TRUE', 'not': '!', 'comment': '#', 'indent': 2 * ' ', 'quote': '\"', 'print': 'print(\"{message}\")', 'fprintf': 'print(sprintf(\"{message}\", {variables}))', 'error': 'stop(\"{error_msg}\")', 'block_end': '}', 'if_begin': 'if({cond}) {{', 'for_begin': 'for ({iter_var} in {iter_begin}:{iter_end}) {{', 'while_begin': 'while ({cond}) {{', 'try_begin': 'tryCatch({', 'try_except': '}}, error = function({error_var}) {{', 'try_end': '})', 'assign': '{name} <- {value}' } @classmethod def is_library_installed(cls, lib, **kwargs): r"""Determine if a dependency is installed. Args: lib (str): Name of the library that should be checked. **kwargs: Additional keyword arguments are ignored. Returns: bool: True if the library is installed, False otherwise. """ if lib not in cls._library_cache: try: cls.run_executable(['-e', 'library(%s)' % lib]) cls._library_cache[lib] = True except RuntimeError: cls._library_cache[lib] = False return cls._library_cache[lib] @classmethod def language_version(cls, **kwargs): r"""Determine the version of this language. Args: **kwargs: Keyword arguments are passed to the parent class's method. Returns: str: Version of compiler/interpreter for this language. """ kwargs.setdefault('skip_interpreter_flags', True) return super(RModelDriver, cls).language_version(**kwargs) # @property # def debug_flags(self): # r"""list: Flags that should be prepended to an executable command to # enable debugging.""" # if self.with_valgrind: # interp = 'R'.join(self.get_interpreter().rsplit('Rscript', 1)) # return [interp, '-d', '"valgrind %s"' # % ' '.join(self.valgrind_flags), '--vanilla', '-f'] # return super(RModelDriver, self).debug_flags def set_env(self): r"""Get environment variables that should be set for the model process. Returns: dict: Environment variables for the model process. """ out = super(RModelDriver, self).set_env() out['RETICULATE_PYTHON'] = PythonModelDriver.get_interpreter() c_linker = CModelDriver.get_tool('linker') search_dirs = c_linker.get_search_path(conda_only=True) out = CModelDriver.update_ld_library_path(out, paths_to_add=search_dirs, add_to_front=True) return out @classmethod def comm_atexit(cls, comm): # pragma: no cover r"""Operations performed on comm at exit including draining receive. Args: comm (CommBase): Communication object. """ if comm.direction == 'recv': while comm.recv(timeout=0)[0]: comm.sleep() else: comm.send_eof() if not getattr(comm, 'dont_backlog', True): comm.linger_close() @classmethod def language2python(cls, robj): r"""Prepare an R object for serialization in Python. Args: robj (object): Python object prepared in R. Returns: object: Python object in a form that is serialization friendly. """ logger.debug("language2python: %s, %s" % (robj, type(robj))) if isinstance(robj, tuple): return tuple([cls.language2python(x) for x in robj]) elif isinstance(robj, list): return [cls.language2python(x) for x in robj] elif isinstance(robj, dict): return {k: cls.language2python(v) for k, v in robj.items()} elif isinstance(robj, backwards.string_types): return backwards.as_bytes(robj) return robj @classmethod def python2language(cls, pyobj): r"""Prepare a python object for transformation in R. Args: pyobj (object): Python object. Returns: object: Python object in a form that is R friendly. """ logger.debug("python2language: %s, %s" % (pyobj, type(pyobj))) if isinstance(pyobj, tuple): return tuple([cls.python2language(x) for x in pyobj]) elif isinstance(pyobj, list): return [cls.python2language(x) for x in pyobj] elif isinstance(pyobj, OrderedDict): return OrderedDict([(backwards.as_str(k), cls.python2language(v)) for k, v in pyobj.items()]) elif isinstance(pyobj, dict): return { backwards.as_str(k): cls.python2language(v) for k, v in pyobj.items() } elif isinstance(pyobj, tuple(list(backwards.string_types) + [np.string_])): return backwards.as_str(pyobj) elif isinstance(pyobj, pd.DataFrame): # R dosn't have int64 and will cast 64bit ints as floats if passed # without casting them to int32 first for n in pyobj.columns: if pyobj[n].dtype == np.dtype('int64'): pyobj[n] = pyobj[n].astype('int32') elif ((not backwards.PY2) and (pyobj[n].dtype == np.dtype('object')) and isinstance(pyobj[n][0], backwards.bytes_type)): pyobj[n] = pyobj[n].apply(backwards.as_str) return pyobj @classmethod def write_model_wrapper(cls, model_file, model_function, **kwargs): r"""Return the lines required to wrap a model function as an integrated model. Args: model_file (str): Full path to the file containing the model function's declaration. model_function (str): Name of the model function. **kwargs: Additional keyword arguments are passed to the parent class's method. Returns: list: Lines of code wrapping the provided model with the necessary code to run it as part of an integration. """ if platform._is_win: # pragma: windows model_file = model_file.replace('\\', '/') return super(RModelDriver, cls).write_model_wrapper(model_file, model_function, **kwargs)
class RModelDriver(InterpretedModelDriver): # pragma: R r"""Base class for running R models. Args: name (str): Driver name. args (str or list): Argument(s) for running the model in matlab. Generally, this should be the full path to a Matlab script. **kwargs: Additional keyword arguments are passed to parent class's __init__ method. """ _schema_subtype_description = ('Model is written in R.') language = 'R' language_aliases = ['r'] language_ext = '.R' base_languages = ['python'] default_interpreter = 'Rscript' # Dynamically setting the interface library causes circular a import so # it is defined here statically. For dynamic import, use the following: # interface_library = PythonModelDriver.interface_library interface_library = 'yggdrasil' interface_dependencies = [ x.split()[0] for x in install.requirements_from_description() ] # The Batch version causes output to saved to a file rather than directed to # stdout so use Rscript instead. For the batch version, use the following: # default_interpreter_flags = ['CMD', 'BATCH' '--vanilla', '--silent'] default_interpreter_flags = ['--default-packages=methods,utils'] send_converters = {'table': serialize.consolidate_array} type_map = { 'int': 'integer, bit64::integer64', 'float': 'double', 'string': 'character', 'array': 'list', 'object': 'list', 'boolean': 'logical', 'null': 'NA', 'uint': 'integer', 'complex': 'complex', 'bytes': 'char (utf-8)', 'unicode': 'char', '1darray': 'list', 'ndarray': 'list', 'ply': 'PlyDict', 'obj': 'ObjDict', 'schema': 'list' } function_param = { 'import': 'source(\"{filename}\")', 'istype': 'is({variable}, \"{type}\")', 'len': 'length({variable})', 'index': '{variable}[[{index}]]', 'first_index': 1, 'interface': 'library(yggdrasil)', 'input': '{channel} <- YggInterface(\"YggInput\", \"{channel_name}\")', 'output': '{channel} <- YggInterface(\"YggOutput\", \"{channel_name}\")', 'python_interface': ('{channel} <- YggInterface(\"{python_interface}\", ' '\"{channel_name}\")'), 'python_interface_format': ('{channel} <- YggInterface(' '\"{python_interface}\", ' '\"{channel_name}\", ' '\"{format_str}\")'), 'recv_function': '{channel}$recv', 'send_function': '{channel}$send', 'multiple_outputs': 'c({outputs})', 'multiple_outputs_def': 'list({outputs})', 'true': 'TRUE', 'false': 'FALSE', 'not': '!', 'and': '&&', 'comment': '#', 'indent': 2 * ' ', 'quote': '\"', 'print_generic': 'print({object})', 'print': 'print(\"{message}\")', 'fprintf': 'print(sprintf(\"{message}\", {variables}))', 'error': 'stop(\"{error_msg}\")', 'block_end': '}', 'if_begin': 'if ({cond}) {{', 'if_elif': '}} else if ({cond}) {{', 'if_else': '}} else {{', 'for_begin': 'for ({iter_var} in {iter_begin}:{iter_end}) {{', 'while_begin': 'while ({cond}) {{', 'try_begin': 'tryCatch({', 'try_except': '}}, error = function({error_var}) {{', 'try_end': '})', 'assign': '{name} <- {value}', 'assign_mult': '{name} %<-% {value}', 'function_def_begin': '{function_name} <- function({input_var}) {{', 'return': 'return({output_var})', 'function_def_regex': (r'{function_name} *(?:(?:\<-)|(?:=)) *function' r'\((?P<inputs>(?:.|(?:\r?\n))*?)\)\s*\{{' r'(?P<body>(?:.|(?:\r?\n))*?)' r'(?:return\((list\()?' r'(?P<outputs>(?:.|(?:\r?\n))*?)(?(3)\))\)' r'(?:.|(?:\r?\n))*?\}})' r'|(?:\}})'), 'inputs_def_regex': r'\s*(?P<name>.+?)\s*(?:,|$)', 'outputs_def_regex': r'\s*(?P<name>.+?)\s*(?:,|$)', 'interface_regex': (r'(?P<indent>[ \t]*)' r'(?P<variable>[a-zA-Z\_]+[a-zA-Z\_0-9]*)\s*\<\-\s*' r'YggInterface\(\'(?P<class>[a-zA-Z\_]+[a-zA-Z\_0-9]*)\'\s*\,\s*' r'\'(?P<channel>[a-zA-Z\_]+[a-zA-Z\_0-9]*)\'\s*' r'(?P<args>[^\)]*)\)') } brackets = (r'{', r'}') zero_based = False @classmethod def is_library_installed(cls, lib, **kwargs): r"""Determine if a dependency is installed. Args: lib (str): Name of the library that should be checked. **kwargs: Additional keyword arguments are ignored. Returns: bool: True if the library is installed, False otherwise. """ if lib not in cls._library_cache: try: cls.run_executable(['-e', 'library(%s)' % lib.split()[0]]) cls._library_cache[lib] = True except RuntimeError: cls._library_cache[lib] = False return cls._library_cache[lib] @classmethod def language_version(cls, **kwargs): r"""Determine the version of this language. Args: **kwargs: Keyword arguments are passed to the parent class's method. Returns: str: Version of compiler/interpreter for this language. """ kwargs.setdefault('skip_interpreter_flags', True) return super(RModelDriver, cls).language_version(**kwargs) # @property # def debug_flags(self): # r"""list: Flags that should be prepended to an executable command to # enable debugging.""" # if self.with_valgrind: # interp = 'R'.join(self.get_interpreter().rsplit('Rscript', 1)) # return [interp, '-d', '"valgrind %s"' # % ' '.join(self.valgrind_flags), '--vanilla', '-f'] # return super(RModelDriver, self).debug_flags def set_env(self): r"""Get environment variables that should be set for the model process. Returns: dict: Environment variables for the model process. """ out = super(RModelDriver, self).set_env() out['RETICULATE_PYTHON'] = PythonModelDriver.get_interpreter() if CModelDriver.is_language_installed(): c_linker = CModelDriver.get_tool('linker') search_dirs = c_linker.get_search_path(env_only=True) out = CModelDriver.update_ld_library_path(out, paths_to_add=search_dirs, add_to_front=True) return out @classmethod def comm_atexit(cls, comm): # pragma: no cover r"""Operations performed on comm at exit including draining receive. Args: comm (CommBase): Communication object. """ if comm.direction == 'recv': while comm.recv(timeout=0)[0]: comm.sleep() else: comm.send_eof() if not getattr(comm, 'dont_backlog', True): comm.linger_close() @classmethod def python2language(cls, pyobj): r"""Prepare a python object for transformation in R. Args: pyobj (object): Python object. Returns: object: Python object in a form that is R friendly. """ logger.debug("python2language: %s, %s" % (pyobj, type(pyobj))) if isinstance(pyobj, tuple): return tuple([cls.python2language(x) for x in pyobj]) elif isinstance(pyobj, list): return [cls.python2language(x) for x in pyobj] elif isinstance(pyobj, OrderedDict): return OrderedDict([(cls.python2language(k), cls.python2language(v)) for k, v in pyobj.items()]) elif isinstance(pyobj, dict): return { cls.python2language(k): cls.python2language(v) for k, v in pyobj.items() } elif isinstance(pyobj, np.string_): return pyobj.decode("utf-8") elif isinstance(pyobj, pd.DataFrame): # R dosn't have int64 and will cast 64bit ints as floats if passed # without casting them to int32 first for n in pyobj.columns: if pyobj[n].dtype == np.dtype('int64'): pyobj[n] = pyobj[n].astype('int32') return pyobj @classmethod def write_model_wrapper(cls, model_file, model_function, **kwargs): r"""Return the lines required to wrap a model function as an integrated model. Args: model_file (str): Full path to the file containing the model function's declaration. model_function (str): Name of the model function. **kwargs: Additional keyword arguments are passed to the parent class's method. Returns: list: Lines of code wrapping the provided model with the necessary code to run it as part of an integration. """ if platform._is_win: # pragma: windows model_file = model_file.replace('\\', '/') return super(RModelDriver, cls).write_model_wrapper(model_file, model_function, **kwargs) @classmethod def write_executable_import(cls, **kwargs): r"""Add import statements to executable lines. Args: **kwargs: Keyword arguments for import statement. Returns: list: Lines required to complete the import. """ if kwargs.get('filename', None) and os.path.isfile(kwargs['filename']): with open(kwargs['filename'], 'r') as fd: contents = fd.read() # For functions that contain interface calls, split them out # and assign them to the global level if re.search(cls.function_param['interface_regex'], contents): new_contents = contents for m in re.finditer(cls.function_param['interface_regex'], contents): mdict = m.groupdict() assert ('global_scope' in mdict['args']) # if 'global_scope' not in mdict['args']: # mdict['args'] += ', global_scope=TRUE' new_channel = ( '{indent}if (!exists("{variable}")) {{\n' '{indent} assign("{variable}", YggInterface(' '\'{class}\', \'{channel}\'{args}), ' 'envir = .GlobalEnv)\n' '{indent}}}').format(**mdict) new_contents = new_contents.replace( m.group(0), new_channel) out = new_contents.splitlines() return out return super(RModelDriver, cls).write_executable_import(**kwargs)
class RModelDriver(InterpretedModelDriver): # pragma: R r"""Base class for running R models. Args: name (str): Driver name. args (str or list): Argument(s) for running the model in matlab. Generally, this should be the full path to a Matlab script. **kwargs: Additional keyword arguments are passed to parent class's __init__ method. """ _schema_subtype_description = ('Model is written in R.') language = 'R' language_aliases = ['r'] language_ext = '.R' base_languages = ['python'] default_interpreter = 'Rscript' # Dynamically setting the interface library causes circular a import so # it is defined here statically. For dynamic import, use the following: # interface_library = PythonModelDriver.interface_library interface_library = 'yggdrasil' interface_dependencies = [x.split()[0] for x in install.requirements_from_description()] # The Batch version causes output to saved to a file rather than directed to # stdout so use Rscript instead. For the batch version, use the following: # default_interpreter_flags = ['CMD', 'BATCH' '--vanilla', '--silent'] default_interpreter_flags = ['--default-packages=methods,utils'] send_converters = {'table': serialize.consolidate_array} type_map = { 'int': 'integer, bit64::integer64', 'float': 'double', 'string': 'character', 'array': 'list', 'object': 'list', 'boolean': 'logical', 'null': 'NA', 'uint': 'integer', 'complex': 'complex', 'bytes': 'char (utf-8)', 'unicode': 'char', '1darray': 'list', 'ndarray': 'list', 'ply': 'PlyDict', 'obj': 'ObjDict', 'schema': 'list'} function_param = { 'import': 'source(\"{filename}\")', 'istype': 'is({variable}, \"{type}\")', 'len': 'length({variable})', 'index': '{variable}[[{index}]]', 'first_index': 1, 'interface': 'library(yggdrasil)', 'input': '{channel} <- YggInterface(\"YggInput\", \"{channel_name}\")', 'output': '{channel} <- YggInterface(\"YggOutput\", \"{channel_name}\")', 'python_interface': ('{channel} <- YggInterface(\"{python_interface}\", ' '\"{channel_name}\")'), 'python_interface_format': ('{channel} <- YggInterface(' '\"{python_interface}\", ' '\"{channel_name}\", ' '\"{format_str}\")'), 'recv_function': '{channel}$recv', 'send_function': '{channel}$send', 'multiple_outputs': 'c({outputs})', 'multiple_outputs_def': 'list({outputs})', 'true': 'TRUE', 'false': 'FALSE', 'not': '!', 'and': '&&', 'comment': '#', 'indent': 2 * ' ', 'quote': '\"', 'print_generic': 'print({object})', 'print': 'print(\"{message}\")', 'fprintf': 'print(sprintf(\"{message}\", {variables}))', 'error': 'stop(\"{error_msg}\")', 'block_end': '}', 'if_begin': 'if ({cond}) {{', 'if_elif': '}} else if ({cond}) {{', 'if_else': '}} else {{', 'for_begin': 'for ({iter_var} in {iter_begin}:{iter_end}) {{', 'while_begin': 'while ({cond}) {{', 'try_begin': 'tryCatch({', 'try_except': '}}, error = function({error_var}) {{', 'try_end': '})', 'assign': '{name} <- {value}', 'assign_mult': '{name} %<-% {value}', 'function_def_begin': '{function_name} <- function({input_var}) {{', 'return': 'return({output_var})', 'function_def_regex': ( r'{function_name} *(?:(?:\<-)|(?:=)) *function' r'\((?P<inputs>(?:.|(?:\r?\n))*?)\)\s*\{{' r'(?P<body>(?:.|(?:\r?\n))*?)' r'(?:return\((list\()?' r'(?P<outputs>(?:.|(?:\r?\n))*?)(?(3)\))\)' r'(?:.|(?:\r?\n))*?\}})' r'|(?:\}})'), 'inputs_def_regex': r'\s*(?P<name>.+?)\s*(?:,|$)', 'outputs_def_regex': r'\s*(?P<name>.+?)\s*(?:,|$)', 'interface_regex': ( r'(?P<indent>[ \t]*)' r'(?P<variable>[a-zA-Z\_]+[a-zA-Z\_0-9]*)\s*\<\-\s*' r'YggInterface\(\'(?P<class>[a-zA-Z\_]+[a-zA-Z\_0-9]*)\'\s*\,\s*' r'\'(?P<channel>[a-zA-Z\_]+[a-zA-Z\_0-9]*)\'\s*' r'(?P<args>[^\)]*)\)')} brackets = (r'{', r'}') zero_based = False @classmethod def is_library_installed(cls, lib, **kwargs): r"""Determine if a dependency is installed. Args: lib (str): Name of the library that should be checked. **kwargs: Additional keyword arguments are ignored. Returns: bool: True if the library is installed, False otherwise. """ if lib not in cls._library_cache: try: cls.run_executable(['-e', 'library(%s)' % lib.split()[0]]) cls._library_cache[lib] = True except RuntimeError as e: logger.info('Error checking for R library %s: %s' % (lib, e)) cls._library_cache[lib] = False return cls._library_cache[lib] @classmethod def language_version(cls, **kwargs): r"""Determine the version of this language. Args: **kwargs: Keyword arguments are passed to the parent class's method. Returns: str: Version of compiler/interpreter for this language. """ kwargs.setdefault('skip_interpreter_flags', True) return super(RModelDriver, cls).language_version(**kwargs) def run_model(self, *args, **kwargs): r"""Run the model. Unless overridden, the model will be run using run_executable. Args: *args: Arguments are passed to the parent class's method. **kwargs: Keyword arguments are passed to the parent class's method. """ if self.with_valgrind: interp = kwargs.pop('interpreter', self.get_interpreter()) interp_flags = kwargs.pop('interpreter_flags', []) if 'Rscript' in interp: interp = 'R'.join(interp.rsplit('Rscript', 1)) interp_flags = [] kwargs['skip_interpreter_flags'] = True interp_flags += [ '--vanilla', '-d', 'valgrind %s' % ' '.join(self.valgrind_flags), '-f'] kwargs['interpreter'] = interp kwargs['interpreter_flags'] = interp_flags kwargs['debug_flags'] = [] return super(RModelDriver, self).run_model(*args, **kwargs) def set_env(self, **kwargs): r"""Get environment variables that should be set for the model process. Returns: dict: Environment variables for the model process. """ out = super(RModelDriver, self).set_env(**kwargs) out['RETICULATE_PYTHON'] = PythonModelDriver.get_interpreter() if CModelDriver.is_language_installed(): c_linker = CModelDriver.get_tool('linker') search_dirs = c_linker.get_search_path(env_only=True) out = CModelDriver.update_ld_library_path(out, paths_to_add=search_dirs, add_to_front=True) return out @classmethod def comm_atexit(cls, comm): # pragma: no cover r"""Operations performed on comm at exit including draining receive. Args: comm (CommBase): Communication object. """ if comm.direction == 'recv': while comm.recv(timeout=0)[0]: comm.sleep() else: comm.send_eof() comm.linger() if not getattr(comm, 'dont_backlog', True): comm.linger_close() @classmethod def python2language(cls, pyobj): r"""Prepare a python object for transformation in R. Args: pyobj (object): Python object. Returns: object: Python object in a form that is R friendly. """ logger.debug("python2language: %s, %s" % (pyobj, type(pyobj))) if isinstance(pyobj, tuple): return tuple([cls.python2language(x) for x in pyobj]) elif isinstance(pyobj, list): return [cls.python2language(x) for x in pyobj] elif isinstance(pyobj, OrderedDict): return OrderedDict([(cls.python2language(k), cls.python2language(v)) for k, v in pyobj.items()]) elif isinstance(pyobj, dict): return {cls.python2language(k): cls.python2language(v) for k, v in pyobj.items()} elif isinstance(pyobj, np.string_): return pyobj.decode("utf-8") elif isinstance(pyobj, pd.DataFrame): # R dosn't have int64 and will cast 64bit ints as floats if passed # without casting them to int32 first for n in pyobj.columns: if pyobj[n].dtype == np.dtype('int64'): pyobj[n] = pyobj[n].astype('int32') return pyobj @classmethod def write_model_wrapper(cls, model_file, model_function, **kwargs): r"""Return the lines required to wrap a model function as an integrated model. Args: model_file (str): Full path to the file containing the model function's declaration. model_function (str): Name of the model function. **kwargs: Additional keyword arguments are passed to the parent class's method. Returns: list: Lines of code wrapping the provided model with the necessary code to run it as part of an integration. """ if platform._is_win: # pragma: windows model_file = model_file.replace('\\', '/') return super(RModelDriver, cls).write_model_wrapper( model_file, model_function, **kwargs) @classmethod def write_executable_import(cls, **kwargs): r"""Add import statements to executable lines. Args: **kwargs: Keyword arguments for import statement. Returns: list: Lines required to complete the import. """ if kwargs.get('filename', None) and os.path.isfile(kwargs['filename']): with open(kwargs['filename'], 'r') as fd: contents = fd.read() # For functions that contain interface calls, split them out # and assign them to the global level if re.search(cls.function_param['interface_regex'], contents): new_contents = contents for m in re.finditer(cls.function_param['interface_regex'], contents): mdict = m.groupdict() assert('global_scope' in mdict['args']) # if 'global_scope' not in mdict['args']: # mdict['args'] += ', global_scope=TRUE' new_channel = ( '{indent}if (!exists("{variable}")) {{\n' '{indent} assign("{variable}", YggInterface(' '\'{class}\', \'{channel}\'{args}), ' 'envir = .GlobalEnv)\n' '{indent}}}').format(**mdict) new_contents = new_contents.replace(m.group(0), new_channel) out = new_contents.splitlines() return out return super(RModelDriver, cls).write_executable_import(**kwargs) # The following is only provided for the yggcc CLI for building R # packages and should not be used directly @classmethod def call_compile(cls, package_dir, toolname=None, flags=None, language='c++', verbose=False): # pragma: no cover r"""Build an R package w/ the yggdrasil compilers. Args: package_dir (str): Full path to the package directory. toolname (str, optional): Compilation tool that should be used. Defaults to None and the default tools will be used. flags (list, optional): Additional flags that should be passed to the build command. Defaults to []. language (str, optional): Language that the package is written in (e.g. c, fortran). Defautls to 'c++'. verbose (bool, optional): If True, information about the build process will be displayed. Defaults to False. """ import shutil import subprocess from yggdrasil.components import import_component if flags is None: flags = [] if isinstance(package_dir, list): assert(len(package_dir) == 1) package_dir = package_dir[0] cexec_vars = {'c': ['CC', 'CC_FOR_BUILD'], 'c++': ['CXX', 'CPP', 'CXX98', 'CXX11', 'CXX14', 'CXX17', 'CXX_FOR_BUILD'], 'fortran': ['FC', 'F77']} cflag_vars = {'c': ['CFLAGS'], 'c++': ['CXXFLAGS', 'CXX98FLAGS', 'CXX11FLAGS', 'CXX14FLAGS', 'CXX17FLAGS'], 'fortran': ['FFFLAGS', 'FCFLAGS']} env = os.environ.copy() new_env = {} for x in constants.LANGUAGES['compiled']: # for x in [language]: drv = import_component('model', x) compiler = drv.get_tool('compiler', toolname=toolname) # archiver = compiler.archiver() env = drv.set_env_compiler(existing=env, compiler=compiler) cexec = compiler.get_executable(full_path=True) kws = {} if x == 'c++': kws['skip_standard_flag'] = True cflags = drv.get_compiler_flags(for_model=True, toolname=toolname, dry_run=True, compiler=compiler, dont_link=True, **kws) lflags = drv.get_linker_flags(for_model=True, toolname=toolname, dry_run=True, libtype='shared') # Remove flags that are unnecessary cflags = [x for x in cflags if not x.startswith("-std=")] for k in ['-c']: if k in cflags: cflags.remove(k) for k in ['-shared']: if k in lflags: lflags.remove(k) for k in cexec_vars[x]: env[k] = cexec new_env[k] = cexec for k in cflag_vars[x]: env[k] = '' new_env[k] = ' '.join(cflags) if language == x: env['LDFLAGS'] = '' new_env['LDFLAGS'] = ' '.join(lflags) cmd = ['R', 'CMD', 'INSTALL', '--no-html', '--no-help', '--no-docs', '--no-demo', '--no-multiarch', package_dir] + flags makevar = os.path.expanduser(os.path.join('~', '.R', 'Makevars')) makevar_copy = makevar + '_copy' try: if os.path.isfile(makevar): shutil.move(makevar, makevar_copy) with open(makevar, 'w') as fd: for k, v in new_env.items(): if k.startswith('PKG_'): fd.write('%s+=%s\n' % (k, v)) else: fd.write('%s=%s\n' % (k, v)) if verbose: with open(makevar, 'r') as fd: print(fd.read()) subprocess.check_call(cmd, env=env) finally: os.remove(makevar) if os.path.isfile(makevar_copy): shutil.move(makevar_copy, makevar)