Skip to content

Commit

Permalink
heuristic to refresh symbols that were updated but skipped when traci…
Browse files Browse the repository at this point in the history
…ng disabled
  • Loading branch information
smacke committed Dec 2, 2023
1 parent 589b781 commit 7b9d565
Show file tree
Hide file tree
Showing 10 changed files with 86 additions and 55 deletions.
13 changes: 9 additions & 4 deletions core/ipyflow/analysis/symbol_ref.py
Original file line number Diff line number Diff line change
Expand Up @@ -330,15 +330,17 @@ def __init__(self, symbols: Union[ast.AST, Atom, Sequence[Atom]]) -> None:
def from_string(cls, symbol_str: str) -> "SymbolRef":
return cls(ast.parse(symbol_str, mode="eval").body)

@classmethod
def resolve(cls, symbol_str: str) -> Optional["Symbol"]:
ref = cls.from_string(symbol_str)
for resolved in ref.gen_resolved_symbols(
def to_symbol(self) -> Optional["Symbol"]:
for resolved in self.gen_resolved_symbols(
flow().global_scope, only_yield_final_symbol=True, yield_in_reverse=False
):
return resolved.dsym
return None

@classmethod
def resolve(cls, symbol_str: str) -> Optional["Symbol"]:
return cls.from_string(symbol_str).to_symbol()

def __hash__(self) -> int:
return hash(self.chain)

Expand Down Expand Up @@ -425,6 +427,9 @@ def from_string(cls, symbol_str: str, **kwargs) -> "LiveSymbolRef":
def resolve(symbol_str: str) -> Optional["Symbol"]:
return SymbolRef.resolve(symbol_str)

def to_symbol(self) -> Optional["Symbol"]:
return self.ref.to_symbol()

def __hash__(self) -> int:
return hash((self.ref, self.timestamp, self.is_lhs_ref))

Expand Down
4 changes: 4 additions & 0 deletions core/ipyflow/data_model/cell.py
Original file line number Diff line number Diff line change
Expand Up @@ -552,6 +552,10 @@ def is_current(self) -> bool:
def current_cell(cls) -> "Cell":
return cls._override_current_cell or cls._cell_by_cell_ctr[cls._cell_counter]

@classmethod
def current(cls) -> "Cell":
return cls.current_cell()

def get_max_used_live_symbol_cell_counter(
self,
live_symbols: Set[ResolvedSymbol],
Expand Down
2 changes: 1 addition & 1 deletion core/ipyflow/data_model/scope.py
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ def _resolve_symbol_type(
else:
return SymbolType.DEFAULT

def upsert_data_symbol_for_name(
def upsert_symbol_for_name(
self,
name: SupportedIndexType,
obj: Any,
Expand Down
26 changes: 17 additions & 9 deletions core/ipyflow/data_model/statement.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@
from types import FrameType
from typing import TYPE_CHECKING, Dict, List, Optional, Set, Type, Union, cast

from IPython import get_ipython

from ipyflow.analysis.live_refs import stmt_contains_cascading_reactive_rval
from ipyflow.analysis.live_refs import (
compute_live_dead_symbol_refs,
stmt_contains_cascading_reactive_rval,
)
from ipyflow.analysis.symbol_edges import get_symbol_edges
from ipyflow.analysis.symbol_ref import SymbolRef
from ipyflow.analysis.utils import stmt_contains_lval
Expand All @@ -18,7 +19,7 @@
from ipyflow.data_model.symbol import Symbol
from ipyflow.data_model.timestamp import Timestamp
from ipyflow.models import _StatementContainer, cells, statements
from ipyflow.singletons import flow, tracer
from ipyflow.singletons import flow, shell, tracer
from ipyflow.slicing.context import SlicingContext, static_slicing_context
from ipyflow.slicing.mixin import FormatType, Slice, SliceableMixin
from ipyflow.tracing.symbol_resolver import resolve_rval_symbols
Expand Down Expand Up @@ -70,6 +71,10 @@ def __init__(
self.static_parents: Dict[IdType, Set[Symbol]] = {}
self.static_children: Dict[IdType, Set[Symbol]] = {}

@classmethod
def current(cls) -> "Statement":
return cls.at_timestamp(Timestamp.current())

@property
def id(self) -> IdType:
return self.stmt_id
Expand Down Expand Up @@ -142,6 +147,9 @@ def create_and_track(
flow().stmt_deferred_static_parents.pop(stmt.timestamp, None)
return stmt

def is_module_stmt(self) -> bool:
return tracer().parent_stmt_by_id.get(self.stmt_id) is None

@classmethod
def clear(cls):
cls._stmts_by_ts = {}
Expand Down Expand Up @@ -351,7 +359,7 @@ def _handle_assign_target_for_deps(
subscript_vals_to_use.append(not is_subscript)
break
for subscript_val in subscript_vals_to_use:
upserted = scope.upsert_data_symbol_for_name(
upserted = scope.upsert_symbol_for_name(
name,
obj,
deps - excluded_deps,
Expand Down Expand Up @@ -399,15 +407,15 @@ def _handle_starred_store_target(
ns = Namespace(obj, str(name), parent_scope=scope)
for i, inner_dep in enumerate(inner_deps):
deps = set() if inner_dep is None else {inner_dep}
ns.upsert_data_symbol_for_name(
ns.upsert_symbol_for_name(
i,
inner_dep.obj,
deps,
self.stmt_node,
is_subscript=True,
is_cascading_reactive=self.stmt_contains_cascading_reactive_rval,
)
scope.upsert_data_symbol_for_name(
scope.upsert_symbol_for_name(
name,
obj,
set(),
Expand Down Expand Up @@ -536,7 +544,7 @@ def _make_lval_data_symbols_old(self) -> None:
module = sys.modules.get(
f"{self.stmt_node.module}.{dep_node_as_alias.name}"
) or sys.modules.get(self.stmt_node.module)
if self.frame.f_locals is get_ipython().user_ns:
if self.frame.f_locals is shell().user_ns:
for alias in self.stmt_node.names:
if alias.name == "*":
flow().starred_import_modules.add(module.__name__)
Expand Down Expand Up @@ -569,7 +577,7 @@ def _make_lval_data_symbols_old(self) -> None:
is_subscript,
excluded_deps,
) = tracer().resolve_store_data_for_target(target, self.frame)
scope.upsert_data_symbol_for_name(
scope.upsert_symbol_for_name(
name,
obj,
rval_deps - excluded_deps,
Expand Down
12 changes: 5 additions & 7 deletions core/ipyflow/data_model/symbol.py
Original file line number Diff line number Diff line change
Expand Up @@ -771,7 +771,7 @@ def create_symbols_for_call_args(self, call_frame: FrameType) -> None:
logger.info("create symbols for call to %s", self)
for def_arg, deps in self._match_call_args_with_definition_args():
seen_def_args.add(def_arg.arg)
sym = self.call_scope.upsert_data_symbol_for_name(
sym = self.call_scope.upsert_symbol_for_name(
def_arg.arg,
call_frame.f_locals.get(def_arg.arg),
deps,
Expand All @@ -783,7 +783,7 @@ def create_symbols_for_call_args(self, call_frame: FrameType) -> None:
for def_arg in self.get_definition_args():
if def_arg.arg in seen_def_args:
continue
self.call_scope.upsert_data_symbol_for_name(
self.call_scope.upsert_symbol_for_name(
def_arg.arg,
None,
set(),
Expand Down Expand Up @@ -989,9 +989,7 @@ def _handle_possible_widget_creation(self) -> None:
or not hasattr(self.obj, "value")
):
return
self.namespaced().upsert_data_symbol_for_name(
"value", None, set(), self.stmt_node
)
self.namespaced().upsert_symbol_for_name("value", None, set(), self.stmt_node)
self.obj.observe(self._observe_widget)
self._num_widget_observers += 1

Expand Down Expand Up @@ -1126,8 +1124,8 @@ def update_usage_info(
if ns is None or self in seen:
return self
seen.add(self)
for dsym in ns.all_symbols_this_indentation():
dsym.update_usage_info(
for sym in ns.all_symbols_this_indentation():
sym.update_usage_info(
used_time=used_time,
used_node=None,
exclude_ns=False,
Expand Down
26 changes: 13 additions & 13 deletions core/ipyflow/flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -233,10 +233,10 @@ def init_virtual_symbols(self) -> None:
if self._virtual_symbols_inited:
return
self.fs = Namespace(Namespace.FILE_SYSTEM, "fs")
self.display_sym = self.virtual_symbols.upsert_data_symbol_for_name(
self.display_sym = self.virtual_symbols.upsert_symbol_for_name(
"display", Symbol.DISPLAY, propagate=False, implicit=True
)
self.fake_edge_sym = self.virtual_symbols.upsert_data_symbol_for_name(
self.fake_edge_sym = self.virtual_symbols.upsert_symbol_for_name(
"fake_edge_sym", object(), propagate=False, implicit=True
)
self._virtual_symbols_inited = True
Expand Down Expand Up @@ -789,7 +789,7 @@ def handle_upsert_symbol(self, request) -> Optional[Dict[str, Any]]:
if prev_sym is not None and prev_sym.obj is obj:
return {"success": False}
with Timestamp.offset(stmt_offset=-1):
self.global_scope.upsert_data_symbol_for_name(
self.global_scope.upsert_symbol_for_name(
symbol_name, obj, dep_symbols, ast.parse("pass").body[0]
)
return None
Expand Down Expand Up @@ -893,20 +893,20 @@ def _add_parents_for_override_live_refs(self) -> None:
)

def _resync_symbols(self, symbols: Iterable[Symbol]):
for dsym in symbols:
if not dsym.containing_scope.is_global:
for sym in symbols:
if not sym.containing_scope.is_global:
continue
try:
obj = shell().user_global_ns.get(dsym.name, None)
obj = shell().user_ns.get(sym.name)
if obj is None:
continue
except: # noqa
# cinder runtime can throw an exception here due to lazy imports that fail
continue
if dsym.obj_id == id(obj):
if sym.obj_id == id(obj):
continue
for alias in self.aliases.get(dsym.cached_obj_id, set()) | self.aliases.get(
dsym.obj_id, set()
for alias in self.aliases.get(sym.cached_obj_id, set()) | self.aliases.get(
sym.obj_id, set()
):
containing_namespace = alias.containing_namespace
if containing_namespace is None:
Expand All @@ -924,10 +924,10 @@ def _resync_symbols(self, symbols: Iterable[Symbol]):
containing_namespace._subscript_data_symbol_by_name[
alias.name
] = alias
cleanup_discard(self.aliases, dsym.cached_obj_id, dsym)
cleanup_discard(self.aliases, dsym.obj_id, dsym)
self.aliases.setdefault(id(obj), set()).add(dsym)
dsym.update_obj_ref(obj)
cleanup_discard(self.aliases, sym.cached_obj_id, sym)
cleanup_discard(self.aliases, sym.obj_id, sym)
self.aliases.setdefault(id(obj), set()).add(sym)
sym.update_obj_ref(obj)

def _add_applicable_prev_cell_parents_to_current(self) -> None:
cell = cells().at_counter(self.cell_counter())
Expand Down
2 changes: 1 addition & 1 deletion core/ipyflow/shell/interactiveshell.py
Original file line number Diff line number Diff line change
Expand Up @@ -376,7 +376,7 @@ def _ipyflow_run_cell(
raw_cell.strip().splitlines()[0][len("%%capture") :].strip()
)
# TODO: add all live refs as dependencies
singletons.flow().global_scope.upsert_data_symbol_for_name(
singletons.flow().global_scope.upsert_symbol_for_name(
outvar, get_ipython().user_ns.get(outvar)
)
# Stage 3: Run post-execute hook
Expand Down
4 changes: 4 additions & 0 deletions core/ipyflow/slicing/mixin.py
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,10 @@ class SliceableMixin(Protocol):
dangling_static_parents: Dict[IdType, Set["Symbol"]]
dangling_static_children: Dict[IdType, Set["Symbol"]]

@classmethod
def current(cls) -> "SliceableMixin":
...

@classmethod
def at_timestamp(
cls, ts: TimestampOrCounter, stmt_num: Optional[int] = None
Expand Down
4 changes: 2 additions & 2 deletions core/ipyflow/tracing/external_calls/list_handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ def initialize(self, **kwargs) -> None:

def handle_namespace(self, namespace: "Namespace") -> None:
for upsert_pos in range(self.orig_len, len(namespace.obj)):
namespace.upsert_data_symbol_for_name(
namespace.upsert_symbol_for_name(
upsert_pos,
namespace.obj[upsert_pos],
self.arg_dsyms,
Expand All @@ -57,7 +57,7 @@ def handle_namespace(self, namespace: "Namespace") -> None:
if len(inserted_syms) > 1:
return
namespace.shuffle_symbols_upward_from(self.insert_pos)
namespace.upsert_data_symbol_for_name(
namespace.upsert_symbol_for_name(
self.insert_pos,
namespace.obj[self.insert_pos],
inserted_syms,
Expand Down

0 comments on commit 7b9d565

Please sign in to comment.