def test(): """ Verify operators observe their operands """ # get the base node from the {calc} package from p2.calc.Node import Node as node # assertions that involve node comparisons must be done very carefully if nodes have # {ordering} since then the equality test becomes a node. the current implementation of # {node} does not include {ordering}, so we should be ok with naive checks. # get the calculator from p2.calc import calculator # make sure node does not derive from {ordering} assert not issubclass(node, calculator.ordering) # make a pair of variables v1 = node.variable(value=1) v2 = node.variable(value=2) # use them in a simple expression s = v1 + v2 # we expect {s} to have two operands assert set(s.operands) == {v1, v2} # we expect: # {v1} to have a single observer: {s} assert list(v1.observers) == [s] # {v2} to have a single observer: {s} assert list(v2.observers) == [s] # and s to have none assert list(s.observers) == [] # all done return
def test(): """ Exercise the interface of dicts """ # get the base node from the {calc} package from p2.calc.Node import Node as node # make some nodes nodes = ((str(n), node.variable(value=n)) for n in range(10)) # make a dict with these nodes s1 = node.dict(value=nodes) # check that for op, node in zip(s1.operands, nodes): # the operands are the exact nodes we supplied assert op is node # verify that the value is what we expect assert s1.getValue() == dict((str(n), n) for n in range(10)) # make some numbers ints = dict((str(n), n) for n in range(10)) # make a dict out of them s2 = node.dict(value=ints.items()) # check that all the {s2} operands for op in s2.operands: # are literals assert isinstance(op, node.literal) # verify that the value is what we expect assert s2.getValue() == ints # all done return
def test(): """ Verify that the mean operator works as expected """ # externals import statistics # get the node class from p2.calc.Node import Node as node # make some nodes nodes = [node.variable(value=v) for v in range(0, 100, 10)] # construct a node that computes their mean s = node.mean(operands=nodes) # check the current value assert s.getValue() == statistics.mean(range(0, 100, 10)) # adjust the values for node, value in zip(nodes, range(0, 200, 20)): node.setValue(value) # check again assert s.getValue() == statistics.mean(range(0, 200, 20)) # all done return
def test(): """ Exercise basic arithmetic operations among variables """ # get the base node from the {calc} package from p2.calc.Node import Node as node # make a couple of variables v1 = node.variable(value=1) v2 = node.variable(value=2) # basic arithmetic among variables assert (v1 + v2).getValue() == 3 assert (v1 - v2).getValue() == -1 assert (v1 * v2).getValue() == 2 assert (v1 / v2).getValue() == 0.5 assert (v1**v2).getValue() == 1 assert (v1 % v2).getValue() == 1 # variables and literals assert (v1 + 2).getValue() == 3 assert (v1 - 2).getValue() == -1 assert (v1 * 2).getValue() == 2 assert (v1 / 2).getValue() == 0.5 assert (v1**2).getValue() == 1 assert (v1 % 2).getValue() == 1 # all done return
def test(): """ Exercise basic arithmetic operations among literals """ # get the base node from the {calc} package from p2.calc.Node import Node as node # make a couple of literals l1 = node.literal(value=1) l2 = node.literal(value=2) # basic arithmetic among literals assert (l1 + l2).getValue() == 3 assert (l1 - l2).getValue() == -1 assert (l1 * l2).getValue() == 2 assert (l1 / l2).getValue() == 0.5 assert (l1**l2).getValue() == 1 assert (l1 % l2).getValue() == 1 # let the {algebra} build the second literal assert (l1 + 2).getValue() == 3 assert (l1 - 2).getValue() == -1 assert (l1 * 2).getValue() == 2 assert (l1 / 2).getValue() == 0.5 assert (l1**2).getValue() == 1 assert (l1 % 2).getValue() == 1 # all done return
def test(): """ Exercise the interface of lists """ # get the base node from the {calc} package from p2.calc.Node import Node as node # make some nodes nodes = ( node.variable(value=n) for n in range(10) ) # make a list with these nodes l1 = node.list(value=nodes) # check that for op, node in zip(l1.operands, nodes): # the operands are the exact nodes we supplied assert op is node # verify that the value is what we expect assert l1.getValue() == list(range(10)) # make some numbers ints = list(range(10)) # make a list out of them l2 = node.list(value=ints) # check that all the {s2} operands for op in l2.operands: # are literals assert isinstance(op, node.literal) # verify that the value is what we expect assert l2.getValue() == list(range(10)) # all done return
def test(): """ Verify that the product operator works as expected """ # externals import functools import operator # get the node class from p2.calc.Node import Node as node # make some nodes nodes = [node.variable(value=v) for v in range(0, 100, 10)] # construct a node that computes their product s = node.product(operands=nodes) # check the current value assert s.getValue() == functools.reduce(operator.mul, range(0, 100, 10)) # adjust the values for node, value in zip(nodes, range(0, 200, 20)): node.setValue(value) # check again assert s.getValue() == functools.reduce(operator.mul, range(0, 100, 10)) # all done return
def test(): """ Verify that substituting an operator in a simple expression works as expected """ # get the base node from the {calc} package from p2.calc.Node import Node as node # assertions that involve node comparisons must be done very carefully if nodes have # {ordering} since then the equality test becomes a node. the current implementation of # {node} does not include {ordering}, so we should be ok with naive checks. # get the calculator from p2.calc import calculator # make sure node does not derive from {ordering} assert not issubclass(node, calculator.ordering) # make a few variables v1 = node.variable(value=1) v2 = node.variable(value=2) v3 = node.variable(value=3) # use them in a simple expression s = v1 + v2 # and use this to build a more complicated one d = 2 * s # verify that the values are computed correctly assert s.getValue() == 3 assert d.getValue() == 6 # verify the node observers are as expected assert set(v1.observers) == { s } assert set(v2.observers) == { s } assert set(v3.observers) == set() assert set(s.observers) == { d } assert set(d.observers) == set() # now, replace {s} with {v1} d.substitute(current=s, replacement=v3) # the value of {s} should be unchanged assert s.getValue() == 3 # but {d} is different assert d.getValue() == 6 # check the observers # nothing has changed for {v1} since {s} is still alive assert set(v1.observers) == { s } # same for {v2} assert set(v2.observers) == { s } # {v3} is now observed by {d} assert set(v3.observers) == { d } # {s} is not being observed any more assert set(s.observers) == set() # and, of course, no one is watching {d} assert set(d.observers) == set() # all done return
def test(): """ Verify that substituting a variable in a simple expression works as expected """ # get the base node from the {calc} package from p2.calc.Node import Node as node # assertions that involve node comparisons must be done very carefully if nodes have # {ordering} since then the equality test becomes a node. the current implementation of # {node} does not include {ordering}, so we should be ok with naive checks. # get the calculator from p2.calc import calculator # make sure node does not derive from {ordering} assert not issubclass(node, calculator.ordering) # make a few variables v1 = node.variable(value=1) v2 = node.variable(value=2) v3 = node.variable(value=3) # use them in a simple expression s = v1 + v2 # we expect {s} to have two operands assert set(s.operands) == {v1, v2} # make sure it computes correctly assert s.getValue() == 3 # check observers; we expect # {v1} to be observed by {s} assert set(v1.observers) == {s} # {v2} to be observed by {s} assert set(v2.observers) == {s} # and {v3} to have no observers assert set(v3.observers) == set() # substitute {v3} for {v1} s.substitute(current=v1, replacement=v3) # verify the substitution took place assert set(s.operands) == {v2, v3} # make sure it computes correctly assert s.getValue() == 5 # check observers; we expect # {v1} to have no observers assert set(v1.observers) == set() # {v2} to be observed by {s} assert set(v2.observers) == {s} # and {v3} to be observed by {s} assert set(v3.observers) == {s} # all done return
def test(): """ Verify that the {node} class hierarchy looks as expected """ # get the {calc} import p2.calc # and {algebraic} packages import p2.algebraic # access from p2.calc.Node import Node as node # pull out the {calc} metaclass calculator = p2.calc.calculator # and the base metaclass algebra = p2.algebraic.algebra # get the base node {mro} nodeMRO = node.mro() # verify the derivation of the base node assert nodeMRO == [ node, calculator.base, algebra.base, calculator.arithmetic, object ] # all done return
def test(): """ Exercise the interface of operators """ # get the base node from the {calc} package from p2.calc.Node import Node as node # use an expression make an operator operator = 2 * node.literal(value=1) # access the value assert operator.getValue() == 2 # attempt to try: # set the value operator.setValue(value=1) # which should fail assert False, "unreachable" # because there is no base with an implementation except AttributeError as error: # all good pass # all done return
def test(): """ Exercise the interface of literals """ # get the base node from the {calc} package from p2.calc.Node import Node as node # make a literal literal = node.literal(value=0) # access the value assert literal.getValue() == 0 # attempt to try: # set the value literal.setValue(value=1) # which should fail assert False, "unreachable" # because {const} is protecting it except NotImplementedError as error: # all good pass # all done return
def test(): """ Verify that the {literal} class hierarchy looks as expected """ # get the {calc} from p2.calc import calculator # and {algebraic} metaclasses from p2.algebraic import algebra # get the base node from the {calc} package from p2.calc.Node import Node as node # get the base node {mro} nodeMRO = node.mro() # get the literal class literal = node.literal # and its mro literalMRO = literal.mro() # verify the structure assert literalMRO == [ literal, calculator.const, calculator.value, algebra.literal, algebra.leaf ] + nodeMRO # all done return
def test(): """ Verify that the {variable} class hierarchy looks as expected """ # get the {calc} from p2.calc import calculator # and {algebraic} metaclasses from p2.algebraic import algebra # get the base node from the {calc} package from p2.calc.Node import Node as node # get the base node {mro} nodeMRO = node.mro() # get the variable class variable = node.variable # and its mro variableMRO = variable.mro() # verify the structure assert variableMRO == [ # the user visible class variable, # observable calculator.dependency, calculator.observable, calculator.reactor, # value management calculator.value, # base {variable} from {algebra} algebra.variable, algebra.leaf # node ] + nodeMRO # all done return
def test(): """ Verify that the {unresolved} class hierarchy looks as expected """ # get the {calc} from p2.calc import calculator # and {algebraic} metaclasses from p2.algebraic import algebra # get the base node from the {calc} package from p2.calc.Node import Node as node # get the base node {mro} nodeMRO = node.mro() # get the unresolved class unresolved = node.unresolved # and its mro unresolvedMRO = unresolved.mro() # verify the structure assert unresolvedMRO == [ unresolved, calculator.observable, calculator.reactor, calculator.unresolved, algebra.leaf ] + nodeMRO # all done return
def test(): """ Verify that attempting to replace a node that is not present in an expression is a no-op """ # get the base node from the {calc} package from p2.calc.Node import Node as node # assertions that involve node comparisons must be done very carefully if nodes have # {ordering} since then the equality test becomes a node. the current implementation of # {node} does not include {ordering}, so we should be ok with naive checks. # get the calculator from p2.calc import calculator # make sure node does not derive from {ordering} assert not issubclass(node, calculator.ordering) # make a few variables v1 = node.variable(value=1) v2 = node.variable(value=2) v3 = node.variable(value=3) # use them in a simple expression s = v1 + v2 # ask {v1} to replace {v3} v1.replace(obsolete=v3) # verify that nothing was disturbed assert set(s.operands) == {v1, v2} # make sure it computes correctly assert s.getValue() == 3 # check observers; we expect # {v1} to be observed by {s} assert set(v1.observers) == {s} # {v2} to be observed by {s} assert set(v2.observers) == {s} # and {v3} to have no observers assert set(v3.observers) == set() # all done return
def test(): """ Verify that nodes get cleaned up correctly """ # get the node base class from p2.calc.Node import Node as node # verify that it is has extent, and that it is empty assert len(node.pyre_extent) == 0 # make a couple of variables v1 = node.variable(value=1) v2 = node.variable(value=2) # verify that the two nodes are accounted for assert len(node.pyre_extent) == 2 # build an expression e = v1**2 + 2 * v1 * v2 + v2**2 # we just created an additional 9 nodes (count them!) assert len(node.pyre_extent) == 11 # all done; all nodes go out of scope here, so they should get destroyed return
def test(): """ Exercise the interface of lists """ # get the base node from the {calc} package from p2.calc.Node import Node as node # make a list l = node.list(value=[]) # access the value assert l.getValue() == [] # make some nodes nodes = list( node.variable(value=n) for n in range(10) ) # and some numbers numbers = [1, 2, 3] # set the value l.setValue(value=nodes+numbers) # verify it happened correctly assert l.getValue() == [0,1,2,3,4,5,6,7,8,9, 1,2,3] # all done return
def test(): """ Exercise the interface of dicts """ # get the base node from the {calc} package from p2.calc.Node import Node as node # make a dict s = node.dict(value=[]) # access the value assert s.getValue() == dict() # make some nodes nodes = tuple( (str(n), node.variable(value=n)) for n in range(10) ) # and some numbers numbers = ( ("1", 1), ("2", 2), ("3",3)) # set the value s.setValue(value=nodes+numbers) # verify it happened correctly assert s.getValue() == dict((str(n), n) for n in range(10)) # all done return
def test(): """ Exercise the interface of tuples """ # get the base node from the {calc} package from p2.calc.Node import Node as node # make a tuple t = node.tuple(value=[]) # access the value assert t.getValue() == () # make some nodes nodes = tuple(node.variable(value=n) for n in range(10)) # and some numbers numbers = (1, 2, 3) # set the value t.setValue(value=nodes + numbers) # verify it happened correctly assert t.getValue() == (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3) # all done return
def test(): """ Verify that the {list} class hierarchy looks as expected """ # get the {calc} from p2.calc import calculator # and {algebraic} metaclasses from p2.algebraic import algebra # get the base node from the {calc} package from p2.calc.Node import Node as node # get the base node {mro} nodeMRO = node.mro() # get the list class list = node.list # and its mro listMRO = list.mro() # verify the structure assert listMRO == [ # the user visible class list, # observer calculator.dependent, calculator.observer, # observable calculator.dependency, calculator.observable, calculator.reactor, # base {list} from {calculator} calculator.list, # base {sequence} from {calculator} calculator.sequence, # composite node.composite, algebra.composite # node ] + nodeMRO # all done return
def test(): """ Exercise the interface of variables """ # get the base node from the {calc} package from p2.calc.Node import Node as node # make a variable variable = node.variable(value=0) # access the value assert variable.getValue() == 0 # set the value variable.setValue(value=1) # verify it happened correctly assert variable.getValue() == 1 # all done return
def test(): """ Verify that probes get notified when the values of their nodes change """ # get the node class from p2.calc.Node import Node as node # make a probe that records the values of the monitored nodes class probe(node.probe): def flush(self, observable): self.nodes[observable] = observable.getValue() return self def __init__(self, **kwds): super().__init__(**kwds) self.nodes = {} return # make a probe p = probe() # make a node v = 80. production = node.variable(value=v) assert production.getValue() == v # insert the probe p.observe(observables=[production]) # set and check the value production.setValue(value=v) assert production.getValue() == v assert p.nodes[production] == v # once more v = 100. production.setValue(value=v) assert production.getValue() == v assert p.nodes[production] == v return
def test(): """ Verify that the {count} class hierarchy looks as expected """ # get the {calc} from p2.calc import calculator # and {algebraic} metaclasses from p2.algebraic import algebra # get the base node from the {calc} package from p2.calc.Node import Node as node # get the base node {mro} nodeMRO = node.mro() # get the count operator count = node.count # and its mro countMRO = count.mro() # verify the structure assert countMRO == [ # the user visible class node.count, # observer calculator.dependent, calculator.observer, # observable calculator.dependency, calculator.observable, calculator.reactor, # the evaluator calculator.count, # composite node.composite, algebra.composite # node ] + nodeMRO # all done return
def test(): """ Verify that attempting to substitute nodes in a complicated expression works as expected """ # get the base node from the {calc} package from p2.calc.Node import Node as node # assertions that involve node comparisons must be done very carefully if nodes have # {ordering} since then the equality test becomes a node. the current implementation of # {node} does not include {ordering}, so we should be ok with naive checks. # get the calculator from p2.calc import calculator # make sure node does not derive from {ordering} assert not issubclass(node, calculator.ordering) # make a few variables v1 = node.variable(value=1) v2 = node.variable(value=2) # compute their sum s = v1 + v2 # and their difference d = v1 - v2 # form the product p = s * d # verify that the values are computed correctly assert s.getValue() == 3 assert d.getValue() == -1 assert p.getValue() == (v1**2 - v2**2).getValue() # verify the node observers are as expected assert set(v1.observers) == {s, d} assert set(v2.observers) == {s, d} assert set(s.observers) == {p} assert set(d.observers) == {p} # now, replace {d} with {s} in {p} p.substitute(current=d, replacement=s) # the value of {s} should be unchanged assert s.getValue() == 3 # {d} as well assert d.getValue() == -1 # but {p} is different assert p.getValue() == ((v1 + v2)**2).getValue() # check the observers # nothing has changed for {v1} assert set(v1.observers) == {s, d} # nor {v2} assert set(v2.observers) == {s, d} # {s} is being observed by {p}, as before assert set(s.observers) == {p} # and {d} is not observed assert set(d.observers) == set() # all done return