Esempio n. 1
0
    def execute(self, code):
        """Run code
        """
        _, path_to_tmp = tempfile.mkstemp()
        Path(path_to_tmp).write_text(code)

        run_template = Placeholder(self.run_template)
        source = run_template.render(dict(path_to_code=path_to_tmp))

        res = subprocess.run(shlex.split(source), **self.subprocess_run_kwargs)
        stdout = res.stdout.decode('utf-8')
        stderr = res.stderr.decode('utf-8')

        if res.returncode != 0:
            # log source code without expanded params
            self._logger.info(
                ('{} returned stdout: '
                 '{}\nstderr: {}\n'
                 'exit status {}').format(code, stdout, stderr,
                                          res.returncode))
            raise RuntimeError(
                ('Error executing code.\nReturned stdout: '
                 '{}\nstderr: {}\n'
                 'exit status {}').format(stdout, stderr, res.returncode))
        else:
            self._logger.info(('Finished running {}. stdout: {},'
                               ' stderr: {}').format(self, stdout, stderr))
Esempio n. 2
0
class Source(abc.ABC):

    def __init__(self, value):
        self.value = Placeholder(value)
        self._post_init_validation(self.value)

    @property
    def needs_render(self):
        return self.value.needs_render

    def render(self, params):
        self.value.render(params)
        self._post_render_validation(self.value.value, params)

    def __str__(self):
        return str(self.value)

    # required by subclasses
    @property
    @abc.abstractmethod
    def doc(self):
        pass

    @property
    @abc.abstractmethod
    def doc_short(self):
        pass

    @property
    @abc.abstractmethod
    def language(self):
        pass

    @property
    @abc.abstractmethod
    def loc(self):
        pass

    # optional validation

    def _post_render_validation(self, rendered_value, params):
        pass

    def _post_init_validation(self, value):
        pass
Esempio n. 3
0
    def execute(self, code):
        """Run code
        """
        ftp = self.connection.open_sftp()
        path_remote = self.path_to_directory + self._random_name()

        _, path_to_tmp = tempfile.mkstemp()
        Path(path_to_tmp).write_text(code)

        ftp.put(path_to_tmp, path_remote)
        ftp.close()

        run_template = Placeholder(self.run_template)
        source = run_template.render(dict(path_to_code=path_remote))

        # stream stdout. related: https://stackoverflow.com/q/31834743
        # using pty is not ideal, fabric has a clean implementation for this
        # worth checking out
        stdin, stdout, stderr = self.connection.exec_command(source,
                                                             get_pty=True)

        for line in iter(stdout.readline, ""):
            self._logger.info('(STDOUT): {}'.format(line))

        returncode = stdout.channel.recv_exit_status()

        stdout = ''.join(stdout)
        stderr = ''.join(stderr)

        if returncode != 0:
            # log source code without expanded params
            self._logger.info(f'{code} returned stdout: '
                              f'{stdout} and stderr: {stderr} '
                              f'and exit status {returncode}')
            raise CalledProcessError(returncode, code)
        else:
            self._logger.info(f'Finished running {self}. stdout: {stdout},'
                              f' stderr: {stderr}')

        return {'returncode': returncode, 'stdout': stdout, 'stderr': stderr}
Esempio n. 4
0
def test_strict_templates_initialized_from_jinja_template(path_to_assets):
    path = str(path_to_assets / 'templates')
    env = Environment(loader=FileSystemLoader(path), undefined=StrictUndefined)
    st = Placeholder(env.get_template('template.sql'))
    assert st.render({'file': 1})
Esempio n. 5
0
def test_init_placeholder_with_placeholder():
    t = Placeholder('{{file}}')
    tt = Placeholder(t)

    assert tt.render({'file': 'some file'})
Esempio n. 6
0
class GenericProduct(Product):
    def __init__(self,
                 identifier,
                 path_to_metadata,
                 exists_command,
                 delete_command,
                 client=None):

        self._identifier = Placeholder(str(identifier))
        self._path_to_metadata = path_to_metadata
        self._client = client

        self.exists_command = Placeholder(str(exists_command))
        self.delete_command = Placeholder(str(delete_command))

        self.did_download_metadata = False
        self.task = None
        self._logger = logging.getLogger(__name__)

    def _init_identifier(self, identifier):
        pass

    # TODO: create a mixing with this so all client-based tasks can include it
    @property
    def client(self):
        if self._client is None:
            default = self.task.dag.clients.get(type(self))

            if default is None:
                raise ValueError('{} must be initialized with a client'.format(
                    type(self).__name__))
            else:
                self._client = default

        return self._client

    def render(self, params, **kwargs):
        # overriding parent implementation since this product also needs
        # render for other variables
        self._identifier.render(params, **kwargs)
        self.exists_command.render(params, **kwargs)
        self.delete_command.render(params, **kwargs)

    @property
    def _path_to_metadata_file(self):
        return self._path_to_metadata + str(self._identifier) + '.json'

    def fetch_metadata(self):
        try:
            meta = self.client.read_file(self._path_to_metadata_file)
        except Exception as e:
            self._logger.exception(e)
            return {}
        else:
            return json.loads(meta)

    def save_metadata(self):
        metadata_str = json.dumps(self.metadata)
        self.client.write_to_file(metadata_str, self._path_to_metadata_file)

    # TODO: implement
    def exists(self):
        return True

    def delete(self, force=False):
        pass

    @property
    def name(self):
        return Path(str(self._path_to_metadata)).with_suffix('').name