Ejemplo n.º 1
0
        def get_or_set_cache():
            hasher = hashlib.new("md5")

            args_hasher = CodeHasher("md5", hasher, hash_funcs)
            args_hasher.update([args, kwargs])
            LOGGER.debug("Hashing arguments to %s of %i bytes.", name, args_hasher.size)

            code_hasher = CodeHasher("md5", hasher, hash_funcs)
            code_hasher.update(func)
            LOGGER.debug("Hashing function %s in %i bytes.", name, code_hasher.size)

            key = hasher.hexdigest()
            LOGGER.debug("Cache key: %s", key)

            caller_frame = inspect.currentframe().f_back
            try:
                return_value = _read_from_cache(
                    key, persist, allow_output_mutation, func, caller_frame, hash_funcs
                )
                LOGGER.debug("Cache hit: %s", func)
            except CacheKeyNotFoundError:
                LOGGER.debug("Cache miss: %s", func)

                with _calling_cached_function():
                    if suppress_st_warning:
                        with suppress_cached_st_function_warning():
                            return_value = func(*args, **kwargs)
                    else:
                        return_value = func(*args, **kwargs)

                _write_to_cache(
                    key=key,
                    value=return_value,
                    persist=persist,
                    allow_output_mutation=allow_output_mutation,
                    hash_funcs=hash_funcs,
                )

            return return_value
Ejemplo n.º 2
0
def get_hash(f, context=None):
    hasher = CodeHasher("md5")
    hasher._get_main_script_directory = MagicMock()
    hasher._get_main_script_directory.return_value = os.getcwd()
    hasher.update(f, context)
    return hasher.digest()
Ejemplo n.º 3
0
    def has_changes(self):
        current_frame = inspect.currentframe()
        caller_frame = current_frame.f_back

        current_file = inspect.getfile(current_frame)
        caller_file = inspect.getfile(caller_frame)
        real_caller_is_parent_frame = current_file == caller_file
        if real_caller_is_parent_frame:
            caller_frame = caller_frame.f_back

        frameinfo = inspect.getframeinfo(caller_frame)
        filename, caller_lineno, _, code_context, _ = frameinfo

        code_context = code_context[0]

        context_indent = len(code_context) - len(code_context.lstrip())

        lines = []
        # TODO: Memoize open(filename, 'r') in a way that clears the memoized
        # version with each run of the user's script. Then use the memoized
        # text here, in st.echo, and other places.
        with open(filename, "r") as f:
            for line in f.readlines()[caller_lineno:]:
                if line.strip() == "":
                    lines.append(line)
                indent = len(line) - len(line.lstrip())
                if indent <= context_indent:
                    break
                if line.strip() and not line.lstrip().startswith("#"):
                    lines.append(line)

        while lines[-1].strip() == "":
            lines.pop()

        code_block = "".join(lines)
        program = textwrap.dedent(code_block)

        context = Context(dict(caller_frame.f_globals, **caller_frame.f_locals), {}, {})
        code = compile(program, filename, "exec")

        code_hasher = CodeHasher("md5")
        code_hasher.update(code, context)
        LOGGER.debug("Hashing block in %i bytes.", code_hasher.size)

        key = code_hasher.hexdigest()
        LOGGER.debug("Cache key: %s", key)

        try:
            value, _ = _read_from_cache(
                key,
                self._persist,
                self._allow_output_mutation,
                code,
                [caller_lineno + 1, caller_lineno + len(lines)],
            )
            self.update(value)
        except CacheKeyNotFoundError:
            if self._allow_output_mutation and not self._persist:
                # If we don't hash the results, we don't need to use exec and just return True.
                # This way line numbers will be correct.
                _write_to_cache(
                    key=key, value=self, persist=False, allow_output_mutation=True
                )
                return True

            exec(code, caller_frame.f_globals, caller_frame.f_locals)
            _write_to_cache(
                key=key,
                value=self,
                persist=self._persist,
                allow_output_mutation=self._allow_output_mutation,
            )

        # Return False so that we have control over the execution.
        return False
Ejemplo n.º 4
0
        def get_or_set_cache():
            hasher = hashlib.new("md5")

            args_hasher = CodeHasher("md5", hasher)
            args_hasher.update([args, kwargs])
            LOGGER.debug("Hashing arguments to %s of %i bytes.", name,
                         args_hasher.size)

            args_digest_before = args_hasher.digest()

            code_hasher = CodeHasher("md5", hasher)
            code_hasher.update(func)
            LOGGER.debug("Hashing function %s in %i bytes.", name,
                         code_hasher.size)

            key = hasher.hexdigest()
            LOGGER.debug("Cache key: %s", key)

            caller_frame = inspect.currentframe().f_back
            try:
                return_value, args_mutated = _read_from_cache(
                    key, persist, allow_output_mutation, func, caller_frame)
            except (CacheKeyNotFoundError, CachedObjectWasMutatedError):
                with _calling_cached_function():
                    if suppress_st_warning:
                        with suppress_cached_st_function_warning():
                            return_value = func(*args, **kwargs)
                    else:
                        return_value = func(*args, **kwargs)

                args_hasher_after = CodeHasher("md5")
                args_hasher_after.update([args, kwargs])
                args_mutated = args_digest_before != args_hasher_after.digest()

                _write_to_cache(key, return_value, persist,
                                allow_output_mutation, args_mutated)

            if args_mutated:
                # If we're inside a _nested_ cached function, our
                # _within_cached_function_counter will be non-zero.
                # Suppress the warning about this.
                with suppress_cached_st_function_warning():
                    st.warning(_build_args_mutated_message(func))
            return return_value
Ejemplo n.º 5
0
        def function():
            hasher = hashlib.new("md5")

            args_hasher = CodeHasher("md5", hasher)
            args_hasher.update([argc, argv])
            LOGGER.debug("Hashing arguments to %s of %i bytes.", name,
                         args_hasher.size)

            args_digest_before = args_hasher.digest()

            code_hasher = CodeHasher("md5", hasher)
            code_hasher.update(func)
            LOGGER.debug("Hashing function %s in %i bytes.", name,
                         code_hasher.size)

            key = hasher.hexdigest()
            LOGGER.debug("Cache key: %s", key)

            caller_frame = inspect.currentframe().f_back
            try:
                return_value, args_mutated = _read_from_cache(
                    key, persist, ignore_hash, func, caller_frame)
            except (CacheKeyNotFoundError, CachedObjectWasMutatedError):
                return_value = func(*argc, **argv)

                args_hasher_after = CodeHasher("md5")
                args_hasher_after.update([argc, argv])
                args_mutated = args_digest_before != args_hasher_after.digest()

                _write_to_cache(key, return_value, persist, ignore_hash,
                                args_mutated)

            if args_mutated:
                st.warning(_build_args_mutated_message(func))
            return return_value
Ejemplo n.º 6
0
def _get_key(obj: Any) -> str:
    hasher = CodeHasher()
    hasher.update(obj)
    return hasher.hexdigest()
Ejemplo n.º 7
0
    def wrapped_func(*argc, **argv):
        """This function wrapper will only call the underlying function in
        the case of a cache miss. Cached objects are stored in the cache/
        directory."""
        if not config.get_option('client.caching'):
            LOGGER.debug('Purposefully skipping cache')
            return func(*argc, **argv)

        name = func.__name__

        if len(argc) == 0 and len(argv) == 0:
            message = 'Running %s().' % name
        else:
            message = 'Running %s(...).' % name
        with st.spinner(message):
            hasher = hashlib.new('md5')

            args_hasher = CodeHasher('md5', hasher)
            args_hasher.update([argc, argv])
            LOGGER.debug('Hashing arguments to %s of %i bytes.',
                         name, args_hasher.size)

            args_digest_before = args_hasher.digest()

            code_hasher = CodeHasher('md5', hasher)
            code_hasher.update(func)
            LOGGER.debug('Hashing function %s in %i bytes.',
                         name, code_hasher.size)

            key = hasher.hexdigest()
            LOGGER.debug('Cache key: %s', key)

            caller_frame = inspect.currentframe().f_back
            try:
                return_value, args_mutated = _read_from_cache(
                    key, persist, ignore_hash, func, caller_frame)
            except (CacheKeyNotFoundError, CachedObjectWasMutatedError):
                return_value = func(*argc, **argv)

                args_hasher_after = CodeHasher('md5')
                args_hasher_after.update([argc, argv])
                args_mutated = args_digest_before != args_hasher_after.digest()

                _write_to_cache(
                    key, return_value, persist, ignore_hash, args_mutated)

            if args_mutated:
                st.warning(_build_args_mutated_message(func))

        return return_value