Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tests branch #14

Merged
merged 4 commits into from
Sep 18, 2023
Merged
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
6 changes: 3 additions & 3 deletions zt_backend/models/components/slider.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from pydantic import Field, validator
from pydantic import Field, field_validator
from zt_backend.models.components.zt_component import ZTComponent
from zt_backend.models.validations import validate_color, validate_min_less_than_max
from zt_backend.models.state import component_values
Expand All @@ -18,11 +18,11 @@ class Slider(ZTComponent):
size: str = Field('large', description="Size of the slider.")
rounded: bool = Field(True, description="Determines if the slider has rounded edges.")

@validator('color', allow_reuse=True, pre=True)
@field_validator('color')
def validate_color(cls, color):
return validate_color(color)

@validator('value', always=True)
@field_validator('value')
def get_value_from_global_state(cls, value, values):
id = values.get('id') # Get the id if it exists in the field values
try:
Expand Down
4 changes: 2 additions & 2 deletions zt_backend/models/components/zt_component.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
from pydantic import BaseModel, Field, validator
from pydantic import BaseModel, Field, field_validator
from zt_backend.models.state import created_components, context_globals

class ZTComponent(BaseModel):
id: str = Field(description="Unique id for a component")
variable_name: str = Field('fake', description="Optional variable name associated with a component")

@validator('id', always=True)
@field_validator('id',mode='before')
def validate_unique_component_id(cls, id):
if context_globals['exec_mode'] and id in created_components:
raise Exception("Component ID is not unique")
Expand Down
4 changes: 2 additions & 2 deletions zt_backend/models/notebook.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from pydantic import BaseModel, Field, SerializeAsAny, root_validator
from pydantic import BaseModel, Field, SerializeAsAny, model_validator
from typing import OrderedDict, List, Dict, Any
from zt_backend.models.components.zt_component import ZTComponent
from zt_backend.models.components.slider import Slider
Expand All @@ -20,7 +20,7 @@ class CodeCell(BaseModel):
components: List[SerializeAsAny[ZTComponent]]
cellType: str = Field('code', enum=['code', 'markdown'])

@root_validator(pre=True)
@model_validator(mode='before')
def deserialize_components(cls, values):
components = values.get('components', [])
values['components'] = [deserialize_component(comp) for comp in components]
Expand Down
16 changes: 15 additions & 1 deletion zt_backend/models/request.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from pydantic import BaseModel, root_validator
from pydantic import BaseModel
from typing import List, Dict, Union
from zt_backend.models.components.slider import Slider
from zt_backend.models.components.zt_component import ZTComponent
Expand All @@ -17,10 +17,24 @@ class CodeRequest(BaseModel):
id: str
code: str


class Request(BaseModel):
cells: List[CodeRequest]
components: Dict[str, Union[str, bool, int]]


class Cell(BaseModel):
code: str
defined_names: List[str]
loaded_names: List[str]
child_cells: List[int] = []
parent_cells: List[int] = []
previous_child_cells: List[int] = []

class CodeDict(BaseModel):
cells: Dict[str, Cell]


# @root_validator(pre=True)
# def deserialize_components(cls, values):
# components = values.get('components', [])
Expand Down
3 changes: 2 additions & 1 deletion zt_backend/models/state.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
component_values = {}
created_components=[]
context_globals={"exec_mode": False}
context_globals={"exec_mode": False}
cell_outputs_dict = {}
16 changes: 3 additions & 13 deletions zt_backend/runner/code_cell_parser.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,9 @@
from typing import List, Dict, Union, Tuple, Any
from pydantic import BaseModel
import astroid
from zt_backend.models.request import Request

# Define Pydantic model for Cell
class Cell(BaseModel):
code: str
defined_names: List[str]
loaded_names: List[str]
child_cells: List[int] = []
parent_cells: List[int] = []
previous_child_cells: List[int] = []

class CodeDict(BaseModel):
cells: Dict[str, Cell]
from zt_backend.models.request import Request,Cell,CodeDict



def get_imports(module) -> List[str]:
import_froms = [node.names[0][1] or node.names[0][0] for node in module.nodes_of_class(astroid.ImportFrom)]
Expand Down
3 changes: 1 addition & 2 deletions zt_backend/runner/execute_code.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from contextlib import redirect_stdout
from zt_backend.models import request, response
from zt_backend.models.components.zt_component import ZTComponent
from zt_backend.models.state import component_values, created_components, context_globals
from zt_backend.models.state import component_values, created_components, context_globals,cell_outputs_dict
from zt_backend.runner.code_cell_parser import parse_cells,build_dependency_graph,find_downstream_cells, CodeDict,Cell


Expand Down Expand Up @@ -59,7 +59,6 @@ def execute_request(request: request.Request):
cell_outputs = []
component_values.update(request.components)
component_globals={'global_state': component_values}
cell_outputs_dict = {}
added_components = []
dependency_graph = build_dependency_graph(parse_cells(request))
downstream_cells = find_downstream_cells(dependency_graph,request.cells[0].id)
Expand Down
117 changes: 79 additions & 38 deletions zt_backend/tests/test_code_cell_parser.py
Original file line number Diff line number Diff line change
@@ -1,80 +1,121 @@
from zt_backend.runner.code_cell_parser import parse_cells, build_dependency_graph
from zt_backend.models.request import Request,CodeRequest,Cell,CodeDict
import pytest


# Test 1: No dependencies between cells
def test_no_dependencies():
cells = ["a = 1", "b = 2", "c = 3"]
cells = Request(cells=[CodeRequest(id="0",code="a = 1"),
CodeRequest(id="1",code="b = 2"),
CodeRequest(id="2",code="c = 3")],\
components={"":""})
cell_dict = build_dependency_graph(parse_cells(cells))
assert cell_dict[0]['defined_names'] == ['a'] and cell_dict[0]['loaded_names'] == [], "Test 1 Failed"
assert cell_dict[1]['defined_names'] == ['b'] and cell_dict[1]['loaded_names'] == [], "Test 1 Failed"
assert cell_dict[2]['defined_names'] == ['c'] and cell_dict[2]['loaded_names'] == [], "Test 1 Failed"
assert cell_dict.cells['0'].defined_names == ['a'] and cell_dict.cells['0'].loaded_names == [], "Test 1 Failed"
assert cell_dict.cells['1'].defined_names == ['b'] and cell_dict.cells['1'].loaded_names == [], "Test 1 Failed"
assert cell_dict.cells['2'].defined_names == ['c'] and cell_dict.cells['2'].loaded_names == [], "Test 1 Failed"

# Test 2: Simple dependencies
def test_simple_dependencies():
cells = ["a = 1", "b = a + 2", "c = b + 3"]
cells = Request(cells=[CodeRequest(id="0", code="a = 1"),
CodeRequest(id="1", code="b = a + 2"),
CodeRequest(id="2", code="c = b + 3")],
components={})
cell_dict = build_dependency_graph(parse_cells(cells))
assert cell_dict[0]['defined_names'] == ['a'] and cell_dict[0]['loaded_names'] == [], "Test 2 Failed"
assert cell_dict[1]['defined_names'] == ['b'] and cell_dict[1]['loaded_names'] == ['a'], "Test 2 Failed"
assert cell_dict[2]['defined_names'] == ['c'] and cell_dict[2]['loaded_names'] == ['b'], "Test 2 Failed"

assert cell_dict.cells['0'].defined_names == ['a'] and cell_dict.cells['0'].loaded_names == [], "Test 2 Failed"
assert cell_dict.cells['1'].defined_names == ['b'] and cell_dict.cells['1'].loaded_names == ['a'], "Test 2 Failed"
assert cell_dict.cells['2'].defined_names == ['c'] and cell_dict.cells['2'].loaded_names == ['b'], "Test 2 Failed"

# Test 3: Complex dependencies
def test_complex_dependencies():
cells = ["a = 1", "b = a + 2", "c = b + a"]
cells = Request(cells=[CodeRequest(id="0", code="a = 1"),
CodeRequest(id="1", code="b = a + 2"),
CodeRequest(id="2", code="c = b + a")],
components={})
cell_dict = build_dependency_graph(parse_cells(cells))
assert cell_dict[0]['defined_names'] == ['a'] and cell_dict[0]['loaded_names'] == [], "Test 3 Failed"
assert cell_dict[1]['defined_names'] == ['b'] and cell_dict[1]['loaded_names'] == ['a'], "Test 3 Failed"
assert cell_dict[2]['defined_names'] == ['c'] and set(cell_dict[2]['loaded_names']) == set(['b', 'a']), "Test 3 Failed"

assert cell_dict.cells['0'].defined_names == ['a'] and cell_dict.cells['0'].loaded_names == [], "Test 3 Failed"
assert cell_dict.cells['1'].defined_names == ['b'] and cell_dict.cells['1'].loaded_names == ['a'], "Test 3 Failed"
assert cell_dict.cells['2'].defined_names == ['c'] and set(cell_dict.cells['2'].loaded_names) == set(['b', 'a']), "Test 3 Failed"

# Test 4: Overriding dependencies
def test_overriding_dependencies():
cells = ["a = 1", "b = a + 2", "a = 3", "c = a + b"]
cells = Request(cells=[CodeRequest(id="0", code="a = 1"),
CodeRequest(id="1", code="b = a + 2"),
CodeRequest(id="2", code="a = 3"),
CodeRequest(id="3", code="c = a + b")],
components={})
cell_dict = build_dependency_graph(parse_cells(cells))
assert cell_dict[0]['defined_names'] == ['a'] and cell_dict[0]['loaded_names'] == [], "Test 4 Failed"
assert cell_dict[1]['defined_names'] == ['b'] and cell_dict[1]['loaded_names'] == ['a'], "Test 4 Failed"
assert cell_dict[2]['defined_names'] == ['a'] and cell_dict[2]['loaded_names'] == [], "Test 4 Failed"
assert cell_dict[3]['defined_names'] == ['c'] and set(cell_dict[3]['loaded_names']) == set(['a', 'b']), "Test 4 Failed"

assert cell_dict.cells['0'].defined_names == ['a'] and cell_dict.cells['0'].loaded_names == [], "Test 4 Failed"
assert cell_dict.cells['1'].defined_names == ['b'] and cell_dict.cells['1'].loaded_names == ['a'], "Test 4 Failed"
assert cell_dict.cells['2'].defined_names == ['a'] and cell_dict.cells['2'].loaded_names == [], "Test 4 Failed"
assert cell_dict.cells['3'].defined_names == ['c'] and set(cell_dict.cells['3'].loaded_names) == set(['a', 'b']), "Test 4 Failed"

# Test 5: Function definitions and calls
def test_function_definitions_and_calls():
cells = ["def f(x): return x + 2", "a = f(2)", "b = a + 3"]
cells = Request(cells=[CodeRequest(id="0", code="def f(x): return x + 2"),
CodeRequest(id="1", code="a = f(2)"),
CodeRequest(id="2", code="b = a + 3")],
components={})
cell_dict = build_dependency_graph(parse_cells(cells))
assert cell_dict[0]['defined_names'] == ['f'] and cell_dict[0]['loaded_names'] == [], "Test 5 Failed"
assert cell_dict[1]['defined_names'] == ['a'] and cell_dict[1]['loaded_names'] == ['f'], "Test 5 Failed"

assert cell_dict.cells['0'].defined_names == ['f'] and cell_dict.cells['0'].loaded_names == [], "Test 5 Failed"
assert cell_dict.cells['1'].defined_names == ['a'] and cell_dict.cells['1'].loaded_names == ['f'], "Test 5 Failed"
assert cell_dict.cells['2'].defined_names == ['b'] and cell_dict.cells['2'].loaded_names == ['a'], "Test 5 Failed"

# Test 6: Dependencies with function calls and redefinitions
def test_dependencies_with_function_calls_and_redefinitions():
cells = ["def f(x): return x + 2", "a = f(2)", "b = a + 3", "def g(x): return x * 2", "c = g(b)"]
cells = Request(cells=[CodeRequest(id="0", code="def f(x): return x + 2"),
CodeRequest(id="1", code="a = f(2)"),
CodeRequest(id="2", code="b = a + 3"),
CodeRequest(id="3", code="def g(x): return x * 2"),
CodeRequest(id="4", code="c = g(b)")],
components={})
cell_dict = build_dependency_graph(parse_cells(cells))
assert cell_dict[0]['defined_names'] == ['f'] and cell_dict[0]['loaded_names'] == [], "Test 6 Failed"
assert cell_dict[1]['defined_names'] == ['a'] and cell_dict[1]['loaded_names'] == ['f'], "Test 6 Failed"
assert cell_dict[2]['defined_names'] == ['b'] and cell_dict[2]['loaded_names'] == ['a'], "Test 6 Failed"
assert cell_dict[3]['defined_names'] == ['g'] and cell_dict[3]['loaded_names'] == [], "Test 6 Failed"
assert cell_dict[4]['defined_names'] == ['c'] and set(cell_dict[4]['loaded_names']) == set(['g', 'b']), "Test 6 Failed"

assert cell_dict.cells['0'].defined_names == ['f'] and cell_dict.cells['0'].loaded_names == [], "Test 6 Failed"
assert cell_dict.cells['1'].defined_names == ['a'] and cell_dict.cells['1'].loaded_names == ['f'], "Test 6 Failed"
assert cell_dict.cells['2'].defined_names == ['b'] and cell_dict.cells['2'].loaded_names == ['a'], "Test 6 Failed"
assert cell_dict.cells['3'].defined_names == ['g'] and cell_dict.cells['3'].loaded_names == [], "Test 6 Failed"
assert cell_dict.cells['4'].defined_names == ['c'] and set(cell_dict.cells['4'].loaded_names) == set(['g', 'b']), "Test 6 Failed"

# Test 7: Importing a module in one cell and using it in another
def test_importing_module():
cells = ["import math", "a = math.sqrt(4)"]
cells = Request(cells=[CodeRequest(id="0", code="import math"),
CodeRequest(id="1", code="a = math.sqrt(4)")],
components={})
cell_dict = build_dependency_graph(parse_cells(cells))
assert cell_dict[0]['defined_names'] == ['math'] and cell_dict[0]['loaded_names'] == [], "Test 7 Failed"
assert cell_dict[1]['defined_names'] == ['a'] and cell_dict[1]['loaded_names'] == ['math'], "Test 7 Failed"

assert cell_dict.cells['0'].defined_names == ['math'] and cell_dict.cells['0'].loaded_names == [], "Test 7 Failed"
assert cell_dict.cells['1'].defined_names == ['a'] and cell_dict.cells['1'].loaded_names == ['math'], "Test 7 Failed"

# Test 8: Defining multiple variables in one cell
def test_multiple_variables_in_one_cell():
cells = ["a = 1; b = 2; c = 3", "d = a + b + c"]
cells = Request(cells=[CodeRequest(id="0", code="a = 1; b = 2; c = 3"),
CodeRequest(id="1", code="d = a + b + c")],
components={})
cell_dict = build_dependency_graph(parse_cells(cells))
assert set(cell_dict[0]['defined_names']) == set(['a', 'b', 'c']) and cell_dict[0]['loaded_names'] == [], "Test 8 Failed"
assert cell_dict[1]['defined_names'] == ['d'] and set(cell_dict[1]['loaded_names']) == set(['a', 'b', 'c']), "Test 8 Failed"

assert set(cell_dict.cells['0'].defined_names) == set(['a', 'b', 'c']) and cell_dict.cells['0'].loaded_names == [], "Test 8 Failed"
assert cell_dict.cells['1'].defined_names == ['d'] and set(cell_dict.cells['1'].loaded_names) == set(['a', 'b', 'c']), "Test 8 Failed"

# Test 9: Multiline cells
def test_multiline_cells():
cells = ["a = 1\nb = 2\nc = 3", "d = a + b\ne = c * d"]
cells = Request(cells=[CodeRequest(id="0", code="a = 1\nb = 2\nc = 3"),
CodeRequest(id="1", code="d = a + b\ne = c * d")],
components={})
cell_dict = build_dependency_graph(parse_cells(cells))
assert set(cell_dict[0]['defined_names']) == set(['a', 'b', 'c']) and cell_dict[0]['loaded_names'] == [], "Test 9 Failed"
assert set(cell_dict[1]['defined_names']) == set(['d', 'e']) and set(cell_dict[1]['loaded_names']) == set(['a', 'b', 'c']), "Test 9 Failed"

assert set(cell_dict.cells['0'].defined_names) == set(['a', 'b', 'c']) and cell_dict.cells['0'].loaded_names == [], "Test 9 Failed"
assert set(cell_dict.cells['1'].defined_names) == set(['d', 'e']) and set(cell_dict.cells['1'].loaded_names) == set(['a', 'b', 'c']), "Test 9 Failed"

# Test 10: Importing a module with an alias in one cell and using it in another
def test_importing_module_with_alias():
cells = ["import math as m", "a = m.sqrt(4)"]
cells = Request(cells=[CodeRequest(id="0", code="import math as m"),
CodeRequest(id="1", code="a = m.sqrt(4)")],
components={})
cell_dict = build_dependency_graph(parse_cells(cells))
assert cell_dict[0]['defined_names'] == ['m'] and cell_dict[0]['loaded_names'] == [], "Test 10 Failed"
assert cell_dict[1]['defined_names'] == ['a'] and cell_dict[1]['loaded_names'] == ['m'], "Test 10 Failed"

assert cell_dict.cells['0'].defined_names == ['m'] and cell_dict.cells['0'].loaded_names == [], "Test 10 Failed"
assert cell_dict.cells['1'].defined_names == ['a'] and cell_dict.cells['1'].loaded_names == ['m'], "Test 10 Failed"
40 changes: 40 additions & 0 deletions zt_backend/tests/test_execute_code.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
from zt_backend.runner.execute_code import execute_request, cell_outputs_dict
from zt_backend.models.request import Request, CodeRequest
import pytest

# Initialize or clear cell_outputs_dict
def setup_function():
cell_outputs_dict.clear()

# Test for simple variable assignment
def test_execute_request_simple_variable():
setup_function()
req = Request(cells=[CodeRequest(id="0", code="a = 1")], components={})
execute_request(req)
assert 'a' in cell_outputs_dict['0']
assert cell_outputs_dict['0']['a'] == 1

# Test for function definition
def test_execute_request_function_definition():
setup_function()
req = Request(cells=[CodeRequest(id="1", code="def add(x, y): return x + y")], components={})
execute_request(req)
assert 'add' in cell_outputs_dict['1']

# Test for importing modules
def test_execute_request_import_module():
setup_function()
req = Request(cells=[CodeRequest(id="2", code="import math")], components={})
execute_request(req)
assert 'math' in cell_outputs_dict['2']

# Test for multiple cells with dependencies
def test_execute_request_multiple_cells_with_dependencies():
setup_function()
req = Request(cells=[CodeRequest(id="3", code="a = 1"),
CodeRequest(id="4", code="b = a + 1")], components={})
execute_request(req)
assert 'a' in cell_outputs_dict['3']
assert 'b' in cell_outputs_dict['4']
assert cell_outputs_dict['3']['a'] == 1
assert cell_outputs_dict['4']['b'] == 2