Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions graphistry/compute/ComputeMixin.py
Original file line number Diff line number Diff line change
Expand Up @@ -479,8 +479,8 @@ def chain(self, *args, **kwargs):
# Preserve original docstring after deprecation notice
chain.__doc__ = (chain.__doc__ or "") + "\n\n" + (chain_base.__doc__ or "")

# chain_dag removed from public API - use gfql() instead
# (chain_dag_base still available internally for gfql dispatch)
# chain_let removed from public API - use gfql() instead
# (chain_let_base still available internally for gfql dispatch)

def gfql(self, *args, **kwargs):
return gfql_base(self, *args, **kwargs)
Expand Down
10 changes: 5 additions & 5 deletions graphistry/compute/ast.py
Original file line number Diff line number Diff line change
Expand Up @@ -702,10 +702,10 @@ def from_json(cls, d: dict, validate: bool = True) -> 'ASTLet':

def __call__(self, g: Plottable, prev_node_wavefront: Optional[DataFrameT],
target_wave_front: Optional[DataFrameT], engine: Engine) -> Plottable:
# Let bindings don't use wavefronts - execute via chain_dag_impl
from graphistry.compute.chain_dag import chain_dag_impl
# Let bindings don't use wavefronts - execute via chain_let_impl
from graphistry.compute.chain_let import chain_let_impl
from graphistry.Engine import EngineAbstract
return chain_dag_impl(g, self, EngineAbstract(engine.value))
return chain_let_impl(g, self, EngineAbstract(engine.value))

def reverse(self) -> 'ASTLet':
raise NotImplementedError("Let reversal not supported")
Expand Down Expand Up @@ -934,7 +934,7 @@ def __call__(self, g: Plottable, prev_node_wavefront: Optional[DataFrameT],
target_wave_front: Optional[DataFrameT], engine: Engine) -> Plottable:
raise NotImplementedError(
"ASTRef cannot be used directly in chain(). "
"It must be used within an ASTLet/chain_dag() context."
"It must be used within an ASTLet/chain_let() context."
)

def reverse(self) -> 'ASTRef':
Expand Down Expand Up @@ -1050,7 +1050,7 @@ def __call__(self, g: Plottable, prev_node_wavefront: Optional[DataFrameT],
Raises:
GFQLTypeError: If method not in safelist or parameters invalid
"""
# For chain_dag, we don't use wavefronts, just execute the call
# For chain_let, we don't use wavefronts, just execute the call
from graphistry.compute.call_executor import execute_call
return execute_call(g, self.function, self.params, engine)

Expand Down
28 changes: 12 additions & 16 deletions graphistry/compute/chain_dag.py → graphistry/compute/chain_let.py
Original file line number Diff line number Diff line change
Expand Up @@ -194,11 +194,7 @@ def execute_node(name: str, ast_obj: ASTObject, g: Plottable,
"""Execute a single node in the DAG

Handles different AST object types:
<<<<<<< HEAD
- ASTLet: Recursive let execution
=======
- ASTLet: Recursive DAG execution
>>>>>>> refactor: rename ASTQueryDAG to ASTLet throughout codebase
- ASTRef: Reference resolution and chain execution
- ASTNode: Node filtering operations
- ASTEdge: Edge traversal operations
Expand All @@ -219,7 +215,7 @@ def execute_node(name: str, ast_obj: ASTObject, g: Plottable,
# Handle different AST object types
if isinstance(ast_obj, ASTLet):
# Nested let execution
result = chain_dag_impl(g, ast_obj, EngineAbstract(engine.value))
result = chain_let_impl(g, ast_obj, EngineAbstract(engine.value))
elif isinstance(ast_obj, ASTRef):
# Resolve reference from context
try:
Expand All @@ -240,7 +236,7 @@ def execute_node(name: str, ast_obj: ASTObject, g: Plottable,
# Empty chain - just return the referenced result
result = referenced_result
elif isinstance(ast_obj, ASTNode):
# For chain_dag, we execute nodes in a simpler way than chain()
# For chain_let, we execute nodes in a simpler way than chain()
# No wavefront propagation - just filter the graph's nodes
node_obj = cast(ASTNode, ast_obj) # Help mypy understand the type
if node_obj.filter_dict or node_obj.query:
Expand All @@ -258,7 +254,7 @@ def execute_node(name: str, ast_obj: ASTObject, g: Plottable,
if node_obj._name:
result = result.nodes(result._nodes.assign(**{node_obj._name: True}))
elif isinstance(ast_obj, ASTEdge):
# For chain_dag, execute edge operations using hop()
# For chain_let, execute edge operations using hop()
# This is simpler than the full chain() wavefront approach
result = g.hop(
nodes=None, # Start from all nodes
Expand Down Expand Up @@ -316,10 +312,10 @@ def execute_node(name: str, ast_obj: ASTObject, g: Plottable,
return result


def chain_dag_impl(g: Plottable, dag: ASTLet,
def chain_let_impl(g: Plottable, dag: ASTLet,
engine: Union[EngineAbstract, str] = EngineAbstract.AUTO,
output: Optional[str] = None) -> Plottable:
"""Internal implementation of chain_dag execution
"""Internal implementation of chain_let execution

Validates DAG, determines execution order, and executes nodes
in topological order.
Expand All @@ -346,7 +342,7 @@ def chain_dag_impl(g: Plottable, dag: ASTLet,

# Resolve engine
engine_concrete = resolve_engine(engine, g)
logger.debug('chain_dag engine: %s => %s', engine, engine_concrete)
logger.debug('chain_let engine: %s => %s', engine, engine_concrete)

# Materialize nodes if needed (following chain.py pattern)
g = g.materialize_nodes(engine=EngineAbstract(engine_concrete.value))
Expand Down Expand Up @@ -392,7 +388,7 @@ def chain_dag_impl(g: Plottable, dag: ASTLet,
return last_result


def chain_dag(self: Plottable, dag: ASTLet,
def chain_let(self: Plottable, dag: ASTLet,
engine: Union[EngineAbstract, str] = EngineAbstract.AUTO,
output: Optional[str] = None) -> Plottable:
"""
Expand All @@ -416,7 +412,7 @@ def chain_dag(self: Plottable, dag: ASTLet,
dag = ASTLet({
'people': n({'type': 'person'})
})
result = g.chain_dag(dag)
result = g.chain_let(dag)

**Example: Linear dependencies**

Expand All @@ -428,7 +424,7 @@ def chain_dag(self: Plottable, dag: ASTLet,
'start': n({'type': 'person'}),
'friends': ASTRef('start', [e(), n()])
})
result = g.chain_dag(dag)
result = g.chain_let(dag)

**Example: Diamond pattern**

Expand All @@ -441,9 +437,9 @@ def chain_dag(self: Plottable, dag: ASTLet,
'branch2': ASTRef('transactions', [e()]),
'merged': g.union(ASTRef('branch1'), ASTRef('branch2'))
})
result = g.chain_dag(dag) # Returns last executed
result = g.chain_let(dag) # Returns last executed

# Or select specific output
people_result = g.chain_dag(dag, output='people')
people_result = g.chain_let(dag, output='people')
"""
return chain_dag_impl(self, dag, engine, output)
return chain_let_impl(self, dag, engine, output)
4 changes: 2 additions & 2 deletions graphistry/compute/gfql_unified.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from graphistry.util import setup_logger
from .ast import ASTObject, ASTLet
from .chain import Chain, chain as chain_impl
from .chain_dag import chain_dag as chain_dag_impl
from .chain_let import chain_let as chain_let_impl

logger = setup_logger(__name__)

Expand Down Expand Up @@ -74,7 +74,7 @@ def gfql(self: Plottable,
# Dispatch based on type - check specific types before generic
if isinstance(query, ASTLet):
logger.debug('GFQL executing as DAG')
return chain_dag_impl(self, query, engine, output)
return chain_let_impl(self, query, engine, output)
elif isinstance(query, Chain):
logger.debug('GFQL executing as Chain')
if output is not None:
Expand Down
2 changes: 1 addition & 1 deletion graphistry/compute/validate/validate_schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ def _validate_ref_op(op: ASTRef, g: Plottable, collect_all: bool) -> List[GFQLSc
raise

# Note: We don't validate that op.ref exists here since that's handled
# by the DAG dependency validation in chain_dag.py
# by the DAG dependency validation in chain_let.py

return errors

Expand Down
2 changes: 1 addition & 1 deletion graphistry/compute/validate_schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ def _validate_chainref_op(op: ASTRef, g: Plottable, collect_all: bool) -> List[G
raise

# Note: We don't validate that op.ref exists here since that's handled
# by the DAG dependency validation in chain_dag.py
# by the DAG dependency validation in chain_let.py

return errors

Expand Down
4 changes: 2 additions & 2 deletions graphistry/tests/compute/README_INTEGRATION_TESTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@ This directory contains both unit tests (always run) and integration tests (opt-
### GPU Tests
```bash
# Enable CUDF/GPU tests
TEST_CUDF=1 pytest test_chain_dag_gpu.py
TEST_CUDF=1 pytest test_chain_let_gpu.py
```

### Remote Graph Integration Tests
```bash
# Enable remote Graphistry server tests
TEST_REMOTE_INTEGRATION=1 pytest test_chain_dag_remote_integration.py
TEST_REMOTE_INTEGRATION=1 pytest test_chain_let_remote_integration.py

# Additional configuration for remote tests:
GRAPHISTRY_USERNAME=myuser # Username for auth
Expand Down
14 changes: 7 additions & 7 deletions graphistry/tests/compute/test_call_operations.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from graphistry.tests.test_compute import CGFull
from graphistry.Engine import Engine, EngineAbstract
from graphistry.compute.ast import ASTCall, ASTLet, n
from graphistry.compute.chain_dag import chain_dag_impl
from graphistry.compute.chain_let import chain_let_impl
from graphistry.compute.gfql.call_safelist import validate_call_params
from graphistry.compute.gfql.call_executor import execute_call
from graphistry.compute.exceptions import ErrorCode, GFQLTypeError, GFQLSyntaxError
Expand Down Expand Up @@ -273,7 +273,7 @@ def test_call_in_dag(self, sample_graph):
'with_degrees': ASTCall('get_degrees', {'col': 'degree'})
})

result = chain_dag_impl(sample_graph, dag, EngineAbstract.PANDAS)
result = chain_let_impl(sample_graph, dag, EngineAbstract.PANDAS)

# Should have degree column
assert 'degree' in result._nodes.columns
Expand All @@ -282,15 +282,15 @@ def test_call_in_dag(self, sample_graph):

def test_call_referencing_binding(self, sample_graph):
"""Test ASTCall that operates on whole graph (not in chain)."""
from graphistry.compute.ast import ASTChainRef
from graphistry.compute.ast import ASTRef

# Call operations work on the whole graph, not as part of chains
dag = ASTLet({
'users': n({'type': 'user'}),
'with_degrees': ASTCall('get_degrees', {'col': 'degree'})
})

result = chain_dag_impl(sample_graph, dag, EngineAbstract.PANDAS)
result = chain_let_impl(sample_graph, dag, EngineAbstract.PANDAS)

# Should have degree column on all nodes
assert len(result._nodes) == 4 # All nodes
Expand All @@ -302,14 +302,14 @@ def test_multiple_calls(self, sample_graph):
dag1 = ASTLet({
'with_degrees': ASTCall('get_degrees', {'col': 'deg'})
})
result1 = chain_dag_impl(sample_graph, dag1, EngineAbstract.PANDAS)
result1 = chain_let_impl(sample_graph, dag1, EngineAbstract.PANDAS)
assert 'deg' in result1._nodes.columns

# Then filter - use the graph that has degrees
dag2 = ASTLet({
'filtered': ASTCall('filter_nodes_by_dict', {'filter_dict': {'deg': 2}})
})
result2 = chain_dag_impl(result1, dag2, EngineAbstract.PANDAS)
result2 = chain_let_impl(result1, dag2, EngineAbstract.PANDAS)

# Should have nodes with degree 2
assert len(result2._nodes) > 0
Expand All @@ -327,7 +327,7 @@ def test_call_execution_error(self, mock_getattr, sample_graph):
})

with pytest.raises(RuntimeError) as exc_info:
chain_dag_impl(sample_graph, dag, EngineAbstract.PANDAS)
chain_let_impl(sample_graph, dag, EngineAbstract.PANDAS)
assert "Failed to execute node 'failing'" in str(exc_info.value)


Expand Down
6 changes: 3 additions & 3 deletions graphistry/tests/compute/test_call_operations_gpu.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from graphistry.tests.test_compute import CGFull
from graphistry.Engine import Engine
from graphistry.compute.ast import ASTCall, ASTLet, n
from graphistry.compute.chain_dag import chain_dag_impl
from graphistry.compute.chain_let import chain_let_impl
from graphistry.compute.gfql.call_executor import execute_call
from graphistry.compute.validate.validate_schema import validate_chain_schema
from graphistry.compute.exceptions import ErrorCode, GFQLTypeError
Expand Down Expand Up @@ -171,7 +171,7 @@ def test_layout_cugraph_call(self):
assert result._nodes['y'].notna().all()

@skip_gpu
def test_chain_dag_with_gpu_calls(self):
def test_chain_let_with_gpu_calls(self):
"""Test DAG execution with Call operations on GPU."""
import cudf

Expand Down Expand Up @@ -199,7 +199,7 @@ def test_chain_dag_with_gpu_calls(self):
'with_degrees': ASTCall('get_degrees', {'col': 'degree'})
})

result = chain_dag_impl(g, dag, Engine.CUDF)
result = chain_let_impl(g, dag, Engine.CUDF)

# Should have degrees column
assert 'degree' in result._nodes.columns
Expand Down
Loading
Loading