|
@@ -1,23 +1,27 @@
|
|
|
+import re
|
|
|
+import logging
|
|
|
+from copy import deepcopy
|
|
|
from .util import enum, hash64
|
|
|
from collections import namedtuple
|
|
|
-from copy import deepcopy
|
|
|
-import re
|
|
|
-
|
|
|
-from CBD import naivelog
|
|
|
|
|
|
InputLink = namedtuple("InputLink", ["block", "output_port"])
|
|
|
Signal = namedtuple("Signal", ["time", "value"])
|
|
|
|
|
|
+# Error logging
|
|
|
+level = enum(WARNING=1, ERROR=2, CRITICAL=3)
|
|
|
+class LoggingHandler(logging.StreamHandler):
|
|
|
+ def emit(self, record):
|
|
|
+ super().emit(record)
|
|
|
+ if record.levelno >= logging.ERROR:
|
|
|
+ raise SystemExit(1)
|
|
|
|
|
|
-level = enum(WARNING=1, ERROR=2, FATAL=3)
|
|
|
-epsilon = 0.001
|
|
|
+logging.basicConfig(handlers=[LoggingHandler()])
|
|
|
|
|
|
-class Port:
|
|
|
|
|
|
- class Direction:
|
|
|
- IN = 0
|
|
|
- OUT = 1
|
|
|
+epsilon = 0.001
|
|
|
|
|
|
+class Port:
|
|
|
+ Direction = enum(IN=0, OUT=1)
|
|
|
def __init__(self, name, direction, block):
|
|
|
self.name = name
|
|
|
self.direction = direction
|
|
@@ -49,6 +53,12 @@ class Port:
|
|
|
def getHistory(self):
|
|
|
return self.__history
|
|
|
|
|
|
+ def getPreviousPortClosure(self):
|
|
|
+ inc = self.getIncoming().source
|
|
|
+ while inc.getIncoming() is not None:
|
|
|
+ inc = inc.getIncoming().source
|
|
|
+ return inc
|
|
|
+
|
|
|
def count(self):
|
|
|
return len(self.__history)
|
|
|
|
|
@@ -97,7 +107,7 @@ class BaseBlock:
|
|
|
if name != "":
|
|
|
self.setBlockName(name)
|
|
|
if re.match(r"[^a-zA-Z0-9_]", self.__block_name):
|
|
|
- logger = naivelog.getLogger("CBD")
|
|
|
+ logger = logging.getLogger("CBD")
|
|
|
logger.warning("Block names should only contain alphanumeric characters or underscores.")
|
|
|
|
|
|
# The output signals produced by this block are encoded in a dictionary.
|
|
@@ -462,6 +472,11 @@ class CBD(BaseBlock):
|
|
|
ignore (iter): Block class names to ignore in the flattening. When :code:`None`,
|
|
|
no blocks are ignored. Defaults to :code:`None`.
|
|
|
psep (str): The path separator to use. Defaults to :code:`"."`.
|
|
|
+
|
|
|
+ Note:
|
|
|
+ When an empty CBD block is encountered during flattening, this block will be removed from
|
|
|
+ the resulting flattened model. Add it to the :attr:`ignore` iterable to prevent such a
|
|
|
+ removal.
|
|
|
"""
|
|
|
if ignore is None: ignore = []
|
|
|
|
|
@@ -475,13 +490,13 @@ class CBD(BaseBlock):
|
|
|
for port in block.getInputPorts() + block.getOutputPorts():
|
|
|
source = port.getIncoming().source
|
|
|
Port.disconnect(source, port)
|
|
|
- for conn in port.getOutgoing():
|
|
|
+ outgoing = port.getOutgoing()[:]
|
|
|
+ for conn in outgoing:
|
|
|
target = conn.target
|
|
|
Port.disconnect(port, target)
|
|
|
self.addConnection(source.block, target.block, target.name, source.name)
|
|
|
self.removeBlock(block)
|
|
|
|
|
|
-
|
|
|
def getBlocks(self):
|
|
|
"""
|
|
|
Gets the list of blocks.
|
|
@@ -574,8 +589,8 @@ class CBD(BaseBlock):
|
|
|
if isinstance(block, (Clock, DummyClock)):
|
|
|
self.__clock = block
|
|
|
else:
|
|
|
- logger = naivelog.getLogger("CBD")
|
|
|
- logger.warning("Warning: did not add this block as it has the same name %s as an already existing block/port" % block.getBlockName())
|
|
|
+ logger = logging.getLogger("CBD")
|
|
|
+ logger.warning("Warning: did not add this block as it has the same name '%s' as an already existing block/port" % block.getBlockName())
|
|
|
|
|
|
def removeBlock(self, block):
|
|
|
"""
|
|
@@ -635,8 +650,8 @@ class CBD(BaseBlock):
|
|
|
block = self.getBlockByName(block)
|
|
|
block.unlinkInput(input_port_name)
|
|
|
|
|
|
- def findBlock(self, path, sep='.'):
|
|
|
- """Obtain a block in a submodel of this CBD.
|
|
|
+ def find(self, path, sep='.'):
|
|
|
+ """Obtain a block/port in a submodel of this CBD.
|
|
|
|
|
|
Args:
|
|
|
path (str): The path of the block to find. Empty string for the current block,
|
|
@@ -645,13 +660,13 @@ class CBD(BaseBlock):
|
|
|
sep (str): The path separator to use. Defaults to :code:`.`
|
|
|
|
|
|
Returns:
|
|
|
- The block that corresponds to the given path and the path itself.
|
|
|
+ The block that corresponds to the given path and the path to the block itself.
|
|
|
|
|
|
- .. note:: The block that will be returned has a different path than the path provided
|
|
|
+ .. note:: The block/port that will be returned has a different path than the path provided
|
|
|
in this function call. This is because this function assumes you already have
|
|
|
a path to the CBD you call it on. For instance, if this CBD contains a child
|
|
|
called :code:`child`, which has a :code:`grandchild` block in its turn, calling
|
|
|
- findBlock on the :class:`child` to locate the :code:`grandchild` only needs
|
|
|
+ find on the :class:`child` to locate the :code:`grandchild` only needs
|
|
|
:code:`grandchild` to be passed as a path. If the function is called on the
|
|
|
current CBD block instead, :code:`child.grandchild` is required to obtain the
|
|
|
same block.
|
|
@@ -662,6 +677,12 @@ class CBD(BaseBlock):
|
|
|
for p in path.split(sep):
|
|
|
if p in cur.__blocksDict:
|
|
|
cur = cur.getBlockByName(p)
|
|
|
+ elif p in cur.getInputPortNames():
|
|
|
+ cur = cur.getInputPortByName(p)
|
|
|
+ path = cur.block.getPath()
|
|
|
+ elif p in cur.getOutputPortNames():
|
|
|
+ cur = cur.getOutputPortByName(p)
|
|
|
+ path = cur.block.getPath()
|
|
|
else:
|
|
|
raise ValueError("Cannot find block '{}' in '{}'.".format(p, cur.getPath()))
|
|
|
return cur, path
|
|
@@ -740,7 +761,7 @@ class CBD(BaseBlock):
|
|
|
:code:`False`, the identifier will start at 1 and
|
|
|
no hashing will be done. Defaults to :code:`False`.
|
|
|
"""
|
|
|
- names = set([x.getBlockName() for x in self.getBlocks()])
|
|
|
+ names = set([x.getBlockName() for x in self.getBlocks()] + self.getInputPortNames() + self.getOutputPortNames())
|
|
|
uid = 1
|
|
|
if hash:
|
|
|
uid = id(self)
|