beremiz

7e61baa047f0
Parents c02818d7e29f
Children a39c2918c015
clean-up: fix PEP8 E302 expected 2 blank lines, found 1
  • +1 -0
    Beremiz.py
  • +7 -0
    BeremizIDE.py
  • +9 -0
    Beremiz_service.py
  • +1 -0
    CodeFileTreeNode.py
  • +1 -0
    ConfigTreeNode.py
  • +12 -1
    IDEFrame.py
  • +1 -0
    NativeLib.py
  • +32 -10
    PLCControler.py
  • +7 -2
    PLCGenerator.py
  • +5 -0
    PLCOpenEditor.py
  • +1 -0
    POULibrary.py
  • +5 -0
    ProjectController.py
  • +2 -0
    c_ext/CFileEditor.py
  • +1 -0
    c_ext/c_ext.py
  • +1 -0
    canfestival/NetworkEditor.py
  • +2 -0
    canfestival/SlaveEditor.py
  • +6 -0
    canfestival/canfestival.py
  • +4 -0
    canfestival/config_utils.py
  • +1 -0
    connectors/PYRO/__init__.py
  • +2 -0
    connectors/WAMP/__init__.py
  • +1 -0
    controls/CustomEditableListBox.py
  • +1 -0
    controls/CustomGrid.py
  • +2 -0
    controls/CustomStyledTextCtrl.py
  • +1 -0
    controls/CustomTable.py
  • +3 -3
    controls/CustomToolTip.py
  • +4 -0
    controls/CustomTree.py
  • +8 -7
    controls/DebugVariablePanel/DebugVariableGraphicViewer.py
  • +4 -4
    controls/DebugVariablePanel/DebugVariableItem.py
  • +9 -7
    controls/DebugVariablePanel/DebugVariablePanel.py
  • +6 -7
    controls/DebugVariablePanel/DebugVariableTextViewer.py
  • +4 -4
    controls/DebugVariablePanel/DebugVariableViewer.py
  • +3 -3
    controls/DebugVariablePanel/GraphButton.py
  • +2 -0
    controls/DurationCellEditor.py
  • +1 -0
    controls/EnhancedStatusBar.py
  • +3 -0
    controls/FolderTree.py
  • +6 -6
    controls/LibraryPanel.py
  • +2 -0
    controls/LocationCellEditor.py
  • +5 -0
    controls/LogViewer.py
  • +3 -0
    controls/PouInstanceVariablesPanel.py
  • +1 -0
    controls/ProjectPropertiesPanel.py
  • +2 -0
    controls/SearchResultPanel.py
  • +2 -0
    controls/TextCtrlAutoComplete.py
  • +6 -0
    controls/VariablePanel.py
  • +1 -0
    dialogs/AboutDialog.py
  • +4 -0
    dialogs/ActionBlockDialog.py
  • +1 -0
    dialogs/ArrayTypeDialog.py
  • +4 -4
    dialogs/BlockPreviewDialog.py
  • +3 -0
    dialogs/BrowseLocationsDialog.py
  • +4 -4
    dialogs/ConnectionDialog.py
  • +2 -0
    dialogs/DiscoveryDialog.py
  • +1 -0
    dialogs/DurationEditorDialog.py
  • +5 -4
    dialogs/FBDBlockDialog.py
  • +4 -4
    dialogs/FBDVariableDialog.py
  • +1 -0
    dialogs/FindInPouDialog.py
  • +7 -0
    dialogs/ForceVariableDialog.py
  • +4 -4
    dialogs/LDElementDialog.py
  • +4 -5
    dialogs/LDPowerRailDialog.py
  • +2 -0
    dialogs/PouActionDialog.py
  • +3 -0
    dialogs/PouDialog.py
  • +1 -0
    dialogs/PouNameDialog.py
  • +2 -0
    dialogs/PouTransitionDialog.py
  • +1 -0
    dialogs/ProjectDialog.py
  • +4 -4
    dialogs/SFCDivergenceDialog.py
  • +4 -4
    dialogs/SFCStepDialog.py
  • +1 -0
    dialogs/SFCStepNameDialog.py
  • +4 -4
    dialogs/SFCTransitionDialog.py
  • +2 -0
    dialogs/SearchInProjectDialog.py
  • +4 -0
    docutil/dochtml.py
  • +4 -0
    docutil/docpdf.py
  • +4 -0
    docutil/docsvg.py
  • +1 -0
    editors/CodeFileEditor.py
  • +2 -0
    editors/ConfTreeNodeEditor.py
  • +5 -0
    editors/DataTypeEditor.py
  • +4 -4
    editors/DebugViewer.py
  • +1 -0
    editors/EditorPanel.py
  • +1 -0
    editors/FileManagementPanel.py
  • +1 -0
    editors/IECCodeViewer.py
  • +8 -4
    editors/LDViewer.py
  • +1 -0
    editors/ProjectNodeEditor.py
  • +4 -0
    editors/ResourceEditor.py
  • +2 -0
    editors/TextViewer.py
  • +18 -4
    editors/Viewer.py
  • +10 -5
    graphics/DebugDataConsumer.py
  • +10 -9
    graphics/FBD_Objects.py
  • +53 -28
    graphics/GraphicCommons.py
  • +9 -9
    graphics/LD_Objects.py
  • +3 -3
    graphics/RubberBand.py
  • +17 -17
    graphics/SFC_Objects.py
  • +3 -3
    graphics/ToolTipProducer.py
  • +8 -24
    i18n/mki18n.py
  • +1 -0
    plcopen/definitions.py
  • +73 -3
    plcopen/plcopen.py
  • +36 -28
    plcopen/structures.py
  • +1 -0
    py_ext/PythonEditor.py
  • +1 -0
    py_ext/PythonFileCTNMixin.py
  • +2 -0
    py_ext/py_ext.py
  • +8 -0
    runtime/NevowServer.py
  • +4 -0
    runtime/PLCObject.py
  • +1 -0
    runtime/ServicePublisher.py
  • +7 -0
    runtime/WampClient.py
  • +18 -3
    svgui/pyjs/build.py
  • +10 -0
    svgui/pyjs/jsonrpc/django/jsonrpc.py
  • +1 -0
    svgui/pyjs/jsonrpc/jsonrpc.py
  • +1 -0
    svgui/pyjs/jsonrpc/web2py/jsonrpc.py
  • +48 -2
    svgui/pyjs/lib/pyjslib.py
  • +8 -0
    svgui/pyjs/lib/sys.py
  • +12 -0
    svgui/pyjs/pyjs.py
  • +2 -0
    svgui/svgui.py
  • +10 -0
    svgui/svgui_server.py
  • +2 -0
    svgui/svguilib.py
  • +1 -0
    targets/Generic/__init__.py
  • +1 -0
    targets/Linux/__init__.py
  • +1 -0
    targets/Win32/__init__.py
  • +1 -0
    targets/Xenomai/__init__.py
  • +7 -0
    targets/__init__.py
  • +1 -0
    targets/toolchain_gcc.py
  • +1 -0
    targets/toolchain_makefile.py
  • +6 -0
    targets/typemapping.py
  • +3 -0
    util/BitmapLibrary.py
  • +1 -0
    util/MiniTextControler.py
  • +1 -0
    util/ProcessLogger.py
  • +2 -0
    util/TranslationCatalogs.py
  • +15 -0
    util/Zeroconf.py
  • +4 -1
    util/misc.py
  • +3 -0
    util/paths.py
  • +3 -0
    version.py
  • +1 -0
    wxglade_hmi/wxglade_hmi.py
  • +57 -16
    xmlclass/xmlclass.py
  • +25 -7
    xmlclass/xsdschema.py
  • --- a/Beremiz.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/Beremiz.py Mon Aug 14 23:27:15 2017 +0300
    @@ -31,6 +31,7 @@
    import __builtin__
    import util.paths as paths
    +
    class BeremizIDELauncher:
    def __init__(self):
    self.updateinfo_url = None
    --- a/BeremizIDE.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/BeremizIDE.py Mon Aug 14 23:27:15 2017 +0300
    @@ -37,6 +37,7 @@
    beremiz_dir = paths.AbsDir(__file__)
    +
    def Bpath(*args):
    return os.path.join(beremiz_dir,*args)
    @@ -88,6 +89,8 @@
    MainThread = currentThread().ident
    REFRESH_PERIOD = 0.1
    from time import time as gettime
    +
    +
    class LogPseudoFile:
    """ Base class for file like objects to facilitate StdOut for the Shell."""
    def __init__(self, output, risecall):
    @@ -213,6 +216,7 @@
    EncodeFileSystemPath, DecodeFileSystemPath
    from util.BitmapLibrary import GetBitmap
    +
    class Beremiz(IDEFrame):
    def _init_utils(self):
    @@ -1086,6 +1090,7 @@
    Max_Traceback_List_Size = 20
    +
    def Display_Exception_Dialog(e_type, e_value, e_tb, bug_report_path):
    trcbck_lst = []
    for i,line in enumerate(traceback.extract_tb(e_tb)):
    @@ -1124,6 +1129,7 @@
    return res
    +
    def get_last_traceback(tb):
    while tb.tb_next:
    tb = tb.tb_next
    @@ -1136,6 +1142,7 @@
    ignored_exceptions = [] # a problem with a line in a module is only reported once per session
    +
    def AddExceptHook(path, app_version='[No version]'):#, ignored_exceptions=[]):
    def save_bug_report(e_type, e_value, e_traceback, bug_report_path,date):
    --- a/Beremiz_service.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/Beremiz_service.py Mon Aug 14 23:27:15 2017 +0300
    @@ -28,6 +28,7 @@
    import getopt
    from threading import Thread
    +
    def usage():
    print """
    Usage of Beremiz PLC execution service :\n
    @@ -116,9 +117,11 @@
    if __name__ == '__main__':
    __builtin__.__dict__['_'] = lambda x: x
    +
    def Bpath(*args):
    return os.path.join(beremiz_dir,*args)
    +
    def SetupI18n():
    # Import module for internationalization
    import gettext
    @@ -379,6 +382,7 @@
    if not os.path.isdir(WorkingDir):
    os.mkdir(WorkingDir)
    +
    def default_evaluator(tocall, *args, **kwargs):
    try:
    res=(tocall(*args,**kwargs), None)
    @@ -386,6 +390,7 @@
    res=(None, sys.exc_info())
    return res
    +
    class Server():
    def __init__(self, servicename, ip_addr, port,
    workdir, argv, autostart=False,
    @@ -528,6 +533,8 @@
    # Exception hooks s
    import threading
    import traceback
    +
    +
    def LogException(*exp):
    if pyroserver.plcobj is not None:
    pyroserver.plcobj.LogMessage(0,'\n'.join(traceback.format_exception(*exp)))
    @@ -535,6 +542,8 @@
    traceback.print_exception(*exp)
    sys.excepthook = LogException
    +
    +
    def installThreadExcepthook():
    init_old = threading.Thread.__init__
    def init(self, *args, **kwargs):
    --- a/CodeFileTreeNode.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/CodeFileTreeNode.py Mon Aug 14 23:27:15 2017 +0300
    @@ -82,6 +82,7 @@
    SECTION_TAG_ELEMENT = "<xsd:element name=\"%s\" type=\"CodeText\"/>"
    +
    class CodeFile:
    CODEFILE_NAME = "CodeFile"
    --- a/ConfigTreeNode.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/ConfigTreeNode.py Mon Aug 14 23:27:15 2017 +0300
    @@ -57,6 +57,7 @@
    NameTypeSeparator = '@'
    XSDSchemaErrorMessage = _("{a1} XML file doesn't follow XSD schema at line {a2}:\n{a3}")
    +
    class ConfigTreeNode:
    """
    This class is the one that define confnodes.
    --- a/IDEFrame.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/IDEFrame.py Mon Aug 14 23:27:15 2017 +0300
    @@ -193,19 +193,24 @@
    import base64
    +
    def EncodeFileSystemPath(path, use_base64=True):
    path = path.encode(sys.getfilesystemencoding())
    if use_base64:
    return base64.encodestring(path)
    return path
    +
    def DecodeFileSystemPath(path, is_base64=True):
    if is_base64:
    path = base64.decodestring(path)
    return unicode(path, sys.getfilesystemencoding())
    -# Compatibility function for wx versions < 2.6
    +
    def AppendMenu(parent, help, id, kind, text):
    + """
    + Compatibility function for wx versions < 2.6
    + """
    if wx.VERSION >= (2, 6, 0):
    parent.Append(help=help, id=id, kind=kind, text=text)
    else:
    @@ -215,6 +220,7 @@
    POUINSTANCEVARIABLESPANEL, LIBRARYTREE, SCALING, PAGETITLES
    ] = range(10)
    +
    def GetShortcutKeyCallbackFunction(viewer_function):
    def ShortcutKeyFunction(self, event):
    control = self.FindFocus()
    @@ -226,6 +232,7 @@
    control.ProcessEvent(event)
    return ShortcutKeyFunction
    +
    def GetDeleteElementFunction(remove_function, parent_type=None, check_function=None):
    def DeleteElementFunction(self, selected):
    name = self.ProjectTree.GetItemText(selected)
    @@ -245,6 +252,7 @@
    TAB_BORDER = 7
    NOTEBOOK_BORDER = 2
    +
    def SimplifyTabLayout(tabs, rect):
    for tab in tabs:
    if tab["pos"][0] == rect.x:
    @@ -278,6 +286,7 @@
    return True
    return False
    +
    def ComputeTabsLayout(tabs, rect):
    if len(tabs) == 0:
    return tabs
    @@ -323,6 +332,7 @@
    UNEDITABLE_NAMES_DICT = dict([(_(name), name) for name in UNEDITABLE_NAMES])
    +
    class IDEFrame(wx.Frame):
    # Compatibility function for wx versions < 2.6
    @@ -2549,6 +2559,7 @@
    UPPER_DIV = lambda x, y: (x / y) + {True : 0, False : 1}[(x % y) == 0]
    +
    class GraphicPrintout(wx.Printout):
    def __init__(self, viewer, page_size, margins, preview = False):
    wx.Printout.__init__(self)
    --- a/NativeLib.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/NativeLib.py Mon Aug 14 23:27:15 2017 +0300
    @@ -27,6 +27,7 @@
    import util.paths as paths
    from POULibrary import POULibrary
    +
    class NativeLibrary(POULibrary):
    def GetLibraryPath(self):
    return paths.AbsNeighbourFile(__file__, "NativeLib.xml")
    --- a/PLCControler.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/PLCControler.py Mon Aug 14 23:27:15 2017 +0300
    @@ -94,6 +94,7 @@
    ScriptDirectory = paths.AbsDir(__file__)
    +
    def GetUneditableNames():
    _ = lambda x:x
    return [_("User-defined POUs"), _("Functions"), _("Function Blocks"),
    @@ -108,6 +109,7 @@
    # Helper object for loading library in xslt stylesheets
    #-------------------------------------------------------------------------------
    +
    class LibraryResolver(etree.Resolver):
    def __init__(self, controller, debug=False):
    @@ -136,6 +138,7 @@
    _StringValue = lambda x: x
    _BoolValue = lambda x: x in ["true", "0"]
    +
    def _translate_args(translations, args):
    return [translate(arg[0]) if len(arg) > 0 else None
    for translate, arg in
    @@ -145,6 +148,7 @@
    # Helpers object for generating pou var list
    #-------------------------------------------------------------------------------
    +
    class _VariableInfos(object):
    __slots__ = ["Name", "Class", "Option", "Location", "InitialValue",
    "Edit", "Documentation", "Type", "Tree", "Number"]
    @@ -154,6 +158,7 @@
    def copy(self):
    return _VariableInfos(*[getattr(self, attr) for attr in self.__slots__])
    +
    class VariablesInfosFactory:
    def __init__(self, variables):
    @@ -194,6 +199,7 @@
    # Helpers object for generating pou variable instance list
    #-------------------------------------------------------------------------------
    +
    def class_extraction(value):
    class_type = {
    "configuration": ITEM_CONFIGURATION,
    @@ -214,6 +220,7 @@
    return None
    +
    class _VariablesTreeItemInfos(object):
    __slots__ = ["name", "var_class", "type", "edit", "debug", "variables"]
    def __init__(self, *args):
    @@ -222,6 +229,7 @@
    def copy(self):
    return _VariableTreeItem(*[getattr(self, attr) for attr in self.__slots__])
    +
    class VariablesTreeInfosFactory:
    def __init__(self):
    @@ -247,6 +255,7 @@
    # Helpers object for generating instances path list
    #-------------------------------------------------------------------------------
    +
    class InstancesPathFactory:
    def __init__(self, instances):
    @@ -259,6 +268,7 @@
    # Helpers object for generating instance tagname
    #-------------------------------------------------------------------------------
    +
    class InstanceTagName:
    def __init__(self, controller):
    @@ -355,6 +365,7 @@
    _ConnectionLinkInfos = namedtuple("ConnectionLinkInfos",
    ["refLocalId", "formalParameter", "points"])
    +
    class _ActionInfos(object):
    __slots__ = ["qualifier", "type", "value", "duration", "indicator"]
    def __init__(self, *args):
    @@ -363,6 +374,7 @@
    def copy(self):
    return _ActionInfos(*[getattr(self, attr) for attr in self.__slots__])
    +
    class BlockInstanceFactory:
    def __init__(self, block_instances):
    @@ -438,13 +450,16 @@
    # Length of the buffer
    UNDO_BUFFER_LENGTH = 20
    -"""
    -Class implementing a buffer of changes made on the current editing model
    -"""
    +
    class UndoBuffer:
    -
    - # Constructor initialising buffer
    + """
    + Class implementing a buffer of changes made on the current editing model
    + """
    +
    def __init__(self, currentstate, issaved = False):
    + """
    + Constructor initialising buffer
    + """
    self.Buffer = []
    self.CurrentIndex = -1
    self.MinIndex = -1
    @@ -466,8 +481,11 @@
    else:
    self.LastSave = -1
    - # Add a new state in buffer
    +
    def Buffering(self, currentstate):
    + """
    + Add a new state in buffer
    + """
    self.CurrentIndex = (self.CurrentIndex + 1) % UNDO_BUFFER_LENGTH
    self.Buffer[self.CurrentIndex] = currentstate
    # Actualising buffer limits
    @@ -479,8 +497,11 @@
    self.MinIndex = (self.MinIndex + 1) % UNDO_BUFFER_LENGTH
    self.MinIndex = max(self.MinIndex, 0)
    - # Return current state of buffer
    +
    def Current(self):
    + """
    + Return current state of buffer
    + """
    return self.Buffer[self.CurrentIndex]
    # Change current state to previous in buffer and return new current state
    @@ -518,10 +539,11 @@
    # Controler for PLCOpenEditor
    #-------------------------------------------------------------------------------
    -"""
    -Class which controls the operations made on the plcopen model and answers to view requests
    -"""
    +
    class PLCControler:
    + """
    + Class which controls the operations made on the plcopen model and answers to view requests
    + """
    # Create a new PLCControler
    def __init__(self):
    --- a/PLCGenerator.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/PLCGenerator.py Mon Aug 14 23:27:15 2017 +0300
    @@ -45,8 +45,9 @@
    "VAR_INOUT": "var_inout",
    }
    -# Helper function for reindenting text
    +
    def ReIndentText(text, nb_spaces):
    + """ Helper function for reindenting text """
    compute = ""
    lines = text.splitlines()
    if len(lines) > 0:
    @@ -67,6 +68,7 @@
    compute += "\n"
    return compute
    +
    def SortInstances(a, b):
    ax, ay = int(a.getx()), int(a.gety())
    bx, by = int(b.getx()), int(b.gety())
    @@ -75,8 +77,9 @@
    else:
    return cmp(ay, by)
    -# Helper for emulate join on element list
    +
    def JoinList(separator, mylist):
    + """ Helper for emulate join on element list """
    if len(mylist) > 0 :
    return reduce(lambda x, y: x + separator + y, mylist)
    else :
    @@ -500,6 +503,7 @@
    TransitionObjClass = PLCOpenParser.GetElementClass("transition", "transitions")
    ActionObjClass = PLCOpenParser.GetElementClass("action", "actions")
    +
    class PouProgramGenerator:
    # Create a new POU program generator
    @@ -1658,6 +1662,7 @@
    program += [("END_%s\n\n" % self.Type, ())]
    return program
    +
    def GenerateCurrentProgram(controler, project, errors, warnings):
    generator = ProgramGenerator(controler, project, errors, warnings)
    generator.GenerateProgram()
    --- a/PLCOpenEditor.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/PLCOpenEditor.py Mon Aug 14 23:27:15 2017 +0300
    @@ -94,6 +94,7 @@
    [ID_PLCOPENEDITORFILEMENUGENERATE,
    ] = [wx.NewId() for _init_coll_FileMenu_Items in range(1)]
    +
    class PLCOpenEditor(IDEFrame):
    # Compatibility function for wx versions < 2.6
    @@ -403,6 +404,7 @@
    Max_Traceback_List_Size = 20
    +
    def Display_Exception_Dialog(e_type,e_value,e_tb):
    trcbck_lst = []
    for i,line in enumerate(traceback.extract_tb(e_tb)):
    @@ -441,11 +443,13 @@
    return res
    +
    def Display_Error_Dialog(e_value):
    message = wx.MessageDialog(None, str(e_value), _("Error"), wx.OK|wx.ICON_ERROR)
    message.ShowModal()
    message.Destroy()
    +
    def get_last_traceback(tb):
    while tb.tb_next:
    tb = tb.tb_next
    @@ -458,6 +462,7 @@
    ignored_exceptions = [] # a problem with a line in a module is only reported once per session
    +
    def AddExceptHook(path, app_version='[No version]'):#, ignored_exceptions=[]):
    def handle_exception(e_type, e_value, e_traceback):
    --- a/POULibrary.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/POULibrary.py Mon Aug 14 23:27:15 2017 +0300
    @@ -24,6 +24,7 @@
    from weakref import ref
    +
    class POULibrary:
    def __init__(self, CTR, LibName, TypeStack):
    from PLCControler import PLCControler
    --- a/ProjectController.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/ProjectController.py Mon Aug 14 23:27:15 2017 +0300
    @@ -67,6 +67,7 @@
    ITEM_CONFNODE = 25
    +
    def ExtractChildrenTypesFromCatalog(catalog):
    children_types = []
    for n,d,h,c in catalog:
    @@ -76,6 +77,7 @@
    children_types.append((n, GetClassImporter(c), d))
    return children_types
    +
    def ExtractMenuItemsFromCatalog(catalog):
    menu_items = []
    for n,d,h,c in catalog:
    @@ -86,9 +88,11 @@
    menu_items.append((n, d, h, children))
    return menu_items
    +
    def GetAddMenuItems():
    return ExtractMenuItemsFromCatalog(features.catalog)
    +
    class Iec2CSettings():
    def __init__(self):
    self.iec2c = None
    @@ -170,6 +174,7 @@
    iec2c_cfg = Iec2CSettings()
    +
    class ProjectController(ConfigTreeNode, PLCControler):
    """
    This class define Root object of the confnode tree.
    --- a/c_ext/CFileEditor.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/c_ext/CFileEditor.py Mon Aug 14 23:27:15 2017 +0300
    @@ -27,6 +27,7 @@
    from controls.CustomStyledTextCtrl import faces
    from editors.CodeFileEditor import CodeFileEditor, CodeEditor
    +
    class CppEditor(CodeEditor):
    KEYWORDS = ["asm", "auto", "bool", "break", "case", "catch", "char", "class",
    @@ -57,6 +58,7 @@
    # CFileEditor Main Frame Class
    #-------------------------------------------------------------------------------
    +
    class CFileEditor(CodeFileEditor):
    CONFNODEEDITOR_TABS = [
    --- a/c_ext/c_ext.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/c_ext/c_ext.py Mon Aug 14 23:27:15 2017 +0300
    @@ -27,6 +27,7 @@
    from CFileEditor import CFileEditor
    from CodeFileTreeNode import CodeFile
    +
    class CFile(CodeFile):
    XSD = """<?xml version="1.0" encoding="ISO-8859-1" ?>
    <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    --- a/canfestival/NetworkEditor.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/canfestival/NetworkEditor.py Mon Aug 14 23:27:15 2017 +0300
    @@ -45,6 +45,7 @@
    ID_NETWORKEDITORADDMENUMAPVARIABLE, ID_NETWORKEDITORADDMENUUSERTYPE,
    ] = [wx.NewId() for _init_coll_AddMenu_Items in range(6)]
    +
    class NetworkEditor(ConfTreeNodeEditor, NetworkEditorTemplate):
    ID = ID_NETWORKEDITOR
    --- a/canfestival/SlaveEditor.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/canfestival/SlaveEditor.py Mon Aug 14 23:27:15 2017 +0300
    @@ -38,6 +38,7 @@
    ID_SLAVEEDITORADDMENUMAPVARIABLE, ID_SLAVEEDITORADDMENUUSERTYPE,
    ] = [wx.NewId() for _init_coll_AddMenu_Items in range(6)]
    +
    class SlaveEditor(ConfTreeNodeEditor, NodeEditorTemplate):
    CONFNODEEDITOR_TABS = [
    @@ -97,6 +98,7 @@
    self.ParentWindow.RefreshEditMenu()
    self.ParentWindow.RefreshPageTitles()
    +
    class MasterViewer(SlaveEditor):
    SHOW_BASE_PARAMS = False
    SHOW_PARAMS = False
    --- a/canfestival/canfestival.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/canfestival/canfestival.py Mon Aug 14 23:27:15 2017 +0300
    @@ -60,6 +60,7 @@
    # Location Tree Helper
    #--------------------------------------------------
    +
    def GetSlaveLocationTree(slave_node, current_location, name):
    entries = []
    for index, subindex, size, entry_name in slave_node.GetMapVariableList():
    @@ -86,6 +87,7 @@
    # SLAVE
    #--------------------------------------------------
    +
    class _SlaveCTN(NodeManager):
    XSD = """<?xml version="1.0" encoding="ISO-8859-1" ?>
    <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    @@ -246,6 +248,7 @@
    # MASTER
    #--------------------------------------------------
    +
    class MiniNodeManager(NodeManager):
    def __init__(self, parent, filepath, fullname):
    @@ -273,6 +276,7 @@
    ConfNodeMethods = []
    +
    class _NodeManager(NodeManager):
    def __init__(self, parent, *args, **kwargs):
    @@ -288,6 +292,7 @@
    def GetCurrentNodeID(self):
    return self.Parent.CanFestivalNode.getNodeId()
    +
    class _NodeListCTN(NodeList):
    XSD = """<?xml version="1.0" encoding="ISO-8859-1" ?>
    <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    @@ -459,6 +464,7 @@
    def GetBufferState(self):
    return self.Manager.GetCurrentBufferState()
    +
    class RootClass:
    XSD = """<?xml version="1.0" encoding="ISO-8859-1" ?>
    <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    --- a/canfestival/config_utils.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/canfestival/config_utils.py Mon Aug 14 23:27:15 2017 +0300
    @@ -50,6 +50,7 @@
    # Specific exception for PDO mapping errors
    #-------------------------------------------------------------------------------
    +
    class PDOmappingException(Exception):
    pass
    @@ -137,6 +138,7 @@
    dcfdata += [LE_to_BE(idx, 2) + LE_to_BE(0x01, 1) + LE_to_BE(0x04, 4) + LE_to_BE(cobid, 4)]
    return "".join(dcfdata), len(dcfdata)
    +
    class ConciseDCFGenerator:
    def __init__(self, nodelist, nodename):
    @@ -592,6 +594,7 @@
    # Add variable to pointed variables
    self.PointedVariables[(mapvariableidx, nbsubentries)] = "%s_%s" % (indexname, subindexname)
    +
    def GenerateConciseDCF(locations, current_location, nodelist, sync_TPDOs, nodename):
    """
    Fills a CanFestival network editor model, with DCF with requested PDO mappings.
    @@ -613,6 +616,7 @@
    pointers.update(LocalODPointers(locations, current_location, masternode))
    return masternode,pointers
    +
    def LocalODPointers(locations, current_location, slave):
    IECLocations = {}
    pointers = {}
    --- a/connectors/PYRO/__init__.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/connectors/PYRO/__init__.py Mon Aug 14 23:27:15 2017 +0300
    @@ -38,6 +38,7 @@
    # for connectors that do not support DNS-SD, this attribute can be omitted
    # or set to an empty list.
    +
    def PYRO_connector_factory(uri, confnodesroot):
    """
    This returns the connector to Pyro style PLCobject
    --- a/connectors/WAMP/__init__.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/connectors/WAMP/__init__.py Mon Aug 14 23:27:15 2017 +0300
    @@ -38,6 +38,7 @@
    _WampConnection = None
    _WampSessionEvent = Event()
    +
    class WampSession(wamp.ApplicationSession):
    def onJoin(self, details):
    global _WampSession, _WampSessionEvent
    @@ -56,6 +57,7 @@
    "GetPLCstatus" : ("Broken",None),
    "RemoteExec" : (-1, "RemoteExec script failed!")}
    +
    def WAMP_connector_factory(uri, confnodesroot):
    """
    WAMP://127.0.0.1:12345/path#realm#ID
    --- a/controls/CustomEditableListBox.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/controls/CustomEditableListBox.py Mon Aug 14 23:27:15 2017 +0300
    @@ -25,6 +25,7 @@
    import wx
    import wx.gizmos
    +
    class CustomEditableListBox(wx.gizmos.EditableListBox):
    def __init__(self, *args, **kwargs):
    --- a/controls/CustomGrid.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/controls/CustomGrid.py Mon Aug 14 23:27:15 2017 +0300
    @@ -25,6 +25,7 @@
    import wx
    import wx.grid
    +
    class CustomGrid(wx.grid.Grid):
    def __init__(self, *args, **kwargs):
    --- a/controls/CustomStyledTextCtrl.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/controls/CustomStyledTextCtrl.py Mon Aug 14 23:27:15 2017 +0300
    @@ -58,6 +58,7 @@
    wx.WXK_NUMPAD_PAGEDOWN,
    wx.WXK_NUMPAD_END]
    +
    def GetCursorPos(old, new):
    if old == "":
    return 0
    @@ -81,6 +82,7 @@
    else:
    return None
    +
    class CustomStyledTextCtrl(wx.stc.StyledTextCtrl):
    def __init__(self, *args, **kwargs):
    --- a/controls/CustomTable.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/controls/CustomTable.py Mon Aug 14 23:27:15 2017 +0300
    @@ -30,6 +30,7 @@
    else:
    ROW_HEIGHT = 28
    +
    class CustomTable(wx.grid.PyGridTableBase):
    """
    --- a/controls/CustomToolTip.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/controls/CustomToolTip.py Mon Aug 14 23:27:15 2017 +0300
    @@ -34,11 +34,11 @@
    # Custom ToolTip
    #-------------------------------------------------------------------------------
    -"""
    -Class that implements a custom tool tip
    -"""
    class CustomToolTip(wx.PopupWindow):
    + """
    + Class that implements a custom tool tip
    + """
    def __init__(self, parent, tip, restricted=True):
    """
    --- a/controls/CustomTree.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/controls/CustomTree.py Mon Aug 14 23:27:15 2017 +0300
    @@ -30,6 +30,7 @@
    # Customize CustomTreeItem for adding icon on item left
    CT.GenericTreeItem._ExtraImage = None
    +
    def SetExtraImage(self, image):
    self._type = (1 if image is not None else 0)
    self._ExtraImage = image
    @@ -37,12 +38,15 @@
    CT.GenericTreeItem.SetExtraImage = SetExtraImage
    _DefaultGetCurrentCheckedImage = CT.GenericTreeItem.GetCurrentCheckedImage
    +
    +
    def GetCurrentCheckedImage(self):
    if self._ExtraImage is not None:
    return self._ExtraImage
    return _DefaultGetCurrentCheckedImage(self)
    CT.GenericTreeItem.GetCurrentCheckedImage = GetCurrentCheckedImage
    +
    class CustomTree(CT.CustomTreeCtrl):
    def __init__(self, *args, **kwargs):
    --- a/controls/DebugVariablePanel/DebugVariableGraphicViewer.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/controls/DebugVariablePanel/DebugVariableGraphicViewer.py Mon Aug 14 23:27:15 2017 +0300
    @@ -67,6 +67,7 @@
    # Debug Variable Graphic Viewer Helpers
    #-------------------------------------------------------------------------------
    +
    def merge_ranges(ranges):
    """
    Merge variables data range in a list to return a range of minimal min range
    @@ -107,12 +108,12 @@
    # Debug Variable Graphic Viewer Drop Target
    #-------------------------------------------------------------------------------
    -"""
    -Class that implements a custom drop target class for Debug Variable Graphic
    -Viewer
    -"""
    class DebugVariableGraphicDropTarget(wx.TextDropTarget):
    + """
    + Class that implements a custom drop target class for Debug Variable Graphic
    + Viewer
    + """
    def __init__(self, parent, window):
    """
    @@ -238,11 +239,11 @@
    # Debug Variable Graphic Viewer Class
    #-------------------------------------------------------------------------------
    -"""
    -Class that implements a Viewer that display variable values as a graphs
    -"""
    class DebugVariableGraphicViewer(DebugVariableViewer, FigureCanvas):
    + """
    + Class that implements a Viewer that display variable values as a graphs
    + """
    def __init__(self, parent, window, items, graph_type):
    """
    --- a/controls/DebugVariablePanel/DebugVariableItem.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/controls/DebugVariablePanel/DebugVariableItem.py Mon Aug 14 23:27:15 2017 +0300
    @@ -38,12 +38,12 @@
    # Debug Variable Item Class
    #-------------------------------------------------------------------------------
    -"""
    -Class that implements an element that consumes debug values for PLC variable and
    -stores received values for displaying them in graphic panel or table
    -"""
    class DebugVariableItem(DebugDataConsumer):
    + """
    + Class that implements an element that consumes debug values for PLC variable and
    + stores received values for displaying them in graphic panel or table
    + """
    def __init__(self, parent, variable, store_data=False):
    """
    --- a/controls/DebugVariablePanel/DebugVariablePanel.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/controls/DebugVariablePanel/DebugVariablePanel.py Mon Aug 14 23:27:15 2017 +0300
    @@ -58,10 +58,12 @@
    # Scrollbar increment in pixel
    SCROLLBAR_UNIT = 10
    +
    def compute_mask(x, y):
    return [(xp if xp == yp else "*")
    for xp, yp in zip(x, y)]
    +
    def NextTick(variables):
    next_tick = None
    for item, data in variables:
    @@ -78,12 +80,12 @@
    # Debug Variable Graphic Panel Drop Target
    #-------------------------------------------------------------------------------
    -"""
    -Class that implements a custom drop target class for Debug Variable Graphic
    -Panel
    -"""
    class DebugVariableDropTarget(wx.TextDropTarget):
    + """
    + Class that implements a custom drop target class for Debug Variable Graphic
    + Panel
    + """
    def __init__(self, window):
    """
    @@ -173,11 +175,11 @@
    # Debug Variable Graphic Panel Class
    #-------------------------------------------------------------------------------
    -"""
    -Class that implements a Viewer that display variable values as a graphs
    -"""
    class DebugVariablePanel(wx.Panel, DebugViewer):
    + """
    + Class that implements a Viewer that display variable values as a graphs
    + """
    def __init__(self, parent, producer, window):
    """
    --- a/controls/DebugVariablePanel/DebugVariableTextViewer.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/controls/DebugVariablePanel/DebugVariableTextViewer.py Mon Aug 14 23:27:15 2017 +0300
    @@ -34,11 +34,11 @@
    # Debug Variable Text Viewer Drop Target
    #-------------------------------------------------------------------------------
    -"""
    -Class that implements a custom drop target class for Debug Variable Text Viewer
    -"""
    class DebugVariableTextDropTarget(wx.TextDropTarget):
    + """
    + Class that implements a custom drop target class for Debug Variable Text Viewer
    + """
    def __init__(self, parent, window):
    """
    @@ -144,11 +144,10 @@
    # Debug Variable Text Viewer Class
    #-------------------------------------------------------------------------------
    -"""
    -Class that implements a Viewer that display variable values as a text
    -"""
    -
    class DebugVariableTextViewer(DebugVariableViewer, wx.Panel):
    + """
    + Class that implements a Viewer that display variable values as a text
    + """
    def __init__(self, parent, window, items=[]):
    """
    --- a/controls/DebugVariablePanel/DebugVariableViewer.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/controls/DebugVariablePanel/DebugVariableViewer.py Mon Aug 14 23:27:15 2017 +0300
    @@ -50,12 +50,12 @@
    # Base Debug Variable Viewer Class
    #-------------------------------------------------------------------------------
    -"""
    -Class that implements a generic viewer that display a list of variable values
    -This class has to be inherited to effectively display variable values
    -"""
    class DebugVariableViewer:
    + """
    + Class that implements a generic viewer that display a list of variable values
    + This class has to be inherited to effectively display variable values
    + """
    def __init__(self, window, items=[]):
    """
    --- a/controls/DebugVariablePanel/GraphButton.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/controls/DebugVariablePanel/GraphButton.py Mon Aug 14 23:27:15 2017 +0300
    @@ -30,11 +30,11 @@
    # Custom button for Graphic Viewer Class
    #-------------------------------------------------------------------------------
    -"""
    -Class that implements a custom button for graphic Viewer
    -"""
    class GraphButton():
    + """
    + Class that implements a custom button for graphic Viewer
    + """
    def __init__(self, x, y, bitmap, callback):
    """
    --- a/controls/DurationCellEditor.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/controls/DurationCellEditor.py Mon Aug 14 23:27:15 2017 +0300
    @@ -26,6 +26,7 @@
    from dialogs.DurationEditorDialog import DurationEditorDialog
    +
    class DurationCellControl(wx.PyControl):
    '''
    @@ -94,6 +95,7 @@
    def SetFocus(self):
    self.Duration.SetFocus()
    +
    class DurationCellEditor(wx.grid.PyGridCellEditor):
    '''
    Grid cell editor that uses DurationCellControl to display an edit button.
    --- a/controls/EnhancedStatusBar.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/controls/EnhancedStatusBar.py Mon Aug 14 23:27:15 2017 +0300
    @@ -80,6 +80,7 @@
    def __init__(self, widget, pos, horizontalalignment=ESB_ALIGN_CENTER_HORIZONTAL, verticalalignment=ESB_ALIGN_CENTER_VERTICAL):
    self.__dict__.update( locals() )
    +
    class EnhancedStatusBar(wx.StatusBar):
    def __init__(self, parent, id=wx.ID_ANY, style=wx.ST_SIZEGRIP,
    --- a/controls/FolderTree.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/controls/FolderTree.py Mon Aug 14 23:27:15 2017 +0300
    @@ -30,6 +30,7 @@
    DRIVE, FOLDER, FILE = range(3)
    +
    def sort_folder(x, y):
    if x[1] == y[1]:
    return cmp(x[0], y[0])
    @@ -38,6 +39,7 @@
    else:
    return 1
    +
    def splitpath(path):
    head, tail = os.path.split(path)
    if head == "":
    @@ -46,6 +48,7 @@
    return splitpath(head)
    return splitpath(head) + [tail]
    +
    class FolderTree(wx.Panel):
    def __init__(self, parent, folder, filter=None, editable=True):
    --- a/controls/LibraryPanel.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/controls/LibraryPanel.py Mon Aug 14 23:27:15 2017 +0300
    @@ -34,14 +34,14 @@
    # Library Panel
    #-------------------------------------------------------------------------------
    -"""
    -Class that implements a panel displaying a tree containing an hierarchical list
    -of functions and function blocks available in project an a search control for
    -quickly find one functions or function blocks in this list and a text control
    -displaying informations about selected functions or function blocks
    -"""
    class LibraryPanel(wx.Panel):
    + """
    + Class that implements a panel displaying a tree containing an hierarchical list
    + of functions and function blocks available in project an a search control for
    + quickly find one functions or function blocks in this list and a text control
    + displaying informations about selected functions or function blocks
    + """
    def __init__(self, parent, enable_drag=False):
    """
    --- a/controls/LocationCellEditor.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/controls/LocationCellEditor.py Mon Aug 14 23:27:15 2017 +0300
    @@ -26,6 +26,7 @@
    from dialogs.BrowseLocationsDialog import BrowseLocationsDialog
    +
    class LocationCellControl(wx.PyControl):
    '''
    @@ -133,6 +134,7 @@
    def SetFocus(self):
    self.Location.SetFocus()
    +
    class LocationCellEditor(wx.grid.PyGridCellEditor):
    '''
    Grid cell editor that uses LocationCellControl to display a browse button.
    --- a/controls/LogViewer.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/controls/LogViewer.py Mon Aug 14 23:27:15 2017 +0300
    @@ -37,6 +37,7 @@
    THUMB_SIZE_RATIO = 1. / 8.
    +
    def ArrowPoints(direction, width, height, xoffset, yoffset):
    if direction == wx.TOP:
    return [wx.Point(xoffset + 1, yoffset + height - 2),
    @@ -47,6 +48,7 @@
    wx.Point(xoffset + width / 2, yoffset - 2),
    wx.Point(xoffset + width - 1, yoffset - height + 1)]
    +
    class LogScrollBar(wx.Panel):
    def __init__(self, parent, size):
    @@ -179,6 +181,7 @@
    BUTTON_SIZE = (70, 15)
    +
    class LogButton():
    def __init__(self, label, callback):
    @@ -223,6 +226,7 @@
    DATE_INFO_SIZE = 10
    MESSAGE_INFO_SIZE = 18
    +
    class LogMessage:
    def __init__(self, tv_sec, tv_nsec, level, level_bitmap, msg):
    @@ -281,6 +285,7 @@
    (_("1m"), MINUTE),
    (_("1s"), SECOND)]
    +
    class LogViewer(DebugViewer, wx.Panel):
    def __init__(self, parent, window):
    --- a/controls/PouInstanceVariablesPanel.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/controls/PouInstanceVariablesPanel.py Mon Aug 14 23:27:15 2017 +0300
    @@ -31,10 +31,12 @@
    # Customize CustomTreeItem for adding icon on item right
    CT.GenericTreeItem._rightimages = []
    +
    def SetRightImages(self, images):
    self._rightimages = images
    CT.GenericTreeItem.SetRightImages = SetRightImages
    +
    def GetRightImages(self):
    return self._rightimages
    CT.GenericTreeItem.GetRightImages = GetRightImages
    @@ -112,6 +114,7 @@
    from PLCControler import ITEMS_VARIABLE, ITEM_CONFIGURATION, ITEM_RESOURCE, ITEM_POU, ITEM_TRANSITION, ITEM_ACTION
    from util.BitmapLibrary import GetBitmap
    +
    class PouInstanceVariablesPanel(wx.Panel):
    def __init__(self, parent, window, controller, debug):
    --- a/controls/ProjectPropertiesPanel.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/controls/ProjectPropertiesPanel.py Mon Aug 14 23:27:15 2017 +0300
    @@ -39,6 +39,7 @@
    # Project Properties Panel
    #-------------------------------------------------------------------------------
    +
    class ProjectPropertiesPanel(wx.Notebook):
    def AddSizerParams(self, parent, sizer, params):
    --- a/controls/SearchResultPanel.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/controls/SearchResultPanel.py Mon Aug 14 23:27:15 2017 +0300
    @@ -31,6 +31,7 @@
    from PLCControler import *
    from util.BitmapLibrary import GetBitmap
    +
    def GenerateName(infos):
    if infos[0] in ["input", "output", "value"]:
    return "%s %d:" % (infos[0], infos[1])
    @@ -48,6 +49,7 @@
    ID_SEARCHRESULTPANELSEARCHRESULTSTREE, ID_SEARCHRESULTPANELRESETBUTTON,
    ] = [wx.NewId() for _init_ctrls in range(4)]
    +
    class SearchResultPanel(wx.Panel):
    if wx.VERSION < (2, 6, 0):
    --- a/controls/TextCtrlAutoComplete.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/controls/TextCtrlAutoComplete.py Mon Aug 14 23:27:15 2017 +0300
    @@ -34,6 +34,7 @@
    LISTBOX_BORDER_HEIGHT = 4
    LISTBOX_INTERVAL_HEIGHT = 6
    +
    class PopupWithListbox(wx.PopupWindow):
    def __init__(self, parent, choices=[]):
    @@ -105,6 +106,7 @@
    self.ListBox.HitTest(wx.Point(event.GetX(), event.GetY())))
    event.Skip()
    +
    class TextCtrlAutoComplete(wx.TextCtrl):
    def __init__ (self, parent, choices=None, dropDownClick=True,
    --- a/controls/VariablePanel.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/controls/VariablePanel.py Mon Aug 14 23:27:15 2017 +0300
    @@ -47,12 +47,14 @@
    POUINSTANCEVARIABLESPANEL, LIBRARYTREE, SCALING, PAGETITLES
    ] = range(10)
    +
    def GetVariableTableColnames(location):
    _ = lambda x : x
    if location:
    return ["#", _("Name"), _("Class"), _("Type"), _("Location"), _("Initial Value"), _("Option"), _("Documentation")]
    return ["#", _("Name"), _("Class"), _("Type"), _("Initial Value"), _("Option"), _("Documentation")]
    +
    def GetOptions(constant=True, retain=True, non_retain=True):
    _ = lambda x : x
    options = [""]
    @@ -65,6 +67,7 @@
    return options
    OPTIONS_DICT = dict([(_(option), option) for option in GetOptions()])
    +
    def GetFilterChoiceTransfer():
    _ = lambda x : x
    return {_("All"): _("All"), _("Interface"): _("Interface"),
    @@ -90,6 +93,7 @@
    # Variables Panel Table
    #-------------------------------------------------------------------------------
    +
    class VariableTable(CustomTable):
    """
    @@ -227,6 +231,7 @@
    # Variable Panel Drop Target
    #-------------------------------------------------------------------------------
    +
    class VariableDropTarget(wx.TextDropTarget):
    '''
    This allows dragging a variable location from somewhere to the Location
    @@ -407,6 +412,7 @@
    # Variable Panel
    #-------------------------------------------------------------------------------
    +
    class VariablePanel(wx.Panel):
    def __init__(self, parent, window, controler, element_type, debug=False):
    --- a/dialogs/AboutDialog.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/dialogs/AboutDialog.py Mon Aug 14 23:27:15 2017 +0300
    @@ -175,6 +175,7 @@
    #----------------------------------------------------------------------
    +
    def ShowAboutDialog(parent, info):
    if os.name == "nt":
    AboutDialog(parent, info)
    --- a/dialogs/ActionBlockDialog.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/dialogs/ActionBlockDialog.py Mon Aug 14 23:27:15 2017 +0300
    @@ -34,10 +34,12 @@
    # Helpers
    #-------------------------------------------------------------------------------
    +
    def GetActionTableColnames():
    _ = lambda x: x
    return [_("Qualifier"), _("Duration"), _("Type"), _("Value"), _("Indicator")]
    +
    def GetTypeList():
    _ = lambda x: x
    return [_("Action"), _("Variable"), _("Inline")]
    @@ -46,6 +48,7 @@
    # Action Table
    #-------------------------------------------------------------------------------
    +
    class ActionTable(CustomTable):
    def GetValue(self, row, col):
    @@ -115,6 +118,7 @@
    # Action Block Dialog
    #-------------------------------------------------------------------------------
    +
    class ActionBlockDialog(wx.Dialog):
    def __init__(self, parent):
    --- a/dialogs/ArrayTypeDialog.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/dialogs/ArrayTypeDialog.py Mon Aug 14 23:27:15 2017 +0300
    @@ -38,6 +38,7 @@
    # Array Type Dialog
    #-------------------------------------------------------------------------------
    +
    class ArrayTypeDialog(wx.Dialog):
    def __init__(self, parent, datatypes, infos):
    --- a/dialogs/BlockPreviewDialog.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/dialogs/BlockPreviewDialog.py Mon Aug 14 23:27:15 2017 +0300
    @@ -32,12 +32,12 @@
    # Dialog with preview for graphic block
    #-------------------------------------------------------------------------------
    -"""
    -Class that implements a generic dialog containing a preview panel for displaying
    -graphic created by dialog
    -"""
    class BlockPreviewDialog(wx.Dialog):
    + """
    + Class that implements a generic dialog containing a preview panel for displaying
    + graphic created by dialog
    + """
    def __init__(self, parent, controller, tagname, title):
    """
    --- a/dialogs/BrowseLocationsDialog.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/dialogs/BrowseLocationsDialog.py Mon Aug 14 23:27:15 2017 +0300
    @@ -35,6 +35,7 @@
    # Helpers
    #-------------------------------------------------------------------------------
    +
    def GetDirFilterChoiceOptions():
    _ = lambda x : x
    return [(_("All"), [LOCATION_VAR_INPUT, LOCATION_VAR_OUTPUT, LOCATION_VAR_MEMORY]),
    @@ -43,6 +44,7 @@
    (_("Memory"), [LOCATION_VAR_MEMORY])]
    DIRFILTERCHOICE_OPTIONS = dict([(_(option), filter) for option, filter in GetDirFilterChoiceOptions()])
    +
    def GetTypeFilterChoiceOptions():
    _ = lambda x : x
    return [_("All"),
    @@ -59,6 +61,7 @@
    # Browse Locations Dialog
    #-------------------------------------------------------------------------------
    +
    class BrowseLocationsDialog(wx.Dialog):
    def __init__(self, parent, var_type, controller):
    --- a/dialogs/ConnectionDialog.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/dialogs/ConnectionDialog.py Mon Aug 14 23:27:15 2017 +0300
    @@ -33,12 +33,12 @@
    # Set Connection Parameters Dialog
    #-------------------------------------------------------------------------------
    -"""
    -Class that implements a dialog for defining parameters of a connection graphic
    -element
    -"""
    class ConnectionDialog(BlockPreviewDialog):
    + """
    + Class that implements a dialog for defining parameters of a connection graphic
    + element
    + """
    def __init__(self, parent, controller, tagname, apply_button=False):
    """
    --- a/dialogs/DiscoveryDialog.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/dialogs/DiscoveryDialog.py Mon Aug 14 23:27:15 2017 +0300
    @@ -32,6 +32,7 @@
    service_type = '_PYRO._tcp.local.'
    +
    class AutoWidthListCtrl(wx.ListCtrl, listmix.ListCtrlAutoWidthMixin):
    def __init__(self, parent, id, name, pos=wx.DefaultPosition,
    size=wx.DefaultSize, style=0):
    @@ -43,6 +44,7 @@
    ID_DISCOVERYDIALOGLOCALBUTTON, ID_DISCOVERYDIALOGIPBUTTON,
    ] = [wx.NewId() for _init_ctrls in range(6)]
    +
    class DiscoveryDialog(wx.Dialog, listmix.ColumnSorterMixin):
    def _init_coll_MainSizer_Items(self, parent):
    --- a/dialogs/DurationEditorDialog.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/dialogs/DurationEditorDialog.py Mon Aug 14 23:27:15 2017 +0300
    @@ -53,6 +53,7 @@
    # Edit Duration Value Dialog
    #-------------------------------------------------------------------------------
    +
    class DurationEditorDialog(wx.Dialog):
    def __init__(self, parent):
    --- a/dialogs/FBDBlockDialog.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/dialogs/FBDBlockDialog.py Mon Aug 14 23:27:15 2017 +0300
    @@ -35,6 +35,7 @@
    # Helpers
    #-------------------------------------------------------------------------------
    +
    def GetBlockTypeDefaultNameModel(blocktype):
    return re.compile("%s[0-9]+" % blocktype if blocktype is not None else ".*")
    @@ -42,12 +43,12 @@
    # Set Block Parameters Dialog
    #-------------------------------------------------------------------------------
    -"""
    -Class that implements a dialog for defining parameters of a FBD block graphic
    -element
    -"""
    class FBDBlockDialog(BlockPreviewDialog):
    + """
    + Class that implements a dialog for defining parameters of a FBD block graphic
    + element
    + """
    def __init__(self, parent, controller, tagname):
    """
    --- a/dialogs/FBDVariableDialog.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/dialogs/FBDVariableDialog.py Mon Aug 14 23:27:15 2017 +0300
    @@ -45,12 +45,12 @@
    # Set Variable Parameters Dialog
    #-------------------------------------------------------------------------------
    -"""
    -Class that implements a dialog for defining parameters of a FBD variable graphic
    -element
    -"""
    class FBDVariableDialog(BlockPreviewDialog):
    + """
    + Class that implements a dialog for defining parameters of a FBD variable graphic
    + element
    + """
    def __init__(self, parent, controller, tagname, exclude_input=False):
    """
    --- a/dialogs/FindInPouDialog.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/dialogs/FindInPouDialog.py Mon Aug 14 23:27:15 2017 +0300
    @@ -26,6 +26,7 @@
    import wx
    from plcopen.plcopen import *
    +
    class FindInPouDialog(wx.Dialog):
    def _init_icon(self, parent):
    --- a/dialogs/ForceVariableDialog.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/dialogs/ForceVariableDialog.py Mon Aug 14 23:27:15 2017 +0300
    @@ -36,6 +36,7 @@
    "D" : ["DINT", "UDINT", "REAL", "DWORD"],
    "L" : ["LINT", "ULINT", "LREAL", "LWORD"]}
    +
    def gen_get_function(f):
    def get_function(v):
    try:
    @@ -44,6 +45,7 @@
    return None
    return get_function
    +
    def gen_get_string(delimiter):
    STRING_MODEL = re.compile("%(delimiter)s([^%(delimiter)s]*)%(delimiter)s$" % {"delimiter": delimiter})
    def get_string(v):
    @@ -68,6 +70,7 @@
    IEC_DATETIME_MODEL = re.compile("(?:(?:DT|DATE_AND_TIME)#)?([0-9]{4})-([0-9]{2})-([0-9]{2})-([0-9]{2}):([0-9]{2}):([0-9]{2}(?:\.[0-9]+)?)$")
    IEC_TIMEOFDAY_MODEL = re.compile("(?:(?:TOD|TIME_OF_DAY)#)?([0-9]{2}):([0-9]{2}):([0-9]{2}(?:\.[0-9]+)?)$")
    +
    def gettime(v):
    result = IEC_TIME_MODEL.match(v.upper())
    if result is not None:
    @@ -91,6 +94,7 @@
    else:
    return None
    +
    def getdate(v):
    result = IEC_DATE_MODEL.match(v.upper())
    if result is not None:
    @@ -104,6 +108,7 @@
    else:
    return None
    +
    def getdatetime(v):
    result = IEC_DATETIME_MODEL.match(v.upper())
    if result is not None:
    @@ -117,6 +122,7 @@
    else:
    return None
    +
    def gettimeofday(v):
    result = IEC_TIMEOFDAY_MODEL.match(v.upper())
    if result is not None:
    @@ -156,6 +162,7 @@
    # Force Variable Dialog
    #-------------------------------------------------------------------------------
    +
    class ForceVariableDialog(wx.TextEntryDialog):
    def __init__(self, parent, iec_type, defaultValue=""):
    --- a/dialogs/LDElementDialog.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/dialogs/LDElementDialog.py Mon Aug 14 23:27:15 2017 +0300
    @@ -35,12 +35,12 @@
    # Set Ladder Element Parmeters Dialog
    #-------------------------------------------------------------------------------
    -"""
    -Class that implements a dialog for defining parameters of a LD contact or coil
    -graphic element
    -"""
    class LDElementDialog(BlockPreviewDialog):
    + """
    + Class that implements a dialog for defining parameters of a LD contact or coil
    + graphic element
    + """
    def __init__(self, parent, controller, tagname, type):
    """
    --- a/dialogs/LDPowerRailDialog.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/dialogs/LDPowerRailDialog.py Mon Aug 14 23:27:15 2017 +0300
    @@ -33,13 +33,12 @@
    # Set Ladder Power Rail Parameters Dialog
    #-------------------------------------------------------------------------------
    -"""
    -Class that implements a dialog for defining parameters of a power rail graphic
    -element
    -"""
    class LDPowerRailDialog(BlockPreviewDialog):
    -
    + """
    + Class that implements a dialog for defining parameters of a power rail graphic
    + element
    + """
    def __init__(self, parent, controller, tagname):
    """
    Constructor
    --- a/dialogs/PouActionDialog.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/dialogs/PouActionDialog.py Mon Aug 14 23:27:15 2017 +0300
    @@ -27,11 +27,13 @@
    from plcopen.structures import TestIdentifier, IEC_KEYWORDS
    +
    def GetActionLanguages():
    _ = lambda x : x
    return [_("IL"), _("ST"), _("LD"), _("FBD")]
    ACTION_LANGUAGES_DICT = dict([(_(language), language) for language in GetActionLanguages()])
    +
    class PouActionDialog(wx.Dialog):
    def __init__(self, parent):
    --- a/dialogs/PouDialog.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/dialogs/PouDialog.py Mon Aug 14 23:27:15 2017 +0300
    @@ -27,15 +27,18 @@
    from plcopen.structures import TestIdentifier, IEC_KEYWORDS
    +
    def GetPouTypes():
    _ = lambda x : x
    return [_("function"), _("functionBlock"), _("program")]
    POU_TYPES_DICT = dict([(_(pou_type), pou_type) for pou_type in GetPouTypes()])
    +
    def GetPouLanguages():
    _ = lambda x : x
    return [_("IL"), _("ST"), _("LD"), _("FBD"), _("SFC")]
    +
    class PouDialog(wx.Dialog):
    POU_LANGUAGES = GetPouLanguages()
    --- a/dialogs/PouNameDialog.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/dialogs/PouNameDialog.py Mon Aug 14 23:27:15 2017 +0300
    @@ -28,6 +28,7 @@
    # POU Name Dialog
    #-------------------------------------------------------------------------------
    +
    class PouNameDialog(wx.TextEntryDialog):
    def __init__(self, parent, message, caption = "Please enter text", defaultValue = "",
    --- a/dialogs/PouTransitionDialog.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/dialogs/PouTransitionDialog.py Mon Aug 14 23:27:15 2017 +0300
    @@ -31,11 +31,13 @@
    # POU Transition Dialog
    #-------------------------------------------------------------------------------
    +
    def GetTransitionLanguages():
    _ = lambda x : x
    return [_("IL"), _("ST"), _("LD"), _("FBD")]
    TRANSITION_LANGUAGES_DICT = dict([(_(language), language) for language in GetTransitionLanguages()])
    +
    class PouTransitionDialog(wx.Dialog):
    def __init__(self, parent):
    --- a/dialogs/ProjectDialog.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/dialogs/ProjectDialog.py Mon Aug 14 23:27:15 2017 +0300
    @@ -27,6 +27,7 @@
    from controls.ProjectPropertiesPanel import ProjectPropertiesPanel
    +
    class ProjectDialog(wx.Dialog):
    def __init__(self, parent, enable_required=True):
    --- a/dialogs/SFCDivergenceDialog.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/dialogs/SFCDivergenceDialog.py Mon Aug 14 23:27:15 2017 +0300
    @@ -34,12 +34,12 @@
    # Create New Divergence Dialog
    #-------------------------------------------------------------------------------
    -"""
    -Class that implements a dialog for defining parameters for creating a new
    -divergence graphic element
    -"""
    class SFCDivergenceDialog(BlockPreviewDialog):
    + """
    + Class that implements a dialog for defining parameters for creating a new
    + divergence graphic element
    + """
    def __init__(self, parent, controller, tagname, poss_div_types = None):
    """
    --- a/dialogs/SFCStepDialog.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/dialogs/SFCStepDialog.py Mon Aug 14 23:27:15 2017 +0300
    @@ -32,12 +32,12 @@
    # Set SFC Step Parameters Dialog
    #-------------------------------------------------------------------------------
    -"""
    -Class that implements a dialog for defining parameters of a SFC step graphic
    -element
    -"""
    class SFCStepDialog(BlockPreviewDialog):
    + """
    + Class that implements a dialog for defining parameters of a SFC step graphic
    + element
    + """
    def __init__(self, parent, controller, tagname, initial=False):
    """
    --- a/dialogs/SFCStepNameDialog.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/dialogs/SFCStepNameDialog.py Mon Aug 14 23:27:15 2017 +0300
    @@ -28,6 +28,7 @@
    # Edit Step Name Dialog
    #-------------------------------------------------------------------------------
    +
    class SFCStepNameDialog(wx.TextEntryDialog):
    def __init__(self, parent, message, caption = "Please enter text", defaultValue = "",
    --- a/dialogs/SFCTransitionDialog.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/dialogs/SFCTransitionDialog.py Mon Aug 14 23:27:15 2017 +0300
    @@ -32,12 +32,12 @@
    # Set Transition Parameters Dialog
    #-------------------------------------------------------------------------------
    -"""
    -Class that implements a dialog for defining parameters of a transition graphic
    -element
    -"""
    class SFCTransitionDialog(BlockPreviewDialog):
    + """
    + Class that implements a dialog for defining parameters of a transition graphic
    + element
    + """
    def __init__(self, parent, controller, tagname, connection=True):
    """
    --- a/dialogs/SearchInProjectDialog.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/dialogs/SearchInProjectDialog.py Mon Aug 14 23:27:15 2017 +0300
    @@ -31,6 +31,7 @@
    # Search In Project Dialog
    #-------------------------------------------------------------------------------
    +
    def GetElementsChoices():
    _ = lambda x: x
    return [("datatype", _("Data Type")),
    @@ -39,6 +40,7 @@
    ("program", _("Program")),
    ("configuration", _("Configuration"))]
    +
    class SearchInProjectDialog(wx.Dialog):
    def __init__(self, parent):
    --- a/docutil/dochtml.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/docutil/dochtml.py Mon Aug 14 23:27:15 2017 +0300
    @@ -29,6 +29,7 @@
    HtmlFrameOpened = []
    +
    def OpenHtmlFrame(self, title, file, size):
    if title not in HtmlFrameOpened:
    HtmlFrameOpened.append(title)
    @@ -41,12 +42,14 @@
    [ID_HTMLFRAME, ID_HTMLFRAMEHTMLCONTENT] = [wx.NewId() for _init_ctrls in range(2)]
    EVT_HTML_URL_CLICK = wx.NewId()
    +
    class HtmlWindowUrlClick(wx.PyEvent):
    def __init__(self, linkinfo):
    wx.PyEvent.__init__(self)
    self.SetEventType(EVT_HTML_URL_CLICK)
    self.linkinfo = (linkinfo.GetHref(), linkinfo.GetTarget())
    +
    class UrlClickHtmlWindow(wx.html.HtmlWindow):
    """ HTML window that generates and OnLinkClicked event.
    @@ -61,6 +64,7 @@
    else:
    wx.html.HtmlWindow.Bind(event, handler, source=source, id=id, id2=id2)
    +
    class HtmlFrame(wx.Frame):
    def _init_ctrls(self, prnt):
    wx.Frame.__init__(self, id=ID_HTMLFRAME, name='HtmlFrame',
    --- a/docutil/docpdf.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/docutil/docpdf.py Mon Aug 14 23:27:15 2017 +0300
    @@ -28,6 +28,7 @@
    readerexepath = None
    +
    def get_acroversion():
    " Return version of Adobe Acrobat executable or None"
    import _winreg
    @@ -45,12 +46,14 @@
    pass
    return None
    +
    def open_win_pdf(readerexepath, pdffile, pagenum = None):
    if pagenum != None :
    os.spawnl(os.P_DETACH, readerexepath, "AcroRd32.exe", "/A", "page=%d=OpenActions" % pagenum, '"%s"' % pdffile)
    else:
    os.spawnl(os.P_DETACH, readerexepath, "AcroRd32.exe", '"%s"' % pdffile)
    +
    def open_lin_pdf(readerexepath, pdffile, pagenum = None):
    if pagenum == None :
    os.system("%s -remote DS301 %s &" % (readerexepath, pdffile))
    @@ -58,6 +61,7 @@
    print "Open pdf %s at page %d" % (pdffile, pagenum)
    os.system("%s -remote DS301 %s %d &" % (readerexepath, pdffile, pagenum))
    +
    def open_pdf(pdffile, pagenum = None):
    if wx.Platform == '__WXMSW__' :
    try:
    --- a/docutil/docsvg.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/docutil/docsvg.py Mon Aug 14 23:27:15 2017 +0300
    @@ -26,6 +26,7 @@
    import os
    import subprocess
    +
    def get_inkscape_path():
    """ Return the Inkscape path """
    import _winreg
    @@ -34,6 +35,7 @@
    svgexepath = svgexepath.replace('"%1"', '')
    return svgexepath.replace('"', '')
    +
    def open_win_svg(svgexepath, svgfile):
    """ Open Inkscape on Windows platform """
    popenargs = [svgexepath]
    @@ -41,11 +43,13 @@
    popenargs.append(svgfile)
    subprocess.Popen(popenargs).pid
    +
    def open_lin_svg(svgexepath, svgfile):
    """ Open Inkscape on Linux platform """
    if os.path.isfile("/usr/bin/inkscape"):
    os.system("%s %s &" % (svgexepath , svgfile))
    +
    def open_svg(svgfile):
    """ Generic function to open SVG file """
    if wx.Platform == '__WXMSW__' :
    --- a/editors/CodeFileEditor.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/editors/CodeFileEditor.py Mon Aug 14 23:27:15 2017 +0300
    @@ -48,6 +48,7 @@
    EDGE_COLUMN = 80
    +
    class CodeEditor(CustomStyledTextCtrl):
    KEYWORDS = []
    --- a/editors/ConfTreeNodeEditor.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/editors/ConfTreeNodeEditor.py Mon Aug 14 23:27:15 2017 +0300
    @@ -53,6 +53,7 @@
    SCROLLBAR_UNIT = 10
    +
    class GenBitmapTextButton(wx.lib.buttons.GenBitmapTextButton):
    def _GetLabelSize(self):
    """ used internally """
    @@ -124,6 +125,7 @@
    style,
    name)
    +
    class ConfTreeNodeEditor(EditorPanel):
    SHOW_BASE_PARAMS = True
    --- a/editors/DataTypeEditor.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/editors/DataTypeEditor.py Mon Aug 14 23:27:15 2017 +0300
    @@ -42,13 +42,16 @@
    DIMENSION_MODEL = re.compile("([0-9]+)\.\.([0-9]+)$")
    +
    def AppendMenu(parent, help, id, kind, text):
    parent.Append(help=help, id=id, kind=kind, text=text)
    +
    def GetElementsTableColnames():
    _ = lambda x : x
    return ["#", _("Name"), _("Type"), _("Initial Value")]
    +
    def GetDatatypeTypes():
    _ = lambda x : x
    return [_("Directly"), _("Subrange"), _("Enumerated"), _("Array"), _("Structure")]
    @@ -58,6 +61,7 @@
    # Structure Elements Table
    #-------------------------------------------------------------------------------
    +
    class ElementsTable(CustomTable):
    """
    @@ -137,6 +141,7 @@
    # Datatype Editor class
    #-------------------------------------------------------------------------------
    +
    class DataTypeEditor(EditorPanel):
    def _init_Editor(self, parent):
    --- a/editors/DebugViewer.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/editors/DebugViewer.py Mon Aug 14 23:27:15 2017 +0300
    @@ -34,12 +34,12 @@
    # Debug Viewer Class
    #-------------------------------------------------------------------------------
    -"""
    -Class that implements common behavior of every viewers able to display debug
    -values
    -"""
    class DebugViewer:
    + """
    + Class that implements common behavior of every viewers able to display debug
    + values
    + """
    def __init__(self, producer, debug, subscribe_tick=True):
    """
    --- a/editors/EditorPanel.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/editors/EditorPanel.py Mon Aug 14 23:27:15 2017 +0300
    @@ -26,6 +26,7 @@
    from controls import VariablePanel
    +
    class EditorPanel(wx.SplitterWindow):
    VARIABLE_PANEL_TYPE = None
    --- a/editors/FileManagementPanel.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/editors/FileManagementPanel.py Mon Aug 14 23:27:15 2017 +0300
    @@ -34,6 +34,7 @@
    FILTER = _("All files (*.*)|*.*|CSV files (*.csv)|*.csv")
    +
    class FileManagementPanel(EditorPanel):
    def _init_Editor(self, parent):
    --- a/editors/IECCodeViewer.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/editors/IECCodeViewer.py Mon Aug 14 23:27:15 2017 +0300
    @@ -25,6 +25,7 @@
    from editors.TextViewer import TextViewer
    from plcopen.plcopen import TestTextElement
    +
    class IECCodeViewer(TextViewer):
    def __del__(self):
    --- a/editors/LDViewer.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/editors/LDViewer.py Mon Aug 14 23:27:15 2017 +0300
    @@ -28,6 +28,7 @@
    from Viewer import *
    +
    def ExtractNextBlocks(block, block_list):
    current_list = [block]
    while len(current_list) > 0:
    @@ -50,6 +51,7 @@
    next_list.append(next)
    current_list = next_list
    +
    def CalcBranchSize(elements, stops):
    branch_size = 0
    stop_list = stops
    @@ -91,6 +93,7 @@
    return 1
    return branch_size
    +
    def RemoveElement(remove, element_tree):
    if remove in element_tree and element_tree[remove]:
    for child in element_tree[remove]["children"]:
    @@ -99,6 +102,7 @@
    element_tree.pop(remove)
    ## element_tree[remove] = None
    +
    def GenerateTree(element, element_tree, stop_list):
    if element in element_tree:
    connectors = element.GetConnectors()
    @@ -128,6 +132,7 @@
    element_tree[next] = {"parents":[element], "children":[], "weight":None}
    GenerateTree(next, element_tree, stop_list)
    +
    def CalcWeight(element, element_tree):
    weight = 0
    parts = None
    @@ -160,11 +165,10 @@
    #-------------------------------------------------------------------------------
    -"""
    -Class derived from Viewer class that implements a Viewer of Ladder Diagram
    -"""
    -
    class LD_Viewer(Viewer):
    + """
    + Class derived from Viewer class that implements a Viewer of Ladder Diagram
    + """
    def __init__(self, parent, tagname, window, controler, debug = False, instancepath = ""):
    Viewer.__init__(self, parent, tagname, window, controler, debug, instancepath)
    --- a/editors/ProjectNodeEditor.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/editors/ProjectNodeEditor.py Mon Aug 14 23:27:15 2017 +0300
    @@ -28,6 +28,7 @@
    from EditorPanel import EditorPanel
    from ConfTreeNodeEditor import ConfTreeNodeEditor
    +
    class ProjectNodeEditor(ConfTreeNodeEditor):
    SHOW_BASE_PARAMS = False
    --- a/editors/ResourceEditor.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/editors/ResourceEditor.py Mon Aug 14 23:27:15 2017 +0300
    @@ -39,6 +39,7 @@
    [ID_CONFIGURATIONEDITOR,
    ] = [wx.NewId() for _init_ctrls in range(1)]
    +
    class ConfigurationEditor(EditorPanel):
    ID = ID_CONFIGURATIONEDITOR
    @@ -67,6 +68,7 @@
    _ = lambda x : x
    return [_("Name"), _("Triggering"), _("Single"), _("Interval"), _("Priority")]
    +
    def GetTaskTriggeringOptions():
    _ = lambda x : x
    return [_("Interrupt"), _("Cyclic")]
    @@ -74,6 +76,7 @@
    SingleCellEditor = lambda *x : wx.grid.GridCellChoiceEditor()
    +
    def CheckSingle(single, varlist):
    return single in varlist
    @@ -82,6 +85,7 @@
    _ = lambda x : x
    return [_("Name"), _("Type"), _("Task")]
    +
    class ResourceTable(CustomTable):
    """
    --- a/editors/TextViewer.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/editors/TextViewer.py Mon Aug 14 23:27:15 2017 +0300
    @@ -67,9 +67,11 @@
    SEARCH_RESULT_HIGHLIGHT: STC_PLC_SEARCH_RESULT,
    }
    +
    def LineStartswith(line, symbols):
    return reduce(lambda x, y: x or y, map(lambda x: line.startswith(x), symbols), False)
    +
    class TextViewer(EditorPanel):
    ID = ID_TEXTVIEWER
    --- a/editors/Viewer.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/editors/Viewer.py Mon Aug 14 23:27:15 2017 +0300
    @@ -46,6 +46,7 @@
    CURSORS = None
    SFC_Objects = (SFC_Step, SFC_ActionBlock, SFC_Transition, SFC_Divergence, SFC_Jump)
    +
    def ResetCursors():
    global CURSORS
    if CURSORS == None:
    @@ -56,6 +57,7 @@
    wx.StockCursor(wx.CURSOR_SIZEWE),
    wx.StockCursor(wx.CURSOR_SIZENS)]
    +
    def AppendMenu(parent, help, id, kind, text):
    if wx.VERSION >= (2, 6, 0):
    parent.Append(help=help, id=id, kind=kind, text=text)
    @@ -83,6 +85,7 @@
    MAX_ZOOMIN = 7
    ZOOM_FACTORS = [math.sqrt(2) ** x for x in xrange(-6, MAX_ZOOMIN)]
    +
    def GetVariableCreationFunction(variable_type):
    def variableCreationFunction(viewer, id, specific_values):
    return FBD_Variable(viewer, variable_type,
    @@ -92,15 +95,18 @@
    specific_values.execution_order)
    return variableCreationFunction
    +
    def GetConnectorCreationFunction(connector_type):
    def connectorCreationFunction(viewer, id, specific_values):
    return FBD_Connector(viewer, connector_type,
    specific_values.name, id)
    return connectorCreationFunction
    +
    def commentCreationFunction(viewer, id, specific_values):
    return Comment(viewer, specific_values.content, id)
    +
    def GetPowerRailCreationFunction(powerrail_type):
    def powerRailCreationFunction(viewer, id, specific_values):
    return LD_PowerRail(viewer, powerrail_type, id,
    @@ -114,6 +120,7 @@
    (False, "rising"): CONTACT_RISING,
    (False, "falling"): CONTACT_FALLING}
    +
    def contactCreationFunction(viewer, id, specific_values):
    contact_type = CONTACT_TYPES.get((NEGATED_VALUE(specific_values.negated),
    MODIFIER_VALUE(specific_values.edge)),
    @@ -126,6 +133,7 @@
    (False, "rising", "none"): COIL_RISING,
    (False, "falling", "none"): COIL_FALLING}
    +
    def coilCreationFunction(viewer, id, specific_values):
    coil_type = COIL_TYPES.get((NEGATED_VALUE(specific_values.negated),
    MODIFIER_VALUE(specific_values.edge),
    @@ -133,6 +141,7 @@
    COIL_NORMAL)
    return LD_Coil(viewer, coil_type, specific_values.name, id)
    +
    def stepCreationFunction(viewer, id, specific_values):
    step = SFC_Step(viewer, specific_values.name,
    specific_values.initial, id)
    @@ -142,6 +151,7 @@
    connector.SetPosition(wx.Point(*specific_values.action.position))
    return step
    +
    def transitionCreationFunction(viewer, id, specific_values):
    transition = SFC_Transition(viewer, specific_values.condition_type,
    specific_values.condition,
    @@ -151,15 +161,18 @@
    divergence_types = [SELECTION_DIVERGENCE,
    SELECTION_CONVERGENCE, SIMULTANEOUS_DIVERGENCE, SIMULTANEOUS_CONVERGENCE]
    +
    def GetDivergenceCreationFunction(divergence_type):
    def divergenceCreationFunction(viewer, id, specific_values):
    return SFC_Divergence(viewer, divergence_type,
    specific_values.connectors, id)
    return divergenceCreationFunction
    +
    def jumpCreationFunction(viewer, id, specific_values):
    return SFC_Jump(viewer, specific_values.target, id)
    +
    def actionBlockCreationFunction(viewer, id, specific_values):
    return SFC_ActionBlock(viewer, specific_values.actions, id)
    @@ -184,6 +197,7 @@
    "actionBlock": actionBlockCreationFunction,
    }
    +
    def sort_blocks(block_infos1, block_infos2):
    x1, y1 = block_infos1[0].GetPosition()
    x2, y2 = block_infos2[0].GetPosition()
    @@ -483,12 +497,12 @@
    dc.DrawText(text, x + tw, y)
    dc.SetUserScale(scalex, scaley)
    -"""
    -Class that implements a Viewer based on a wx.ScrolledWindow for drawing and
    -manipulating graphic elements
    -"""
    class Viewer(EditorPanel, DebugViewer):
    + """
    + Class that implements a Viewer based on a wx.ScrolledWindow for drawing and
    + manipulating graphic elements
    + """
    if wx.VERSION < (2, 6, 0):
    def Bind(self, event, function, id = None):
    --- a/graphics/DebugDataConsumer.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/graphics/DebugDataConsumer.py Mon Aug 14 23:27:15 2017 +0300
    @@ -36,6 +36,7 @@
    # Date corresponding to Epoch (1970 January the first)
    DATE_ORIGIN = datetime.datetime(1970, 1, 1)
    +
    def get_microseconds(value):
    """
    Function converting time duration expressed in day, second and microseconds
    @@ -48,6 +49,7 @@
    value.microseconds)
    return
    +
    def generate_time(value):
    """
    Function converting time duration expressed in day, second and microseconds
    @@ -90,6 +92,7 @@
    return data
    +
    def generate_date(value):
    """
    Function converting time duration expressed in day, second and microseconds
    @@ -99,6 +102,7 @@
    """
    return (DATE_ORIGIN + value).strftime("DATE#%Y-%m-%d")
    +
    def generate_datetime(value):
    """
    Function converting time duration expressed in day, second and microseconds
    @@ -108,6 +112,7 @@
    """
    return (DATE_ORIGIN + value).strftime("DT#%Y-%m-%d-%H:%M:%S.%f")
    +
    def generate_timeofday(value):
    """
    Function converting time duration expressed in day, second and microseconds
    @@ -147,13 +152,13 @@
    # Debug Data Consumer Class
    #-------------------------------------------------------------------------------
    -"""
    -Class that implements an element that consumes debug values
    -Value update can be inhibited during the time the associated Debug Viewer is
    -refreshing
    -"""
    class DebugDataConsumer:
    + """
    + Class that implements an element that consumes debug values
    + Value update can be inhibited during the time the associated Debug Viewer is
    + refreshing
    + """
    def __init__(self):
    """
    --- a/graphics/FBD_Objects.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/graphics/FBD_Objects.py Mon Aug 14 23:27:15 2017 +0300
    @@ -31,14 +31,15 @@
    # Function Block Diagram Block
    #-------------------------------------------------------------------------------
    -"""
    -Class that implements the graphic representation of a function block
    -"""
    def TestConnectorName(name, block_type):
    return name in ["OUT", "MN", "MX"] or name.startswith("IN") and (block_type, name) != ("EXPT", "IN2")
    +
    class FBD_Block(Graphic_Element):
    + """
    + Class that implements the graphic representation of a function block
    + """
    # Create a new block
    def __init__(self, parent, type, name, id = None, extension = 0, inputs = None, connectors = {}, executionControl = False, executionOrder = 0):
    @@ -498,11 +499,11 @@
    # Function Block Diagram Variable
    #-------------------------------------------------------------------------------
    -"""
    -Class that implements the graphic representation of a variable
    -"""
    class FBD_Variable(Graphic_Element):
    + """
    + Class that implements the graphic representation of a variable
    + """
    # Create a new variable
    def __init__(self, parent, type, name, value_type, id = None, executionOrder = 0):
    @@ -794,11 +795,11 @@
    # Function Block Diagram Connector
    #-------------------------------------------------------------------------------
    -"""
    -Class that implements the graphic representation of a connection
    -"""
    class FBD_Connector(Graphic_Element):
    + """
    + Class that implements the graphic representation of a connection
    + """
    # Create a new connection
    def __init__(self, parent, type, name, id = None):
    --- a/graphics/GraphicCommons.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/graphics/GraphicCommons.py Mon Aug 14 23:27:15 2017 +0300
    @@ -115,6 +115,7 @@
    (2, 3) : 5
    }
    +
    def round_scaling(x, n, constraint=0):
    fraction = float(x) / float(n)
    if constraint == -1:
    @@ -129,19 +130,28 @@
    Basic vector operations for calculate wire points
    """
    -# Create a vector from two points and define if vector must be normal
    +
    def vector(p1, p2, normal = True):
    + """
    + Create a vector from two points and define if vector must be normal
    + """
    vector = (p2.x - p1.x, p2.y - p1.y)
    if normal:
    return normalize(vector)
    return vector
    -# Calculate the norm of a given vector
    +
    def norm(v):
    + """
    + Calculate the norm of a given vector
    + """
    return sqrt(v[0] * v[0] + v[1] * v[1])
    -# Normalize a given vector
    +
    def normalize(v):
    + """
    + Normalize a given vector
    + """
    v_norm = norm(v)
    # Verifie if it is not a null vector
    if v_norm > 0:
    @@ -149,24 +159,32 @@
    else:
    return v
    -# Calculate the scalar product of two vectors
    +
    def is_null_vector(v):
    + """
    + Calculate the scalar product of two vectors
    + """
    return v == (0, 0)
    -# Calculate the scalar product of two vectors
    +
    def add_vectors(v1, v2):
    + """
    + Calculate the scalar product of two vectors
    + """
    return (v1[0] + v2[0], v1[1] + v2[1])
    -# Calculate the scalar product of two vectors
    +
    def product(v1, v2):
    + """
    + Calculate the scalar product of two vectors
    + """
    return v1[0] * v2[0] + v1[1] * v2[1]
    -"""
    -Function that calculates the nearest point of the grid defined by scaling for the given point
    -"""
    -
    def GetScaledEventPosition(event, dc, scaling):
    + """
    + Function that calculates the nearest point of the grid defined by scaling for the given point
    + """
    pos = event.GetLogicalPosition(dc)
    if scaling:
    pos.x = round(float(pos.x) / float(scaling[0])) * scaling[0]
    @@ -174,11 +192,11 @@
    return pos
    -"""
    -Function that choose a direction during the wire points generation
    -"""
    def DirectionChoice(v_base, v_target, dir_target):
    + """
    + Function that choose a direction during the wire points generation
    + """
    dir_product = product(v_base, v_target)
    if dir_product < 0:
    return (-v_base[0], -v_base[1])
    @@ -186,6 +204,7 @@
    return dir_target
    return v_base
    +
    def MiterPen(colour, width=1, style=wx.SOLID):
    pen = wx.Pen(colour, width, style)
    pen.SetJoin(wx.JOIN_MITER)
    @@ -196,21 +215,25 @@
    # Helpers for highlighting text
    #-------------------------------------------------------------------------------
    +
    def AddHighlight(highlights, infos):
    RemoveHighlight(highlights, infos)
    highlights.append(infos)
    +
    def RemoveHighlight(highlights, infos):
    if infos in highlights:
    highlights.remove(infos)
    return True
    return False
    +
    def ClearHighlight(highlights, highlight_type=None):
    if highlight_type is not None:
    return [highlight for highlight in highlights if highlight[2] != highlight_type]
    return []
    +
    def DrawHighlightedText(dc, text, highlights, x, y):
    current_pen = dc.GetPen()
    dc.SetPen(wx.TRANSPARENT_PEN)
    @@ -229,11 +252,11 @@
    # Graphic element base class
    #-------------------------------------------------------------------------------
    -"""
    -Class that implements a generic graphic element
    -"""
    class Graphic_Element(ToolTipProducer):
    + """
    + Class that implements a generic graphic element
    + """
    # Create a new graphic element
    def __init__(self, parent, id = None):
    @@ -684,11 +707,11 @@
    # Group of graphic elements
    #-------------------------------------------------------------------------------
    -"""
    -Class that implements a group of graphic elements
    -"""
    class Graphic_Group(Graphic_Element):
    + """
    + Class that implements a group of graphic elements
    + """
    # Create a new group of graphic elements
    def __init__(self, parent):
    @@ -1002,11 +1025,11 @@
    # Connector for all types of blocks
    #-------------------------------------------------------------------------------
    -"""
    -Class that implements a connector for any type of block
    -"""
    class Connector(DebugDataConsumer, ToolTipProducer):
    + """
    + Class that implements a connector for any type of block
    + """
    # Create a new connector
    def __init__(self, parent, name, type, position, direction, negated = False, edge = "none", onlyone = False):
    @@ -1536,11 +1559,11 @@
    # Common Wire Element
    #-------------------------------------------------------------------------------
    -"""
    -Class that implements a wire for connecting two blocks
    -"""
    class Wire(Graphic_Element, DebugDataConsumer):
    + """
    + Class that implements a wire for connecting two blocks
    + """
    # Create a new wire
    def __init__(self, parent, start = None, end = None):
    @@ -2716,6 +2739,7 @@
    # Graphic comment element
    #-------------------------------------------------------------------------------
    +
    def FilterHighlightsByRow(highlights, row, length):
    _highlights = []
    for start, end, highlight_type in highlights:
    @@ -2727,6 +2751,7 @@
    _highlights.append((start, end, highlight_type))
    return _highlights
    +
    def FilterHighlightsByColumn(highlights, start_col, end_col):
    _highlights = []
    for start, end, highlight_type in highlights:
    @@ -2736,11 +2761,11 @@
    _highlights.append((start, end, highlight_type))
    return _highlights
    -"""
    -Class that implements a comment
    -"""
    class Comment(Graphic_Element):
    + """
    + Class that implements a comment
    + """
    # Create a new comment
    def __init__(self, parent, content, id = None):
    --- a/graphics/LD_Objects.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/graphics/LD_Objects.py Mon Aug 14 23:27:15 2017 +0300
    @@ -32,11 +32,11 @@
    # Ladder Diagram PowerRail
    #-------------------------------------------------------------------------------
    -"""
    -Class that implements the graphic representation of a power rail
    -"""
    class LD_PowerRail(Graphic_Element):
    + """
    + Class that implements the graphic representation of a power rail
    + """
    # Create a new power rail
    def __init__(self, parent, type, id=None, connectors=1):
    @@ -343,11 +343,11 @@
    # Ladder Diagram Contact
    #-------------------------------------------------------------------------------
    -"""
    -Class that implements the graphic representation of a contact
    -"""
    class LD_Contact(Graphic_Element, DebugDataConsumer):
    + """
    + Class that implements the graphic representation of a contact
    + """
    # Create a new contact
    def __init__(self, parent, type, name, id = None):
    @@ -689,11 +689,11 @@
    # Ladder Diagram Coil
    #-------------------------------------------------------------------------------
    -"""
    -Class that implements the graphic representation of a coil
    -"""
    class LD_Coil(Graphic_Element):
    + """
    + Class that implements the graphic representation of a coil
    + """
    # Create a new coil
    def __init__(self, parent, type, name, id = None):
    --- a/graphics/RubberBand.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/graphics/RubberBand.py Mon Aug 14 23:27:15 2017 +0300
    @@ -30,11 +30,11 @@
    # Viewer RubberBand
    #-------------------------------------------------------------------------------
    -"""
    -Class that implements a rubberband for graphic Viewers
    -"""
    class RubberBand:
    + """
    + Class that implements a rubberband for graphic Viewers
    + """
    def __init__(self, viewer):
    """
    --- a/graphics/SFC_Objects.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/graphics/SFC_Objects.py Mon Aug 14 23:27:15 2017 +0300
    @@ -28,6 +28,7 @@
    from graphics.DebugDataConsumer import DebugDataConsumer
    from plcopen.structures import *
    +
    def GetWireSize(block):
    if isinstance(block, SFC_Step):
    return SFC_WIRE_MIN_SIZE + block.GetActionExtraLineNumber() * SFC_ACTION_MIN_SIZE[1]
    @@ -38,11 +39,11 @@
    # Sequencial Function Chart Step
    #-------------------------------------------------------------------------------
    -"""
    -Class that implements the graphic representation of a step
    -"""
    class SFC_Step(Graphic_Element, DebugDataConsumer):
    + """
    + Class that implements the graphic representation of a step
    + """
    # Create a new step
    def __init__(self, parent, name, initial = False, id = None):
    @@ -571,11 +572,11 @@
    # Sequencial Function Chart Transition
    #-------------------------------------------------------------------------------
    -"""
    -Class that implements the graphic representation of a transition
    -"""
    class SFC_Transition(Graphic_Element, DebugDataConsumer):
    + """
    + Class that implements the graphic representation of a transition
    + """
    # Create a new transition
    def __init__(self, parent, type = "reference", condition = None, priority = 0, id = None):
    @@ -1040,12 +1041,12 @@
    # Sequencial Function Chart Divergence and Convergence
    #-------------------------------------------------------------------------------
    -"""
    -Class that implements the graphic representation of a divergence or convergence,
    -selection or simultaneous
    -"""
    class SFC_Divergence(Graphic_Element):
    + """
    + Class that implements the graphic representation of a divergence or convergence,
    + selection or simultaneous
    + """
    # Create a new divergence
    def __init__(self, parent, type, number = 2, id = None):
    @@ -1502,11 +1503,10 @@
    # Sequencial Function Chart Jump to Step
    #-------------------------------------------------------------------------------
    -"""
    -Class that implements the graphic representation of a jump to step
    -"""
    -
    class SFC_Jump(Graphic_Element):
    + """
    + Class that implements the graphic representation of a jump to step
    + """
    # Create a new jump
    def __init__(self, parent, target, id = None):
    @@ -1778,11 +1778,11 @@
    # Sequencial Function Chart Action Block
    #-------------------------------------------------------------------------------
    -"""
    -Class that implements the graphic representation of an action block
    -"""
    class SFC_ActionBlock(Graphic_Element):
    + """
    + Class that implements the graphic representation of an action block
    + """
    # Create a new action block
    def __init__(self, parent, actions = [], id = None):
    --- a/graphics/ToolTipProducer.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/graphics/ToolTipProducer.py Mon Aug 14 23:27:15 2017 +0300
    @@ -30,11 +30,11 @@
    # Tool Tip Producer class
    #-------------------------------------------------------------------------------
    -"""
    -Class that implements an element that generate Tool Tip
    -"""
    class ToolTipProducer:
    + """
    + Class that implements an element that generate Tool Tip
    + """
    def __init__(self, parent):
    """
    --- a/i18n/mki18n.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/i18n/mki18n.py Mon Aug 14 23:27:15 2017 +0300
    @@ -93,6 +93,7 @@
    # -----------------------------------------------------------------------------
    +
    def getlanguageDict():
    languageDict = {}
    @@ -210,10 +211,7 @@
    os.system(cmd)
    os.chdir(currentDir)
    -# -----------------------------------------------------------------------------
    -# c a t P O ( ) -- Concatenate one or several PO files with the application domain files. --
    -# ^^^^^^^^^^^^^
    -#
    +
    def catPO(applicationDirectoryPath, listOf_extraPo, applicationDomain=None, targetDir=None, verbose=0) :
    """Concatenate one or several PO files with the application domain files.
    """
    @@ -248,10 +246,7 @@
    os.system(cmd)
    os.chdir(currentDir)
    -# -----------------------------------------------------------------------------
    -# m a k e M O ( ) -- Compile the Portable Object files into the Machine Object stored in the right location. --
    -# ^^^^^^^^^^^^^^^
    -#
    +
    def makeMO(applicationDirectoryPath,targetDir='./locale',applicationDomain=None, verbose=0, forceEnglish=0) :
    """Compile the Portable Object files into the Machine Object stored in the right location.
    @@ -297,10 +292,7 @@
    os.system(cmd)
    os.chdir(currentDir)
    -# -----------------------------------------------------------------------------
    -# p r i n t U s a g e -- Displays how to use this script from the command line --
    -# ^^^^^^^^^^^^^^^^^^^
    -#
    +
    def printUsage(errorMsg=None) :
    """Displays how to use this script from the command line."""
    print """
    @@ -337,10 +329,7 @@
    if errorMsg:
    print "\n ERROR: %s" % errorMsg
    -# -----------------------------------------------------------------------------
    -# f i l e B a s e O f ( ) -- Return base name of filename --
    -# ^^^^^^^^^^^^^^^^^^^^^^^
    -#
    +
    def fileBaseOf(filename,withPath=0) :
    """fileBaseOf(filename,withPath) ---> string
    @@ -378,10 +367,8 @@
    return filename
    else:
    return os.path.basename(filename)
    -# -----------------------------------------------------------------------------
    -# m k d i r ( ) -- Create a directory (and possibly the entire tree) --
    -# ^^^^^^^^^^^^^
    -#
    +
    +
    def mkdir(directory) :
    """Create a directory (and possibly the entire tree).
    @@ -420,10 +407,7 @@
    os.mkdir(theDir)
    theDir += '/'
    -# -----------------------------------------------------------------------------
    -# u n i x p a t h ( ) -- Return a path name that contains Unix separator. --
    -# ^^^^^^^^^^^^^^^^^^^
    -#
    +
    def unixpath(thePath) :
    r"""Return a path name that contains Unix separator.
    --- a/plcopen/definitions.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/plcopen/definitions.py Mon Aug 14 23:27:15 2017 +0300
    @@ -50,6 +50,7 @@
    StdFuncsCSV = join(sd,"iec_std.csv")
    +
    def GetBlockInfos(pou):
    infos = pou.getblockInfos()
    infos["inputs"] = [
    --- a/plcopen/plcopen.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/plcopen/plcopen.py Mon Aug 14 23:27:15 2017 +0300
    @@ -59,6 +59,7 @@
    FILTER_ADDRESS_MODEL = "(%%[IQM](?:[XBWDL])?)(%s)((?:\.[0-9]+)*)"
    +
    def update_address(address, address_model, new_leading):
    result = address_model.match(address)
    if result is None:
    @@ -66,6 +67,7 @@
    groups = result.groups()
    return groups[0] + new_leading + groups[2]
    +
    def _init_and_compare(function, v1, v2):
    if v1 is None:
    return v2
    @@ -73,10 +75,11 @@
    return function(v1, v2)
    return v1
    -"""
    -Helper class for bounding_box calculation
    -"""
    +
    class rect:
    + """
    + Helper class for bounding_box calculation
    + """
    def __init__(self, x=None, y=None, width=None, height=None):
    self.x_min = x
    @@ -108,12 +111,14 @@
    height = self.y_max - self.y_min
    return self.x_min, self.y_min, width, height
    +
    def TextLenInRowColumn(text):
    if text == "":
    return (0, 0)
    lines = text.split("\n")
    return len(lines) - 1, len(lines[-1])
    +
    def CompilePattern(criteria):
    flag = 0 if criteria["case_sensitive"] else re.IGNORECASE
    find_pattern = criteria["find_pattern"]
    @@ -121,6 +126,7 @@
    find_pattern = re.escape(find_pattern)
    criteria["pattern"] = re.compile(find_pattern, flag)
    +
    def TestTextElement(text, criteria):
    lines = text.splitlines()
    test_result = []
    @@ -135,6 +141,7 @@
    break
    return test_result
    +
    def TextMatched(str1, str2):
    return str1 and str2 and (str1.upper() == str2.upper())
    @@ -165,6 +172,7 @@
    </project>
    """
    +
    def LOAD_POU_INSTANCES_PROJECT_TEMPLATE(body_type):
    return LOAD_POU_PROJECT_TEMPLATE % """
    <pou name="paste_pou" pouType="program">
    @@ -189,6 +197,7 @@
    ActionBlocksXPath = PLCOpen_XPath("ppx:types/ppx:pous/ppx:pou/ppx:body/*/ppx:actionBlock")
    ActionBlocksConnectionPointOutXPath = PLCOpen_XPath("ppx:connectionPointOut")
    +
    def LoadProjectXML(project_xml):
    project_xml = project_xml.replace(
    "http://www.plcopen.org/xml/tc6.xsd",
    @@ -266,6 +275,7 @@
    except Exception, e:
    return None, e.message
    +
    def LoadProject(filepath):
    project_file = open(filepath)
    project_xml = project_file.read()
    @@ -273,6 +283,8 @@
    return LoadProjectXML(project_xml)
    project_pou_xpath = PLCOpen_XPath("/ppx:project/ppx:types/ppx:pous/ppx:pou")
    +
    +
    def LoadPou(xml_string):
    root, error = LoadProjectXML(LOAD_POU_PROJECT_TEMPLATE % xml_string)
    return project_pou_xpath(root)[0], error
    @@ -281,11 +293,14 @@
    body_type: PLCOpen_XPath(
    "/ppx:project/ppx:types/ppx:pous/ppx:pou[@name='paste_pou']/ppx:body/ppx:%s/*" % body_type)
    for body_type in ["FBD", "LD", "SFC"]}
    +
    +
    def LoadPouInstances(xml_string, body_type):
    root, error = LoadProjectXML(
    LOAD_POU_INSTANCES_PROJECT_TEMPLATE(body_type) % xml_string)
    return project_pou_instances_xpath[body_type](root), error
    +
    def SaveProject(project, filepath):
    project_file = open(filepath, 'w')
    project_file.write(etree.tostring(
    @@ -625,6 +640,7 @@
    return 0, 0
    setattr(cls, "getscaling", getscaling)
    +
    def _Search(attributes, criteria, parent_infos):
    search_result = []
    for attr, value in attributes:
    @@ -632,6 +648,7 @@
    search_result.extend([(tuple(parent_infos + [attr]),) + result for result in TestTextElement(value, criteria)])
    return search_result
    +
    def _updateConfigurationResourceElementName(self, old_name, new_name):
    for varlist in self.getglobalVars():
    for var in varlist.getvariable():
    @@ -642,6 +659,7 @@
    if TextMatched(var.getname(), old_name):
    var.setname(new_name)
    +
    def _updateConfigurationResourceElementAddress(self, address_model, new_leading):
    for varlist in self.getglobalVars():
    for var in varlist.getvariable():
    @@ -649,6 +667,7 @@
    if var_address is not None:
    var.setaddress(update_address(var_address, address_model, new_leading))
    +
    def _removeConfigurationResourceVariableByAddress(self, address):
    for varlist in self.getglobalVars():
    variables = varlist.getvariable()
    @@ -656,6 +675,7 @@
    if variables[i].getaddress() == address:
    variables.remove(variables[i])
    +
    def _removeConfigurationResourceVariableByFilter(self, address_model):
    for varlist in self.getglobalVars():
    variables = varlist.getvariable()
    @@ -666,6 +686,7 @@
    if result is not None:
    variables.remove(variables[i])
    +
    def _SearchInConfigurationResource(self, criteria, parent_infos=[]):
    search_result = _Search([("name", self.getname())], criteria, parent_infos)
    var_number = 0
    @@ -936,6 +957,7 @@
    return search_result
    setattr(cls, "Search", Search)
    +
    def _updateBaseTypeElementName(self, old_name, new_name):
    self.baseType.updateElementName(old_name, new_name)
    @@ -1006,6 +1028,7 @@
    return search_result
    setattr(cls, "Search", Search)
    +
    def _SearchInSubrange(self, criteria, parent_infos=[]):
    search_result = self.baseType.Search(criteria, parent_infos)
    search_result.extend(_Search([("lower", self.range.getlower()),
    @@ -1039,6 +1062,7 @@
    return search_result
    setattr(cls, "Search", Search)
    +
    def _getvariableTypeinfos(variable_type):
    type_content = variable_type.getcontent()
    type_content_type = type_content.getLocalTag()
    @@ -1450,48 +1474,62 @@
    return search_result
    setattr(cls, "Search", Search)
    +
    def setbodyType(self, body_type):
    if body_type in ["IL", "ST", "LD", "FBD", "SFC"]:
    self.body.setcontent(PLCOpenParser.CreateElement(body_type, "body"))
    else:
    raise ValueError, "%s isn't a valid body type!" % type
    +
    def getbodyType(self):
    return self.body.getcontent().getLocalTag()
    +
    def resetexecutionOrder(self):
    self.body.resetexecutionOrder()
    +
    def compileexecutionOrder(self):
    self.body.compileexecutionOrder()
    +
    def setelementExecutionOrder(self, instance, new_executionOrder):
    self.body.setelementExecutionOrder(instance, new_executionOrder)
    +
    def addinstance(self, instance):
    self.body.appendcontentInstance(instance)
    +
    def getinstances(self):
    return self.body.getcontentInstances()
    +
    def getinstance(self, id):
    return self.body.getcontentInstance(id)
    +
    def getrandomInstance(self, exclude):
    return self.body.getcontentRandomInstance(exclude)
    +
    def getinstanceByName(self, name):
    return self.body.getcontentInstanceByName(name)
    +
    def removeinstance(self, id):
    self.body.removecontentInstance(id)
    +
    def settext(self, text):
    self.body.settext(text)
    +
    def gettext(self):
    return self.body.gettext()
    +
    def hasblock(self, name=None, block_type=None):
    if self.getbodyType() in ["FBD", "LD", "SFC"]:
    for instance in self.getinstances():
    @@ -1502,9 +1540,11 @@
    return self.body.hasblock(block_type)
    return False
    +
    def updateElementName(self, old_name, new_name):
    self.body.updateElementName(old_name, new_name)
    +
    def updateElementAddress(self, address_model, new_leading):
    self.body.updateElementAddress(address_model, new_leading)
    @@ -1746,21 +1786,27 @@
    return search_result
    setattr(cls, "Search", Search)
    +
    def getx(self):
    return self.position.getx()
    +
    def gety(self):
    return self.position.gety()
    +
    def setx(self, x):
    self.position.setx(x)
    +
    def sety(self, y):
    self.position.sety(y)
    +
    def _getBoundingBox(self):
    return rect(self.getx(), self.gety(), self.getwidth(), self.getheight())
    +
    def _getConnectionsBoundingBox(connectionPointIn):
    bbox = rect()
    connections = connectionPointIn.getconnections()
    @@ -1770,18 +1816,21 @@
    bbox.update(x, y)
    return bbox
    +
    def _getBoundingBoxSingle(self):
    bbox = _getBoundingBox(self)
    if self.connectionPointIn is not None:
    bbox.union(_getConnectionsBoundingBox(self.connectionPointIn))
    return bbox
    +
    def _getBoundingBoxMultiple(self):
    bbox = _getBoundingBox(self)
    for connectionPointIn in self.getconnectionPointIn():
    bbox.union(_getConnectionsBoundingBox(connectionPointIn))
    return bbox
    +
    def _filterConnections(connectionPointIn, localId, connections):
    in_connections = connectionPointIn.getconnections()
    if in_connections is not None:
    @@ -1791,18 +1840,22 @@
    not connections.has_key((connected, localId)):
    connectionPointIn.remove(connection)
    +
    def _filterConnectionsSingle(self, connections):
    if self.connectionPointIn is not None:
    _filterConnections(self.connectionPointIn, self.localId, connections)
    +
    def _filterConnectionsMultiple(self, connections):
    for connectionPointIn in self.getconnectionPointIn():
    _filterConnections(connectionPointIn, self.localId, connections)
    +
    def _getconnectionsdefinition(instance, connections_end):
    local_id = instance.getlocalId()
    return dict([((local_id, end), True) for end in connections_end])
    +
    def _updateConnectionsId(connectionPointIn, translation):
    connections_end = []
    connections = connectionPointIn.getconnections()
    @@ -1814,22 +1867,26 @@
    connections_end.append(new_reflocalId)
    return connections_end
    +
    def _updateConnectionsIdSingle(self, translation):
    connections_end = []
    if self.connectionPointIn is not None:
    connections_end = _updateConnectionsId(self.connectionPointIn, translation)
    return _getconnectionsdefinition(self, connections_end)
    +
    def _updateConnectionsIdMultiple(self, translation):
    connections_end = []
    for connectionPointIn in self.getconnectionPointIn():
    connections_end.extend(_updateConnectionsId(connectionPointIn, translation))
    return _getconnectionsdefinition(self, connections_end)
    +
    def _translate(self, dx, dy):
    self.setx(self.getx() + dx)
    self.sety(self.gety() + dy)
    +
    def _translateConnections(connectionPointIn, dx, dy):
    connections = connectionPointIn.getconnections()
    if connections is not None:
    @@ -1838,22 +1895,27 @@
    position.setx(position.getx() + dx)
    position.sety(position.gety() + dy)
    +
    def _translateSingle(self, dx, dy):
    _translate(self, dx, dy)
    if self.connectionPointIn is not None:
    _translateConnections(self.connectionPointIn, dx, dy)
    +
    def _translateMultiple(self, dx, dy):
    _translate(self, dx, dy)
    for connectionPointIn in self.getconnectionPointIn():
    _translateConnections(connectionPointIn, dx, dy)
    +
    def _updateElementName(self, old_name, new_name):
    pass
    +
    def _updateElementAddress(self, address_model, new_leading):
    pass
    +
    def _SearchInElement(self, criteria, parent_infos=[]):
    return []
    @@ -1872,6 +1934,7 @@
    "multiple": _updateConnectionsIdMultiple},
    }
    +
    def _initElementClass(name, parent, connectionPointInType="none"):
    cls = PLCOpenParser.GetElementClass(name, parent)
    if cls:
    @@ -1959,13 +2022,16 @@
    _initElementClass("leftPowerRail", "ldObjects")
    _initElementClass("rightPowerRail", "ldObjects", "multiple")
    +
    def _UpdateLDElementName(self, old_name, new_name):
    if TextMatched(self.variable, old_name):
    self.variable = new_name
    +
    def _UpdateLDElementAddress(self, address_model, new_leading):
    self.variable = update_address(self.variable, address_model, new_leading)
    +
    def _getSearchInLDElement(ld_element_type):
    def SearchInLDElement(self, criteria, parent_infos=[]):
    return _Search([("reference", self.variable)], criteria, parent_infos + [ld_element_type, self.getlocalId()])
    @@ -2224,13 +2290,16 @@
    return search_result
    setattr(cls, "Search", Search)
    +
    def _SearchInIOVariable(self, criteria, parent_infos=[]):
    return _Search([("expression", self.expression)], criteria, parent_infos + ["io_variable", self.getlocalId()])
    +
    def _UpdateIOElementName(self, old_name, new_name):
    if TextMatched(self.expression, old_name):
    self.expression = new_name
    +
    def _UpdateIOElementAddress(self, address_model, new_leading):
    self.expression = update_address(self.expression, address_model, new_leading)
    @@ -2404,6 +2473,7 @@
    return self.content.getvalue()
    setattr(cls, "getvalue", getvalue)
    +
    def extractValues(values):
    items = values.split(",")
    i = 1
    --- a/plcopen/structures.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/plcopen/structures.py Mon Aug 14 23:27:15 2017 +0300
    @@ -30,10 +30,11 @@
    TypeHierarchy = dict(TypeHierarchy_list)
    -"""
    -returns true if the given data type is the same that "reference" meta-type or one of its types.
    -"""
    +
    def IsOfType(type, reference):
    + """
    + Returns true if the given data type is the same that "reference" meta-type or one of its types.
    + """
    if reference is None:
    return True
    elif type == reference:
    @@ -44,10 +45,11 @@
    return IsOfType(parent_type, reference)
    return False
    -"""
    -returns list of all types that correspont to the ANY* meta type
    -"""
    +
    def GetSubTypes(type):
    + """
    + Returns list of all types that correspont to the ANY* meta type
    + """
    return [typename for typename, parenttype in TypeHierarchy.items() if not typename.startswith("ANY") and IsOfType(typename, type)]
    DataTypeRange = dict(DataTypeRange_list)
    @@ -82,36 +84,41 @@
    "(?:%(letter)s|_(?:%(letter)s|%(digit)s))(?:_?(?:%(letter)s|%(digit)s))*$" %
    {"letter": "[a-zA-Z]", "digit": "[0-9]"})
    -# Test if identifier is valid
    +
    def TestIdentifier(identifier):
    - return IDENTIFIER_MODEL.match(identifier) is not None
    + """
    + Test if identifier is valid
    + """
    + return IDENTIFIER_MODEL.match(identifier) is not None
    #-------------------------------------------------------------------------------
    # Standard functions list generation
    #-------------------------------------------------------------------------------
    -"""
    -take a .csv file and translate it it a "csv_table"
    -"""
    def csv_file_to_table(file):
    + """
    + take a .csv file and translate it it a "csv_table"
    + """
    return [ map(string.strip,line.split(';')) for line in file.xreadlines()]
    -"""
    -seek into the csv table to a section ( section_name match 1st field )
    -return the matching row without first field
    -"""
    +
    def find_section(section_name, table):
    + """
    + seek into the csv table to a section ( section_name match 1st field )
    + return the matching row without first field
    + """
    fields = [None]
    while(fields[0] != section_name):
    fields = table.pop(0)
    return fields[1:]
    -"""
    -extract the standard functions standard parameter names and types...
    -return a { ParameterName: Type, ...}
    -"""
    +
    def get_standard_funtions_input_variables(table):
    + """
    + extract the standard functions standard parameter names and types...
    + return a { ParameterName: Type, ...}
    + """
    variables = find_section("Standard_functions_variables_types", table)
    standard_funtions_input_variables = {}
    fields = [True,True]
    @@ -121,12 +128,13 @@
    standard_funtions_input_variables[variable_from_csv['name']] = variable_from_csv['type']
    return standard_funtions_input_variables
    -"""
    -translate .csv file input declaration into PLCOpenEditor interessting values
    -in : "(ANY_NUM, ANY_NUM)" and { ParameterName: Type, ...}
    -return [("IN1","ANY_NUM","none"),("IN2","ANY_NUM","none")]
    -"""
    +
    def csv_input_translate(str_decl, variables, base):
    + """
    + translate .csv file input declaration into PLCOpenEditor interessting values
    + in : "(ANY_NUM, ANY_NUM)" and { ParameterName: Type, ...}
    + return [("IN1","ANY_NUM","none"),("IN2","ANY_NUM","none")]
    + """
    decl = str_decl.replace('(','').replace(')','').replace(' ','').split(',')
    params = []
    @@ -145,8 +153,9 @@
    return params
    -"""
    -Returns this kind of declaration for all standard functions
    +def get_standard_funtions(table):
    + """
    + Returns this kind of declaration for all standard functions
    [{"name" : "Numerical", 'list': [ {
    'baseinputnumber': 1,
    @@ -157,8 +166,7 @@
    'name': 'ADD',
    'outputs': [('OUT', 'ANY_NUM', 'none')],
    'type': 'function'}, ...... ] },.....]
    -"""
    -def get_standard_funtions(table):
    + """
    variables = get_standard_funtions_input_variables(table)
    --- a/py_ext/PythonEditor.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/py_ext/PythonEditor.py Mon Aug 14 23:27:15 2017 +0300
    @@ -28,6 +28,7 @@
    from controls.CustomStyledTextCtrl import faces
    from editors.CodeFileEditor import CodeFileEditor, CodeEditor
    +
    class PythonCodeEditor(CodeEditor):
    KEYWORDS = keyword.kwlist
    --- a/py_ext/PythonFileCTNMixin.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/py_ext/PythonFileCTNMixin.py Mon Aug 14 23:27:15 2017 +0300
    @@ -33,6 +33,7 @@
    from CodeFileTreeNode import CodeFile
    from PythonEditor import PythonEditor
    +
    class PythonFileCTNMixin(CodeFile):
    CODEFILE_NAME = "PyFile"
    --- a/py_ext/py_ext.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/py_ext/py_ext.py Mon Aug 14 23:27:15 2017 +0300
    @@ -28,6 +28,7 @@
    from PythonFileCTNMixin import PythonFileCTNMixin
    import util.paths as paths
    +
    class PythonLibrary(POULibrary):
    def GetLibraryPath(self):
    return paths.AbsNeighbourFile(__file__, "pous.xml")
    @@ -56,6 +57,7 @@
    return (["py_ext"], [(Gen_Pythonfile_path, IECCFLAGS)], True), ""
    +
    class PythonFile(PythonFileCTNMixin):
    def GetIconName(self):
    --- a/runtime/NevowServer.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/runtime/NevowServer.py Mon Aug 14 23:27:15 2017 +0300
    @@ -36,6 +36,7 @@
    WorkingDir = None
    +
    class PLCHMI(athena.LiveElement):
    initialised = False
    @@ -46,16 +47,19 @@
    def HMIinitialisation(self):
    self.HMIinitialised(None)
    +
    class DefaultPLCStartedHMI(PLCHMI):
    docFactory = loaders.stan(tags.div(render=tags.directive('liveElement'))[
    tags.h1["PLC IS NOW STARTED"],
    ])
    +
    class PLCStoppedHMI(PLCHMI):
    docFactory = loaders.stan(tags.div(render=tags.directive('liveElement'))[
    tags.h1["PLC IS STOPPED"],
    ])
    +
    class MainPage(athena.LiveElement):
    jsClass = u"WebInterface.PLC"
    docFactory = loaders.stan(tags.div(render=tags.directive('liveElement'))[
    @@ -110,6 +114,7 @@
    for child in self.liveFragmentChildren[:]:
    child.detach()
    +
    class WebInterface(athena.LivePage):
    docFactory = loaders.stan([tags.raw(xhtml_header),
    @@ -173,6 +178,7 @@
    #print reason
    #print "We will be called back when the client disconnects"
    +
    def RegisterWebsite(port):
    website = WebInterface()
    site = appserver.NevowSite(website)
    @@ -182,6 +188,7 @@
    print _("HTTP interface port :"), port
    return website
    +
    class statuslistener:
    def __init__(self, site):
    self.oldstate = None
    @@ -194,5 +201,6 @@
    if action is not None: action ()
    self.oldstate = state
    +
    def website_statuslistener_factory(site):
    return statuslistener(site).listen
    --- a/runtime/PLCObject.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/runtime/PLCObject.py Mon Aug 14 23:27:15 2017 +0300
    @@ -39,6 +39,8 @@
    from _ctypes import dlopen, dlclose
    import traceback
    +
    +
    def get_last_traceback(tb):
    while tb.tb_next:
    tb = tb.tb_next
    @@ -49,10 +51,12 @@
    "win32":".dll",
    }.get(sys.platform, "")
    +
    def PLCprint(message):
    sys.stdout.write("PLCobject : "+message+"\n")
    sys.stdout.flush()
    +
    class PLCObject(pyro.ObjBase):
    def __init__(self, workingdir, daemon, argv, statuschange, evaluator, pyruntimevars):
    pyro.ObjBase.__init__(self)
    --- a/runtime/ServicePublisher.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/runtime/ServicePublisher.py Mon Aug 14 23:27:15 2017 +0300
    @@ -27,6 +27,7 @@
    service_type = '_PYRO._tcp.local.'
    +
    class ServicePublisher():
    def __init__(self):
    # type: fully qualified service type name
    --- a/runtime/WampClient.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/runtime/WampClient.py Mon Aug 14 23:27:15 2017 +0300
    @@ -51,6 +51,7 @@
    DoOnJoin = []
    +
    def GetCallee(name):
    """ Get Callee or Subscriber corresponding to '.' spearated object path """
    global _PySrv
    @@ -59,6 +60,7 @@
    while names: obj = getattr(obj, names.pop(0))
    return obj
    +
    class WampSession(wamp.ApplicationSession):
    @inlineCallbacks
    @@ -81,6 +83,7 @@
    _WampSession = None
    print 'WAMP session left'
    +
    class ReconnectingWampWebSocketClientFactory(WampWebSocketClientFactory, ReconnectingClientFactory):
    def clientConnectionFailed(self, connector, reason):
    print("WAMP Client connection failed .. retrying ..")
    @@ -89,11 +92,13 @@
    print("WAMP Client connection lost .. retrying ..")
    self.retry(connector)
    +
    def LoadWampClientConf(wampconf):
    WSClientConf = json.load(open(wampconf))
    return WSClientConf
    +
    def RegisterWampClient(wampconf):
    WSClientConf = LoadWampClientConf(wampconf)
    @@ -122,10 +127,12 @@
    print "WAMP client connecting to :",WSClientConf["url"]
    return conn
    +
    def GetSession():
    global _WampSession
    return _WampSession
    +
    def SetServer(pysrv):
    global _PySrv
    _PySrv = pysrv
    --- a/svgui/pyjs/build.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/svgui/pyjs/build.py Mon Aug 14 23:27:15 2017 +0300
    @@ -63,6 +63,7 @@
    def read_boilerplate(data_dir, filename):
    return open(join(data_dir, "builder/boilerplate", filename)).read()
    +
    def copy_boilerplate(data_dir, filename, output_dir):
    filename = join(data_dir, "builder/boilerplate", filename)
    shutil.copy(filename, output_dir)
    @@ -103,6 +104,7 @@
    if errors:
    print errors
    +
    def check_html_file(source_file, dest_path):
    """ Checks if a base HTML-file is available in the PyJamas
    output directory.
    @@ -523,15 +525,19 @@
    return app_files
    +
    def flattenlist(ll):
    res = []
    for l in ll:
    res += l
    return res
    -# creates sub-dependencies e.g. pyjamas.ui.Widget
    -# creates pyjamas.ui.Widget, pyjamas.ui and pyjamas.
    +
    def subdeps(m):
    + """
    + creates sub-dependencies e.g. pyjamas.ui.Widget
    + creates pyjamas.ui.Widget, pyjamas.ui and pyjamas.
    + """
    d = []
    m = m.split(".")
    for i in range(0, len(m)):
    @@ -540,6 +546,7 @@
    import time
    +
    def add_subdeps(deps, mod_name):
    sd = subdeps(mod_name)
    if len(sd) == 1:
    @@ -558,14 +565,18 @@
    #print deps
    return res
    -# makes unique and preserves list order
    +
    def uniquify(md):
    + """
    + makes unique and preserves list order
    + """
    res = []
    for m in md:
    if m not in res:
    res.append(m)
    return res
    +
    def filter_mods(app_name, md):
    while 'sys' in md:
    md.remove('sys')
    @@ -578,6 +589,7 @@
    return uniquify(md)
    +
    def filter_deps(app_name, deps):
    res = {}
    @@ -588,11 +600,13 @@
    res[k] = mods
    return res
    +
    def has_nodeps(mod, deps):
    if not deps.has_key(mod) or not deps[mod]:
    return True
    return False
    +
    def nodeps_list(mod_list, deps):
    res = []
    for mod in mod_list:
    @@ -655,6 +669,7 @@
    return ordered_deps
    +
    def main():
    global app_platforms
    --- a/svgui/pyjs/jsonrpc/django/jsonrpc.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/svgui/pyjs/jsonrpc/django/jsonrpc.py Mon Aug 14 23:27:15 2017 +0300
    @@ -18,11 +18,13 @@
    # dump jsonservice into urlpatterns:
    # (r'^service1/$', 'djangoapp.views.jsonservice'),
    +
    class JSONRPCService(JSONRPCServiceBase):
    def __call__(self, request, extra=None):
    return self.process(request.raw_post_data)
    +
    def jsonremote(service):
    """Make JSONRPCService a decorator so that you can write :
    @@ -64,6 +66,7 @@
    from django import forms
    +
    def builderrors(form):
    d = {}
    for error in form.errors.keys():
    @@ -91,6 +94,7 @@
    'IPAddressField': ['max_length', 'min_length'],
    }
    +
    def describe_field_errors(field):
    res = {}
    field_type = field.__class__.__name__
    @@ -102,6 +106,7 @@
    res['fields'] = map(describe_field, field.fields)
    return res
    +
    def describe_fields_errors(fields, field_names):
    res = {}
    if not field_names:
    @@ -111,6 +116,7 @@
    res[name] = describe_field_errors(field)
    return res
    +
    def describe_field(field):
    res = {}
    field_type = field.__class__.__name__
    @@ -121,6 +127,7 @@
    res['fields'] = map(describe_field, field.fields)
    return res
    +
    def describe_fields(fields, field_names):
    res = {}
    if not field_names:
    @@ -130,6 +137,7 @@
    res[name] = describe_field(field)
    return res
    +
    class FormProcessor(JSONRPCService):
    def __init__(self, forms, _formcls=None):
    @@ -206,6 +214,7 @@
    import datetime
    from datetime import date
    +
    def dict_datetimeflatten(item):
    d = {}
    for k, v in item.items():
    @@ -218,6 +227,7 @@
    d[k] = v
    return d
    +
    def json_convert(l, fields=None):
    res = []
    for item in serialize('python', l, fields=fields):
    --- a/svgui/pyjs/jsonrpc/jsonrpc.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/svgui/pyjs/jsonrpc/jsonrpc.py Mon Aug 14 23:27:15 2017 +0300
    @@ -2,6 +2,7 @@
    import types
    import sys
    +
    class JSONRPCServiceBase:
    def __init__(self):
    --- a/svgui/pyjs/jsonrpc/web2py/jsonrpc.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/svgui/pyjs/jsonrpc/web2py/jsonrpc.py Mon Aug 14 23:27:15 2017 +0300
    @@ -1,5 +1,6 @@
    from pyjs.jsonrpc import JSONRPCServiceBase
    +
    class JSONRPCService(JSONRPCServiceBase):
    def serve(self):
    --- a/svgui/pyjs/lib/pyjslib.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/svgui/pyjs/lib/pyjslib.py Mon Aug 14 23:27:15 2017 +0300
    @@ -19,6 +19,7 @@
    # must declare import _before_ importing sys
    +
    def import_module(path, parent_module, module_name, dynamic=1, async=False):
    """
    """
    @@ -184,11 +185,13 @@
    }
    """)
    +
    class Object:
    pass
    object = Object
    +
    class Modload:
    def __init__(self, path, app_modlist, app_imported_fn, dynamic,
    @@ -212,11 +215,13 @@
    else:
    import_wait(getattr(self, "next"), self.parent_mod, self.dynamic)
    +
    def get_module(module_name):
    ev = "__mod = %s;" % module_name
    JS("pyjs_eval(ev);")
    return __mod
    +
    def preload_app_modules(path, app_modnames, app_imported_fn, dynamic,
    parent_mod=None):
    @@ -225,6 +230,7 @@
    import sys
    +
    class BaseException:
    name = "BaseException"
    @@ -242,27 +248,31 @@
    def toString(self):
    return str(self)
    -class Exception(BaseException):
    +class Exception(BaseException):
    name = "Exception"
    +
    class TypeError(BaseException):
    name = "TypeError"
    +
    class StandardError(Exception):
    name = "StandardError"
    +
    class LookupError(StandardError):
    name = "LookupError"
    def toString(self):
    return self.name + ": " + self.args[0]
    +
    class KeyError(LookupError):
    name = "KeyError"
    +
    class AttributeError(StandardError):
    -
    name = "AttributeError"
    def toString(self):
    @@ -407,6 +417,7 @@
    """)
    +
    class Class:
    def __init__(self, name):
    self.name = name
    @@ -414,6 +425,7 @@
    def __str___(self):
    return self.name
    +
    def eq(a,b):
    JS("""
    if (pyjslib.hasattr(a, "__cmp__")) {
    @@ -424,6 +436,7 @@
    return a == b;
    """)
    +
    def cmp(a,b):
    if hasattr(a, "__cmp__"):
    return a.__cmp__(b)
    @@ -436,6 +449,7 @@
    else:
    return 0
    +
    def bool(v):
    # this needs to stay in native code without any dependencies here,
    # because this is used by if and while, we need to prevent
    @@ -456,6 +470,7 @@
    return Boolean(v);
    """)
    +
    class List:
    def __init__(self, data=None):
    JS("""
    @@ -605,6 +620,7 @@
    list = List
    +
    class Tuple:
    def __init__(self, data=None):
    JS("""
    @@ -900,6 +916,8 @@
    dict = Dict
    # taken from mochikit: range( [start,] stop[, step] )
    +
    +
    def range():
    JS("""
    var start = 0;
    @@ -930,6 +948,7 @@
    }
    """)
    +
    def slice(object, lower, upper):
    JS("""
    if (pyjslib.isString(object)) {
    @@ -948,6 +967,7 @@
    return null;
    """)
    +
    def str(text):
    JS("""
    if (pyjslib.hasattr(text,"__str__")) {
    @@ -956,6 +976,7 @@
    return String(text);
    """)
    +
    def ord(x):
    if(isString(x) and len(x) is 1):
    JS("""
    @@ -967,11 +988,13 @@
    """)
    return None
    +
    def chr(x):
    JS("""
    return String.fromCharCode(x)
    """)
    +
    def is_basetype(x):
    JS("""
    var t = typeof(x);
    @@ -983,6 +1006,7 @@
    ;
    """)
    +
    def get_pyjs_classtype(x):
    JS("""
    if (pyjslib.hasattr(x, "__class__"))
    @@ -992,6 +1016,7 @@
    return null;
    """)
    +
    def repr(x):
    """ Return the string representation of 'x'.
    """
    @@ -1088,16 +1113,19 @@
    return "<" + constructor + " object>";
    """)
    +
    def float(text):
    JS("""
    return parseFloat(text);
    """)
    +
    def int(text, radix=0):
    JS("""
    return parseInt(text, radix);
    """)
    +
    def len(object):
    JS("""
    if (object==null) return 0;
    @@ -1105,6 +1133,7 @@
    return object.length;
    """)
    +
    def isinstance(object_, classinfo):
    if pyjslib.isUndefined(object_):
    return False
    @@ -1119,6 +1148,7 @@
    else:
    return _isinstance(object_, classinfo)
    +
    def _isinstance(object_, classinfo):
    if not pyjslib.isObject(object_):
    return False
    @@ -1130,6 +1160,7 @@
    return false;
    """)
    +
    def getattr(obj, name, default_):
    JS("""
    if ((!pyjslib.isObject(obj))||(pyjslib.isUndefined(obj[name]))){
    @@ -1151,6 +1182,7 @@
    return fnwrap;
    """)
    +
    def setattr(obj, name, value):
    JS("""
    if (!pyjslib.isObject(obj)) return null;
    @@ -1159,6 +1191,7 @@
    """)
    +
    def hasattr(obj, name):
    JS("""
    if (!pyjslib.isObject(obj)) return false;
    @@ -1167,6 +1200,7 @@
    return true;
    """)
    +
    def dir(obj):
    JS("""
    var properties=new pyjslib.List();
    @@ -1174,6 +1208,7 @@
    return properties;
    """)
    +
    def filter(obj, method, sequence=None):
    # object context is LOST when a method is passed, hence object must be passed separately
    # to emulate python behaviour, should generate this code inline rather than as a function call
    @@ -1240,6 +1275,7 @@
    next_hash_id = 0
    +
    def hash(obj):
    JS("""
    if (obj == null) return null;
    @@ -1259,41 +1295,49 @@
    return (a != null && (typeof a == 'object')) || pyjslib.isFunction(a);
    """)
    +
    def isFunction(a):
    JS("""
    return typeof a == 'function';
    """)
    +
    def isString(a):
    JS("""
    return typeof a == 'string';
    """)
    +
    def isNull(a):
    JS("""
    return typeof a == 'object' && !a;
    """)
    +
    def isArray(a):
    JS("""
    return pyjslib.isObject(a) && a.constructor == Array;
    """)
    +
    def isUndefined(a):
    JS("""
    return typeof a == 'undefined';
    """)
    +
    def isIteratable(a):
    JS("""
    return pyjslib.isString(a) || (pyjslib.isObject(a) && a.__iter__);
    """)
    +
    def isNumber(a):
    JS("""
    return typeof a == 'number' && isFinite(a);
    """)
    +
    def toJSObjects(x):
    """
    Convert the pyjs pythonic List and Dict objects into javascript Object and Array
    @@ -1337,6 +1381,7 @@
    """)
    return x
    +
    def printFunc(objs):
    JS("""
    if ($wnd.console==undefined) return;
    @@ -1348,6 +1393,7 @@
    console.debug(s)
    """)
    +
    def type(clsname, bases=None, methods=None):
    """ creates a class, derived from bases, with methods and variables
    """
    --- a/svgui/pyjs/lib/sys.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/svgui/pyjs/lib/sys.py Mon Aug 14 23:27:15 2017 +0300
    @@ -11,22 +11,27 @@
    appname = None
    +
    def setloadpath(lp):
    global loadpath
    loadpath = lp
    +
    def setappname(an):
    global appname
    appname = an
    +
    def getloadpath():
    global loadpath
    return loadpath
    +
    def addoverride(module_name, path):
    global overrides
    overrides[module_name] = path
    +
    def addstack(linedebug):
    JS("""
    if (pyjslib.bool((sys.stacktrace === null))) {
    @@ -34,11 +39,14 @@
    }
    sys.stacktrace.append(linedebug);
    """)
    +
    +
    def popstack():
    JS("""
    sys.stacktrace.pop()
    """)
    +
    def printstack():
    JS("""
    var res = '';
    --- a/svgui/pyjs/pyjs.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/svgui/pyjs/pyjs.py Mon Aug 14 23:27:15 2017 +0300
    @@ -90,6 +90,7 @@
    "tuple",
    )
    +
    def pyjs_builtin_remap(name):
    # XXX HACK!
    if name == 'list':
    @@ -119,17 +120,20 @@
    (';', r'\x3B')
    ) + tuple([('%c' % z, '\\x%02X' % z) for z in range(32)])
    +
    def escapejs(value):
    """Hex encodes characters for use in JavaScript strings."""
    for bad, good in JS_ESCAPES:
    value = value.replace(bad, good)
    return value
    +
    def uuprefix(name, leave_alone=0):
    name = name.split(".")
    name = name[:leave_alone] + map(lambda x: "__%s" % x, name[leave_alone:])
    return '.'.join(name)
    +
    class Klass:
    klasses = {}
    @@ -154,9 +158,11 @@
    def __str__(self):
    return self.message
    +
    def strip_py(name):
    return name
    +
    def mod_var_name_decl(raw_module_name):
    """ function to get the last component of the module e.g.
    pyjamas.ui.DOM into the "namespace". i.e. doing
    @@ -174,6 +180,7 @@
    child_name = name[-1]
    return "var %s = %s;\n" % (child_name, raw_module_name)
    +
    def gen_mod_import(parentName, importName, dynamic=1):
    #pyjs_ajax_eval("%(n)s.cache.js", null, true);
    return """
    @@ -181,6 +188,7 @@
    """ % ({'p': parentName, 'd': dynamic, 'n': importName}) + \
    mod_var_name_decl(importName)
    +
    class Translator:
    def __init__(self, mn, module_name, raw_module_name, src, debug, mod, output,
    @@ -1534,6 +1542,7 @@
    import cStringIO
    +
    def translate(file_name, module_name, debug=False):
    f = file(file_name, "r")
    src = f.read()
    @@ -1633,10 +1642,12 @@
    target.defaults = source.defaults
    target.doc = source.doc # @@@ not sure we need to do this any more
    +
    def dotreplace(fname):
    path, ext = os.path.splitext(fname)
    return path.replace(".", "/") + ext
    +
    class AppTranslator:
    def __init__(self, library_dirs=[], parser=None, dynamic=False,
    @@ -1757,6 +1768,7 @@
    usage: %s file_name [module_name]
    """
    +
    def main():
    import sys
    if len(sys.argv)<2:
    --- a/svgui/svgui.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/svgui/svgui.py Mon Aug 14 23:27:15 2017 +0300
    @@ -35,10 +35,12 @@
    from docutil import open_svg
    from py_ext import PythonFileCTNMixin
    +
    class SVGUILibrary(POULibrary):
    def GetLibraryPath(self):
    return paths.AbsNeighbourFile(__file__, "pous.xml")
    +
    class SVGUI(PythonFileCTNMixin):
    ConfNodeMethods = [
    --- a/svgui/svgui_server.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/svgui/svgui_server.py Mon Aug 14 23:27:15 2017 +0300
    @@ -32,11 +32,14 @@
    svguiWidgets = {}
    currentId = 0
    +
    +
    def getNewId():
    global currentId
    currentId += 1
    return currentId
    +
    class SvguiWidget:
    def __init__(self, classname, id, **kwargs):
    @@ -83,6 +86,7 @@
    if self.changed:
    self.RefreshInterface()
    +
    def get_object_init_state(obj):
    # Convert objects to a dictionary of their representation
    attrs = obj.attrs.copy()
    @@ -93,6 +97,7 @@
    }
    return d
    +
    def get_object_current_state(obj):
    # Convert objects to a dictionary of their representation
    d = { '__class__': obj.classname,
    @@ -101,6 +106,7 @@
    }
    return d
    +
    class SVGUI_HMI(website.PLCHMI):
    jsClass = u"LiveSVGPage.LiveSVGWidget"
    @@ -123,6 +129,7 @@
    def setattr(self, id, attrname, value):
    svguiWidgets[id].setinput(attrname, value)
    +
    def createSVGUIControl(*args, **kwargs):
    id = getNewId()
    gad = SvguiWidget(args[0], id, **kwargs)
    @@ -133,16 +140,19 @@
    interface.callRemote('init', gadget)
    return id
    +
    def setAttr(id, attrname, value):
    gad = svguiWidgets.get(id, None)
    if gad is not None:
    gad.setoutput(attrname, value)
    +
    def updateAttr(id, **kwargs):
    gad = svguiWidgets.get(id, None)
    if gad is not None:
    gad.updateoutput(**kwargs)
    +
    def getAttr(id, attrname, default=None):
    gad = svguiWidgets.get(id, None)
    if gad is not None:
    --- a/svgui/svguilib.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/svgui/svguilib.py Mon Aug 14 23:27:15 2017 +0300
    @@ -22,6 +22,7 @@
    # along with this program; if not, write to the Free Software
    # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
    +
    class button:
    def __init__(self, parent, id, args):
    @@ -115,6 +116,7 @@
    self.updateElements()
    self.dragging = False
    +
    class textControl:
    def __init__(self, parent, id, args):
    --- a/targets/Generic/__init__.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/targets/Generic/__init__.py Mon Aug 14 23:27:15 2017 +0300
    @@ -24,5 +24,6 @@
    from ..toolchain_makefile import toolchain_makefile
    +
    class Generic_target(toolchain_makefile):
    pass
    --- a/targets/Linux/__init__.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/targets/Linux/__init__.py Mon Aug 14 23:27:15 2017 +0300
    @@ -24,6 +24,7 @@
    from ..toolchain_gcc import toolchain_gcc
    +
    class Linux_target(toolchain_gcc):
    dlopen_prefix = "./"
    extension = ".so"
    --- a/targets/Win32/__init__.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/targets/Win32/__init__.py Mon Aug 14 23:27:15 2017 +0300
    @@ -24,6 +24,7 @@
    from ..toolchain_gcc import toolchain_gcc
    +
    class Win32_target(toolchain_gcc):
    dlopen_prefix = ""
    extension = ".dll"
    --- a/targets/Xenomai/__init__.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/targets/Xenomai/__init__.py Mon Aug 14 23:27:15 2017 +0300
    @@ -24,6 +24,7 @@
    from ..toolchain_gcc import toolchain_gcc
    +
    class Xenomai_target(toolchain_gcc):
    dlopen_prefix = "./"
    extension = ".so"
    --- a/targets/__init__.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/targets/__init__.py Mon Aug 14 23:27:15 2017 +0300
    @@ -38,6 +38,8 @@
    import util.paths as paths
    _base_path = paths.AbsDir(__file__)
    +
    +
    def _GetLocalTargetClassFactory(name):
    return lambda:getattr(__import__(name,globals(),locals()), name+"_target")
    @@ -54,9 +56,11 @@
    toolchains = {"gcc": path.join(_base_path, "XSD_toolchain_gcc"),
    "makefile": path.join(_base_path, "XSD_toolchain_makefile")}
    +
    def GetBuilder(targetname):
    return targets[targetname]["class"]()
    +
    def GetTargetChoices():
    DictXSD_toolchain = {}
    targetchoices = ""
    @@ -74,15 +78,18 @@
    return targetchoices
    +
    def GetTargetCode(targetname):
    codedesc = targets[targetname]["code"]
    code = "\n".join([open(fpath).read() for fname, fpath in sorted(codedesc.items())])
    return code
    +
    def GetHeader():
    filename = paths.AbsNeighbourFile(__file__,"beremiz.h")
    return open(filename).read()
    +
    def GetCode(name):
    filename = paths.AbsNeighbourFile(__file__,name)
    return open(filename).read()
    --- a/targets/toolchain_gcc.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/targets/toolchain_gcc.py Mon Aug 14 23:27:15 2017 +0300
    @@ -31,6 +31,7 @@
    includes_re = re.compile('\s*#include\s*["<]([^">]*)[">].*')
    +
    class toolchain_gcc():
    """
    This abstract class contains GCC specific code.
    --- a/targets/toolchain_makefile.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/targets/toolchain_makefile.py Mon Aug 14 23:27:15 2017 +0300
    @@ -32,6 +32,7 @@
    includes_re = re.compile('\s*#include\s*["<]([^">]*)[">].*')
    +
    class toolchain_makefile():
    def __init__(self, CTRInstance):
    self.CTRInstance = CTRInstance
    --- a/targets/typemapping.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/targets/typemapping.py Mon Aug 14 23:27:15 2017 +0300
    @@ -30,6 +30,7 @@
    from ctypes import *
    from datetime import timedelta as td
    +
    class IEC_STRING(Structure):
    """
    Must be changed according to changes in iec_types.h
    @@ -37,6 +38,7 @@
    _fields_ = [("len", c_uint8),
    ("body", c_char * 126)]
    +
    class IEC_TIME(Structure):
    """
    Must be changed according to changes in iec_types.h
    @@ -44,7 +46,10 @@
    _fields_ = [("s", c_long), #tv_sec
    ("ns", c_long)] #tv_nsec
    +
    def _t(t, u=lambda x:x.value, p=lambda t,x:t(x)): return (t, u, p)
    +
    +
    def _ttime(): return (IEC_TIME,
    lambda x:td(0, x.s, x.ns/1000),
    lambda t,x:t(x.days * 24 * 3600 + x.seconds, x.microseconds*1000))
    @@ -86,6 +91,7 @@
    # Construct debugger natively supported types
    DebugTypesSize = dict([(key,sizeof(t)) for key,(t,p,u) in SameEndianessTypeTranslator.iteritems() if t is not None])
    +
    def UnpackDebugBuffer(buff, indexes):
    res = []
    buffoffset = 0
    --- a/util/BitmapLibrary.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/util/BitmapLibrary.py Mon Aug 14 23:27:15 2017 +0300
    @@ -37,10 +37,12 @@
    # Library Helpers
    #-------------------------------------------------------------------------------
    +
    def AddBitmapFolder(path):
    if os.path.exists(path) and os.path.isdir(path) and path not in BitmapFolders:
    BitmapFolders.append(path)
    +
    def SearchBitmap(bmp_name):
    for folder in BitmapFolders:
    bmp_path = os.path.join(folder, bmp_name + ".png")
    @@ -48,6 +50,7 @@
    return wx.Bitmap(bmp_path)
    return None
    +
    def GetBitmap(bmp_name1, bmp_name2=None, size=None):
    bmp = BitmapLibrary.get((bmp_name1, bmp_name2, size))
    if bmp is not None:
    --- a/util/MiniTextControler.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/util/MiniTextControler.py Mon Aug 14 23:27:15 2017 +0300
    @@ -28,6 +28,7 @@
    import os
    +
    class MiniTextControler:
    def __init__(self, filepath, controller):
    --- a/util/ProcessLogger.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/util/ProcessLogger.py Mon Aug 14 23:27:15 2017 +0300
    @@ -69,6 +69,7 @@
    self.finished = True
    self.endcallback(self.Proc.pid, err)
    +
    class ProcessLogger:
    def __init__(self, logger, Command, finish_callback = None,
    no_stdout = False, no_stderr = False, no_gui = True,
    --- a/util/TranslationCatalogs.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/util/TranslationCatalogs.py Mon Aug 14 23:27:15 2017 +0300
    @@ -32,6 +32,7 @@
    # Define locale for wx
    locale = wx.Locale(langid)
    +
    def GetDomain(path):
    for name in os.listdir(path):
    filepath = os.path.join(path, name)
    @@ -44,6 +45,7 @@
    return basename
    return None
    +
    def AddCatalog(locale_dir):
    if os.path.exists(locale_dir) and os.path.isdir(locale_dir):
    domain = GetDomain(locale_dir)
    --- a/util/Zeroconf.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/util/Zeroconf.py Mon Aug 14 23:27:15 2017 +0300
    @@ -183,29 +183,36 @@
    # utility functions
    +
    def currentTimeMillis():
    """Current system time in milliseconds"""
    return time.time() * 1000
    # Exceptions
    +
    class NonLocalNameException(Exception):
    pass
    +
    class NonUniqueNameException(Exception):
    pass
    +
    class NamePartTooLongException(Exception):
    pass
    +
    class AbstractMethodException(Exception):
    pass
    +
    class BadTypeInNameException(Exception):
    pass
    # implementation classes
    +
    class DNSEntry(object):
    """A DNS entry"""
    @@ -254,6 +261,7 @@
    result += "]"
    return result
    +
    class DNSQuestion(DNSEntry):
    """A DNS question entry"""
    @@ -332,6 +340,7 @@
    arg = "%s/%s,%s" % (self.ttl, self.getRemainingTTL(currentTimeMillis()), other)
    return DNSEntry.toString(self, "record", arg)
    +
    class DNSAddress(DNSRecord):
    """A DNS address record"""
    @@ -356,6 +365,7 @@
    except:
    return self.address
    +
    class DNSHinfo(DNSRecord):
    """A DNS host information record"""
    @@ -379,6 +389,7 @@
    """String representation"""
    return self.cpu + " " + self.os
    +
    class DNSPointer(DNSRecord):
    """A DNS pointer record"""
    @@ -400,6 +411,7 @@
    """String representation"""
    return self.toString(self.alias)
    +
    class DNSText(DNSRecord):
    """A DNS text record"""
    @@ -424,6 +436,7 @@
    else:
    return self.toString(self.text)
    +
    class DNSService(DNSRecord):
    """A DNS service record"""
    @@ -451,6 +464,7 @@
    """String representation"""
    return self.toString("%s:%s" % (self.server, self.port))
    +
    class DNSIncoming(object):
    """Object representation of an incoming DNS packet"""
    @@ -890,6 +904,7 @@
    self.condition.notify()
    self.condition.release()
    +
    class Listener(object):
    """A Listener is used by this module to listen on the multicast
    group to which DNS messages are sent, allowing the implementation
    --- a/util/misc.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/util/misc.py Mon Aug 14 23:27:15 2017 +0300
    @@ -29,8 +29,9 @@
    import os
    import sys
    -# helper func to check path write permission
    +
    def CheckPathPerm(path):
    + """ Helper func to check path write permission """
    if path is None or not os.path.isdir(path):
    return False
    for root, dirs, files in os.walk(path):
    @@ -41,6 +42,7 @@
    return False
    return True
    +
    def GetClassImporter(classpath):
    if type(classpath)==str:
    def fac():
    @@ -50,6 +52,7 @@
    else:
    return classpath
    +
    def InstallLocalRessources(CWD):
    from BitmapLibrary import AddBitmapFolder
    from TranslationCatalogs import AddCatalog
    --- a/util/paths.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/util/paths.py Mon Aug 14 23:27:15 2017 +0300
    @@ -25,15 +25,18 @@
    import os
    import sys
    +
    def AbsFile(file):
    if isinstance(file, str):
    file = unicode(file,sys.getfilesystemencoding())
    return file
    +
    def AbsDir(file):
    file = AbsFile(file)
    return os.path.dirname(os.path.realpath(file))
    +
    def AbsNeighbourFile(file, *args):
    return os.path.join(AbsDir(file), *args)
    --- a/version.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/version.py Mon Aug 14 23:27:15 2017 +0300
    @@ -28,6 +28,7 @@
    import util.paths as paths
    +
    def GetCommunityHelpMsg():
    return _("The best place to ask questions about Beremiz/PLCOpenEditor\n"
    "is project's mailing list: beremiz-devel@lists.sourceforge.net\n"
    @@ -38,6 +39,7 @@
    "You can subscribe to the list here:\n"
    "https://lists.sourceforge.net/lists/listinfo/beremiz-devel")
    +
    def GetAppRevision():
    rev = None
    app_dir=paths.AbsDir(__file__)
    @@ -63,6 +65,7 @@
    pass
    return rev
    +
    def GetAboutDialogInfo():
    import wx
    info = wx.AboutDialogInfo()
    --- a/wxglade_hmi/wxglade_hmi.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/wxglade_hmi/wxglade_hmi.py Mon Aug 14 23:27:15 2017 +0300
    @@ -32,6 +32,7 @@
    import util.paths as paths
    from py_ext import PythonFileCTNMixin
    +
    class WxGladeHMI(PythonFileCTNMixin):
    ConfNodeMethods = [
    --- a/xmlclass/xmlclass.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/xmlclass/xmlclass.py Mon Aug 14 23:27:15 2017 +0300
    @@ -33,6 +33,7 @@
    from new import classobj
    from collections import OrderedDict
    +
    def CreateNode(name):
    node = minidom.Node()
    node.nodeName = name
    @@ -40,9 +41,11 @@
    node.childNodes = []
    return node
    +
    def NodeRenameAttr(node, old_name, new_name):
    node._attrs[new_name] = node._attrs.pop(old_name)
    +
    def NodeSetAttr(node, name, value):
    attr = minidom.Attr(name)
    text = minidom.Text()
    @@ -73,6 +76,7 @@
    date_model = re.compile('([0-9]{4})-([0-9]{2})-([0-9]{2})((?:[\-\+][0-9]{2}:[0-9]{2})|Z)?$')
    datetime_model = re.compile('([0-9]{4})-([0-9]{2})-([0-9]{2})[ T]([0-9]{2}):([0-9]{2}):([0-9]{2}(?:\.[0-9]*)?)((?:[\-\+][0-9]{2}:[0-9]{2})|Z)?$')
    +
    class xml_timezone(datetime.tzinfo):
    def SetOffset(self, offset):
    @@ -98,6 +102,7 @@
    ATTRIBUTESGROUP, ELEMENTSGROUP, ATTRIBUTE, ELEMENT, CHOICE, ANY, TAG, CONSTRAINT,
    ] = range(13)
    +
    def NotSupportedYet(type):
    """
    Function that generates a function that point out to user that datatype
    @@ -110,10 +115,11 @@
    type)
    return GetUnknownValue
    -"""
    -This function calculates the number of whitespace for indentation
    -"""
    +
    def getIndent(indent, balise):
    + """
    + This function calculates the number of whitespace for indentation
    + """
    first = indent * 2
    second = first + len(balise) + 1
    return u'\t'.expandtabs(first), u'\t'.expandtabs(second)
    @@ -535,6 +541,7 @@
    return values
    return GetModelNameList
    +
    def GenerateAnyInfos(infos):
    def GetTextElement(tree):
    @@ -565,6 +572,7 @@
    "check": lambda x: isinstance(x, (StringType, UnicodeType, etree.ElementBase))
    }
    +
    def GenerateTagInfos(infos):
    def ExtractTag(tree):
    if len(tree._attrs) > 0:
    @@ -591,12 +599,14 @@
    "check": lambda x: x == None or infos["minOccurs"] == 0 and value == True
    }
    +
    def FindTypeInfos(factory, infos):
    if isinstance(infos, (UnicodeType, StringType)):
    namespace, name = DecomposeQualifiedName(infos)
    return factory.GetQualifiedNameInfos(name, namespace)
    return infos
    +
    def GetElementInitialValue(factory, infos):
    infos["elmt_type"] = FindTypeInfos(factory, infos["elmt_type"])
    if infos["minOccurs"] == 1:
    @@ -617,6 +627,7 @@
    else:
    return []
    +
    def GetContentInfos(name, choices):
    for choice_infos in choices:
    if choices_infos["type"] == "sequence":
    @@ -630,6 +641,7 @@
    return choices_infos
    return None
    +
    def ComputeContentChoices(factory, name, infos):
    choices = []
    for choice in infos["choices"]:
    @@ -650,6 +662,7 @@
    choices.append((choice["name"], choice))
    return choices
    +
    def GenerateContentInfos(factory, name, choices):
    choices_dict = {}
    for choice_name, infos in choices:
    @@ -700,6 +713,7 @@
    return None, parts[0]
    return parts
    +
    def GenerateElement(element_name, attributes, elements_model,
    accept_text=False):
    def ExtractElement(factory, node):
    @@ -735,10 +749,10 @@
    return ExtractElement
    -"""
    -Class that generate class from an XML Tree
    -"""
    class ClassFactory:
    + """
    + Class that generate class from an XML Tree
    + """
    def __init__(self, document, filepath=None, debug=False):
    self.Document = document
    @@ -1191,11 +1205,12 @@
    for classname in classnames:
    print classname
    -"""
    -Method that generate the method for generating the xml tree structure model by
    -following the attributes list defined
    -"""
    +
    def ComputeMultiplicity(name, infos):
    + """
    + Method that generate the method for generating the xml tree structure model by
    + following the attributes list defined
    + """
    if infos["minOccurs"] == 0:
    if infos["maxOccurs"] == "unbounded":
    return "(?:%s)*" % name
    @@ -1217,6 +1232,7 @@
    return "(?:%s){%d,%d}" % (name, infos["minOccurs"],
    infos["maxOccurs"])
    +
    def GetStructurePattern(classinfos):
    base_structure_pattern = (
    classinfos["base"].StructurePattern.pattern[:-1]
    @@ -1245,14 +1261,16 @@
    else:
    raise ValueError("XSD structure not yet supported!")
    -"""
    -Method that generate the method for creating a class instance
    -"""
    +
    def generateClassCreateFunction(class_definition):
    + """
    + Method that generate the method for creating a class instance
    + """
    def classCreatefunction():
    return class_definition()
    return classCreatefunction
    +
    def generateGetattrMethod(factory, class_definition, classinfos):
    attributes = dict([(attr["name"], attr) for attr in classinfos["attributes"] if attr["use"] != "prohibited"])
    optional_attributes = dict([(attr["name"], True) for attr in classinfos["attributes"] if attr["use"] == "optional"])
    @@ -1307,6 +1325,7 @@
    return getattrMethod
    +
    def generateSetattrMethod(factory, class_definition, classinfos):
    attributes = dict([(attr["name"], attr) for attr in classinfos["attributes"] if attr["use"] != "prohibited"])
    optional_attributes = dict([(attr["name"], True) for attr in classinfos["attributes"] if attr["use"] == "optional"])
    @@ -1375,6 +1394,7 @@
    return setattrMethod
    +
    def gettypeinfos(name, facets):
    if facets.has_key("enumeration") and facets["enumeration"][0] is not None:
    return facets["enumeration"][0]
    @@ -1392,6 +1412,7 @@
    return limits
    return name
    +
    def generateGetElementAttributes(factory, classinfos):
    def getElementAttributes(self):
    attr_list = []
    @@ -1406,6 +1427,7 @@
    return attr_list
    return getElementAttributes
    +
    def generateGetElementInfos(factory, classinfos):
    attributes = dict([(attr["name"], attr) for attr in classinfos["attributes"] if attr["use"] != "prohibited"])
    elements = dict([(element["name"], element) for element in classinfos["elements"]])
    @@ -1476,6 +1498,7 @@
    return {"name": name, "type": attr_type, "value": value, "use": use, "children": children}
    return getElementInfos
    +
    def generateSetElementValue(factory, classinfos):
    attributes = dict([(attr["name"], attr) for attr in classinfos["attributes"] if attr["use"] != "prohibited"])
    elements = dict([(element["name"], element) for element in classinfos["elements"]])
    @@ -1532,10 +1555,12 @@
    self.setcontentbytype(value)
    return setElementValue
    -"""
    -Methods that generates the different methods for setting and getting the attributes
    -"""
    +
    def generateInitMethod(factory, classinfos):
    + """
    + Methods that generates the different methods for setting and getting the attributes
    + """
    +
    def initMethod(self):
    if classinfos.has_key("base"):
    classinfos["base"]._init_(self)
    @@ -1554,16 +1579,19 @@
    map(self.append, initial)
    return initMethod
    +
    def generateSetMethod(attr):
    def setMethod(self, value):
    setattr(self, attr, value)
    return setMethod
    +
    def generateGetMethod(attr):
    def getMethod(self):
    return getattr(self, attr, None)
    return getMethod
    +
    def generateAddMethod(attr, factory, infos):
    def addMethod(self):
    if infos["type"] == ATTRIBUTE:
    @@ -1580,11 +1608,13 @@
    raise ValueError("Invalid class attribute!")
    return addMethod
    +
    def generateDeleteMethod(attr):
    def deleteMethod(self):
    setattr(self, attr, None)
    return deleteMethod
    +
    def generateAppendMethod(attr, maxOccurs, factory, infos):
    def appendMethod(self, value):
    infos["elmt_type"] = FindTypeInfos(factory, infos["elmt_type"])
    @@ -1598,6 +1628,7 @@
    raise ValueError("There can't be more than %d values in \"%s\"!" % (maxOccurs, attr))
    return appendMethod
    +
    def generateInsertMethod(attr, maxOccurs, factory, infos):
    def insertMethod(self, index, value):
    infos["elmt_type"] = FindTypeInfos(factory, infos["elmt_type"])
    @@ -1613,11 +1644,13 @@
    raise ValueError("There can't be more than %d values in \"%s\"!" % (maxOccurs, attr))
    return insertMethod
    +
    def generateGetChoicesMethod(choice_types):
    def getChoicesMethod(self):
    return [choice["name"] for choice in choice_types]
    return getChoicesMethod
    +
    def generateSetChoiceByTypeMethod(factory, choice_types):
    choices = dict([(choice["name"], choice) for choice in choice_types])
    def setChoiceMethod(self, content_type):
    @@ -1630,6 +1663,7 @@
    return new_content
    return setChoiceMethod
    +
    def generateAppendChoiceByTypeMethod(maxOccurs, factory, choice_types):
    choices = dict([(choice["name"], choice) for choice in choice_types])
    def appendChoiceMethod(self, content_type):
    @@ -1645,6 +1679,7 @@
    raise ValueError("There can't be more than %d values in \"content\"!" % maxOccurs)
    return appendChoiceMethod
    +
    def generateInsertChoiceByTypeMethod(maxOccurs, factory, choice_types):
    choices = dict([(choice["name"], choice) for choice in choice_types])
    def insertChoiceMethod(self, index, content_type):
    @@ -1660,6 +1695,7 @@
    raise ValueError("There can't be more than %d values in \"content\"!" % maxOccurs)
    return insertChoiceMethod
    +
    def generateRemoveMethod(attr, minOccurs):
    def removeMethod(self, index):
    attr_list = getattr(self, attr)
    @@ -1669,6 +1705,7 @@
    raise ValueError("There can't be less than %d values in \"%s\"!" % (minOccurs, attr))
    return removeMethod
    +
    def generateCountMethod(attr):
    def countMethod(self):
    return len(getattr(self, attr))
    @@ -1680,6 +1717,7 @@
    NAMESPACE_PATTERN = re.compile("xmlns(?:\:[^\=]*)?=\"[^\"]*\" ")
    +
    class DefaultElementClass(etree.ElementBase):
    StructurePattern = re.compile("$")
    @@ -1693,6 +1731,7 @@
    def tostring(self):
    return NAMESPACE_PATTERN.sub("", etree.tostring(self, pretty_print=True, encoding='utf-8')).decode('utf-8')
    +
    class XMLElementClassLookUp(etree.PythonElementClassLookup):
    def __init__(self, classes, *args, **kwargs):
    @@ -1727,6 +1766,7 @@
    return element_class[0]
    return element_class
    +
    class XMLClassParser(etree.XMLParser):
    def __init__(self, namespaces, default_namespace_format, base_class, xsd_schema, *args, **kwargs):
    @@ -1789,6 +1829,7 @@
    new_element._init_()
    return new_element
    +
    def GenerateParser(factory, xsdstring):
    ComputedClasses = factory.CreateClasses()
    --- a/xmlclass/xsdschema.py Mon Aug 14 22:30:41 2017 +0300
    +++ b/xmlclass/xsdschema.py Mon Aug 14 23:27:15 2017 +0300
    @@ -30,9 +30,11 @@
    from xmlclass import *
    +
    def GenerateDictFacets(facets):
    return dict([(name, (None, False)) for name in facets])
    +
    def GenerateSimpleTypeXMLText(function):
    def generateXMLTextMethod(value, name=None, indent=0):
    text = ""
    @@ -45,6 +47,7 @@
    return text
    return generateXMLTextMethod
    +
    def GenerateFloatXMLText(extra_values=[], decimal=None):
    float_format = (lambda x: "{:.{width}f}".format(x, width=decimal).rstrip('0')
    if decimal is not None else str)
    @@ -110,6 +113,7 @@
    # Simple type elements
    +
    def GenerateFacetReducing(facetname, canbefixed):
    def ReduceFacet(factory, attributes, elements):
    annotations, children = factory.ReduceElements(elements)
    @@ -486,6 +490,7 @@
    simpleType["generate"] = GenerateSimpleType
    return simpleType
    +
    def ReduceSimpleType(factory, attributes, elements):
    # Reduce all the simple type children
    annotations, children = factory.ReduceElements(elements)
    @@ -497,6 +502,7 @@
    # Complex type
    +
    def ExtractAttributes(factory, elements, base=None):
    attrs = []
    attrnames = {}
    @@ -717,6 +723,7 @@
    any.update(attributes)
    return any
    +
    def ReduceElement(factory, attributes, elements):
    annotations, children = factory.ReduceElements(elements)
    @@ -771,6 +778,7 @@
    else:
    raise ValueError("\"Element\" must have at least a \"ref\" or a \"name\" defined!")
    +
    def ReduceAll(factory, attributes, elements):
    annotations, children = factory.ReduceElements(elements)
    @@ -867,6 +875,7 @@
    # Constraint elements
    +
    def ReduceUnique(factory, attributes, elements):
    annotations, children = factory.ReduceElements(elements)
    @@ -874,6 +883,7 @@
    unique.update(attributes)
    return unique
    +
    def ReduceKey(factory, attributes, elements):
    annotations, children = factory.ReduceElements(elements)
    @@ -881,6 +891,7 @@
    key.update(attributes)
    return key
    +
    def ReduceKeyRef(factory, attributes, elements):
    annotations, children = factory.ReduceElements(elements)
    @@ -888,6 +899,7 @@
    keyref.update(attributes)
    return keyref
    +
    def ReduceSelector(factory, attributes, elements):
    annotations, children = factory.ReduceElements(elements)
    @@ -895,6 +907,7 @@
    selector.update(attributes)
    return selector
    +
    def ReduceField(factory, attributes, elements):
    annotations, children = factory.ReduceElements(elements)
    @@ -909,6 +922,7 @@
    annotations, children = factory.ReduceElements(elements)
    raise ValueError("\"import\" element isn't supported yet!")
    +
    def ReduceInclude(factory, attributes, elements):
    annotations, children = factory.ReduceElements(elements)
    @@ -933,6 +947,7 @@
    factory.EquivalentClassesParent.update(include_factory.EquivalentClassesParent)
    return None
    +
    def ReduceRedefine(factory, attributes, elements):
    annotations, children = factory.ReduceElements(elements)
    raise ValueError("\"redefine\" element isn't supported yet!")
    @@ -962,6 +977,7 @@
    elif not CompareSchema(infos, child):
    raise ValueError("\"%s\" is defined twice in targetNamespace!" % child["name"])
    +
    def CompareSchema(schema, reference):
    if isinstance(schema, ListType):
    if not isinstance(reference, ListType) or len(schema) != len(reference):
    @@ -1091,11 +1107,12 @@
    return element_infos
    return None
    -"""
    -This function opens the xsd file and generate a xml parser with class lookup from
    -the xml tree
    -"""
    +
    def GenerateParserFromXSD(filepath):
    + """
    + This function opens the xsd file and generate a xml parser with class lookup from
    + the xml tree
    + """
    xsdfile = open(filepath, 'r')
    xsdstring = xsdfile.read()
    xsdfile.close()
    @@ -1105,10 +1122,11 @@
    os.chdir(cwd)
    return parser
    -"""
    -This function generate a xml from the xsd given as a string
    -"""
    +
    def GenerateParserFromXSDstring(xsdstring):
    + """
    + This function generate a xml from the xsd given as a string
    + """
    return GenerateParser(XSDClassFactory(minidom.parseString(xsdstring)), xsdstring)