Skip to content

Commit

Permalink
Improve caching code (#2)
Browse files Browse the repository at this point in the history
  • Loading branch information
domoritz committed Aug 24, 2019
1 parent d0dfca6 commit f5332a1
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 13 deletions.
19 changes: 9 additions & 10 deletions lib/streamlit/caching.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@
"""A library of caching utilities."""

# Python 2/3 compatibility
from __future__ import (absolute_import, division, print_function,
unicode_literals)
from __future__ import (absolute_import, division, print_function)

import ast
import hashlib
Expand Down Expand Up @@ -116,7 +115,7 @@ def _build_caching_func_error_message(persisted, func, caller_frame):

try:
# only works if calling code is a single line
parsed_context = ast.parse(lines[0])
parsed_context = ast.parse(lines[0].lstrip())
parsed_context = _AddCopy(name).visit(parsed_context)
copy_code = astor.to_source(parsed_context)
except SyntaxError:
Expand All @@ -129,16 +128,16 @@ def _build_caching_func_error_message(persisted, func, caller_frame):
load_or_rerun = 'rerunning the function'

message = (
'**You code mutated a cached return value**\n\n'
'**Your code mutated a cached return value**\n\n'

'Streamlit detected the mutation of a return value of `{func_name}`, which is '
'Streamlit detected the mutation of a return value of `{name}`, which is '
'a cached function. This happened in `{file_name}` line {lineno}. Since '
'`persist` is `{persisted}`, Streamlit will make up for this by '
'{load_or_rerun}, so your code will still work, but with reduced performance.\n\n'

'To dismiss this warning, try one of the following:\n'
'To dismiss this warning, try one of the following:\n\n'

'1. Preferred: fix the code by removing the mutation. The simplest way to do '
'1. *Preferred:* fix the code by removing the mutation. The simplest way to do '
'this is to copy the cached value to a new variable, which you are allowed to '
'mutate. For example, try changing `{caller_file_name}` line {caller_lineno} to:\n'

Expand Down Expand Up @@ -171,9 +170,9 @@ def _build_caching_block_error_message(persisted, code, line_number_range):

[start, end] = line_number_range
if start == end:
lines = 'line {start}'.format(start)
lines = 'line {start}'.format(start=start)
else:
lines = 'lines {start} to {end}'.format(start=str(start), end=str(end))
lines = 'lines {start} to {end}'.format(start=start, end=end)

message = (
'**Your code mutated a cached value**\n\n'
Expand All @@ -184,7 +183,7 @@ def _build_caching_block_error_message(persisted, code, line_number_range):

'To dismiss this warning, try one of the following:\n\n'

'1. Preferred: fix the code by removing the mutation. The simplest way to do '
'1. *Preferred:* fix the code by removing the mutation. The simplest way to do '
'this is to copy the cached value to a new variable, which you are allowed to mutate.\n'

'2. Add `ignore_hash=True` to the constructor of `streamlit.Cache`. This is an '
Expand Down
4 changes: 2 additions & 2 deletions lib/streamlit/hashing.py
Original file line number Diff line number Diff line change
Expand Up @@ -267,12 +267,12 @@ def _to_bytes(self, obj, context):
elif inspect.ismodule(obj):
# TODO: Hash more than just the name for internal modules.
st.warning(('Streamlit does not support hashing modules. '
'We did not hash %s.') % obj.__name__)
'We did not hash `%s`.') % obj.__name__)
return self.to_bytes(obj.__name__)
elif inspect.isclass(obj):
# TODO: Hash more than just the name of classes.
st.warning(('Streamlit does not support hashing classes. '
'We did not hash %s.') % obj.__name__)
'We did not hash `%s`.') % obj.__name__)
return self.to_bytes(obj.__name__)
elif isinstance(obj, functools.partial):
# The return value of functools.partial is not a plain function:
Expand Down
20 changes: 19 additions & 1 deletion lib/tests/streamlit/caching_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@

"""st.caching unit tests."""

import inspect
import unittest

from mock import patch

import streamlit as st
Expand Down Expand Up @@ -56,7 +58,23 @@ def f(x):
warning.assert_not_called()

@patch.object(st, 'warning')
def test_modify_args(self, warning):
def test_mutate_return(self, warning):
@st.cache
def f():
return [0, 1]

r = f()

r[0] = 1

warning.assert_not_called()

f()

warning.assert_called()

@patch.object(st, 'warning')
def test_mutate_args(self, warning):
@st.cache
def f(x):
x[0] = 2
Expand Down

0 comments on commit f5332a1

Please sign in to comment.