--- a/Beremiz_service.py Thu Mar 07 21:57:18 2019 +0100
+++ b/Beremiz_service.py Mon Mar 11 01:03:32 2019 +0100
@@ -41,6 +41,7 @@
from runtime.xenomai import TryPreloadXenomai
from runtime import LogMessageAndException
from runtime import PlcStatus
+from runtime.Stunnel import ensurePSK import util.paths as paths
@@ -415,7 +416,7 @@
reactor.registerWxApp(app)
twisted_reactor_thread_id = None
wx_eval_lock = Semaphore(0)
@@ -439,8 +440,8 @@
if ui_thread is not None \
and ui_thread.ident != current_id \
and (not havetwisted or (
- twisted_reactor_thread_id is not None
- and twisted_reactor_thread_id != current_id)):
+ twisted_reactor_thread_id is not None + and twisted_reactor_thread_id != current_id)): o = type('', (object,), dict(call=(tocall, args, kwargs), res=None))
wx.CallAfter(wx_evaluator, o)
@@ -508,7 +509,6 @@
# Some extension may set 'servicename' to a computed ID or Serial Number
# instead of using commandline '-n'
if servicename is not None and PSKpath is not None:
- from runtime.Stunnel import ensurePSK
ensurePSK(servicename, PSKpath)
runtime.CreatePLCObjectSingleton(
--- a/PSKManagement.py Thu Mar 07 21:57:18 2019 +0100
+++ b/PSKManagement.py Mon Mar 11 01:03:32 2019 +0100
@@ -14,26 +14,32 @@
COL_ID, COL_URI, COL_DESC, COL_LAST = range(4)
REPLACE, REPLACE_ALL, KEEP, KEEP_ALL, CANCEL = range(5)
def _pskpath(project_path):
return os.path.join(project_path, 'psk')
def _mgtpath(project_path):
return os.path.join(_pskpath(project_path), 'management.json')
def _ensurePSKdir(project_path):
pskpath = _pskpath(project_path)
if not os.path.exists(pskpath):
- '', # default description
+ '', # default description None] # last connection date
- return {row[COL_ID]:row for row in data}
+ return {row[COL_ID]: row for row in data} def _LoadData(project_path):
""" load known keys metadata """
@@ -43,6 +49,7 @@
return json.loads(open(_path).read())
def _filterData(psk_files, data_input):
input_by_ID = _dataByID(data_input)
@@ -51,11 +58,12 @@
# this implicitly filters IDs out of metadata who's
for filename in psk_files:
- if filename.endswith('.secret'):
- ID = filename[:-7] # strip filename extension
- output.append(input_by_ID.get(ID,_default(ID)))
+ if filename.endswith('.secret'): + ID = filename[:-7] # strip filename extension + output.append(input_by_ID.get(ID, _default(ID))) def GetData(project_path):
loaded_data = _LoadData(project_path)
@@ -63,15 +71,18 @@
return _filterData(psk_files, loaded_data)
def DeleteID(project_path, ID):
secret_path = os.path.join(_pskpath(project_path), ID+'.secret')
def SaveData(project_path, data):
_ensurePSKdir(project_path)
with open(_mgtpath(project_path), 'w') as f:
f.write(json.dumps(data))
def UpdateID(project_path, ID, secret, URI):
pskpath = _ensurePSKdir(project_path)
if not os.path.exists(pskpath):
@@ -88,10 +99,10 @@
_is_new_ID = dataForID is None
- dataForID = _default(ID)
+ dataForID = _default(ID) - # FIXME : could store time instead os a string and use DVC model's cmp
+ # FIXME : could store time instead os a string and use DVC model's cmp # then date display could be smarter, etc - sortable sting hack for now
dataForID[COL_LAST] = time.strftime('%y/%M/%d-%H:%M:%S')
@@ -100,6 +111,7 @@
SaveData(project_path, data)
def ExportIDs(project_path, export_zip):
with ZipFile(export_zip, 'w') as zf:
path = _pskpath(project_path)
@@ -107,6 +119,7 @@
if nm.endswith('.secret') or nm == 'management.json':
zf.write(os.path.join(path, nm), nm)
def ImportIDs(project_path, import_zip, should_I_replace_callback):
zf = ZipFile(import_zip, 'r')
data = GetData(project_path)
@@ -132,18 +145,16 @@
if result in [REPLACE_ALL, REPLACE]:
existing_row[:] = imported_row
# copy the key of selected
keys_to_import.append(ID)
for ID in keys_to_import:
zf.extract(ID+".secret", _pskpath(project_path))
SaveData(project_path, data)
--- a/ProjectController.py Thu Mar 07 21:57:18 2019 +0100
+++ b/ProjectController.py Mon Mar 11 01:03:32 2019 +0100
@@ -1789,8 +1789,8 @@
self._SetConnector(connectors.ConnectorFactory(uri, self))
- _("Exception while connecting to '%s': %s\n") % (uri, str(e)))
- #self.logger.write_error(traceback.format_exc())
+ _("Exception while connecting to '{uri}': {ex}\n").format( # Did connection success ?
if self._connector is None:
@@ -1813,7 +1813,7 @@
if self._connector is None:
builder = self.GetBuilder()
MD5 = builder.GetBinaryMD5()
@@ -1846,7 +1846,7 @@
self.logger.write_error(_("Fatal : cannot get builder.\n"))
- # recover md5 from last build
+ # recover md5 from last build MD5 = builder.GetBinaryMD5()
# Check if md5 file is empty : ask user to build PLC
@@ -1871,11 +1871,11 @@
for name in os.listdir(extrafilespath):
self._connector.BlobFromFile(
# use file name as a seed to avoid collisions
# with files having same content
- os.path.join(extrafilespath, name),name)))
+ os.path.join(extrafilespath, name), name))) object_path = builder.GetBinaryPath()
--- a/connectors/PYRO/PSK_Adapter.py Thu Mar 07 21:57:18 2019 +0100
+++ b/connectors/PYRO/PSK_Adapter.py Mon Mar 11 01:03:32 2019 +0100
@@ -7,11 +7,11 @@
from Pyro.core import PyroURI
-from Pyro.protocol import _connect_socket,TCPConnection,PYROAdapter
+from Pyro.protocol import _connect_socket, TCPConnection, PYROAdapter from Pyro.errors import ConnectionDeniedError, ProtocolError
from Pyro.util import Log
# The TLS-PSK adapter that handles SSL connections instead of regular sockets,
# but using Pre Shared Keys instead of Certificates
@@ -19,67 +19,76 @@
# This is essentialy the same as in Pyro/protocol.py
# only raw_sock wrapping into sock through sslpsk.wrap_socket was added
# Pyro unfortunately doesn't allow cleaner customization
- def bindToURI(self,URI):
+ def bindToURI(self, URI): with self.lock: # only 1 thread at a time can bind the URI
# This are the statements that differ from Pyro/protocol.py
raw_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
_connect_socket(raw_sock, URI.address, URI.port, self.timeout)
sock = sslpsk.wrap_socket(
raw_sock, psk=Pyro.config.PYROPSK, server_side=False,
- ciphers="PSK-AES256-CBC-SHA", # available in openssl 1.0.2
+ ciphers="PSK-AES256-CBC-SHA", # available in openssl 1.0.2 ssl_version=ssl.PROTOCOL_TLSv1)
- # all the rest is the same as in Pyro/protocol.py
+ # all the rest is the same as in Pyro/protocol.py - conn=TCPConnection(sock, sock.getpeername())
+ conn = TCPConnection(sock, sock.getpeername()) # receive the authentication challenge string, and use that to build the actual identification string.
- authChallenge=self.recvAuthChallenge(conn)
- except ProtocolError,x:
+ authChallenge = self.recvAuthChallenge(conn) + except ProtocolError, x: # check if we were denied
- if hasattr(x,"partialMsg") and x.partialMsg[:len(self.denyMSG)]==self.denyMSG:
+ if hasattr(x, "partialMsg") and x.partialMsg[:len(self.denyMSG)] == self.denyMSG: raise ConnectionDeniedError(Pyro.constants.deniedReasons[int(x.partialMsg[-1])])
# reply with our ident token, generated from the ident passphrase and the challenge
- msg = self._sendConnect(sock,self.newConnValidator.createAuthToken(self.ident, authChallenge, conn.addr, self.URI, None) )
- if msg==self.acceptMSG:
- Log.msg('PYROAdapter','connected to',str(URI))
- if URI.protocol=='PYROLOCPSK':
- self.resolvePYROLOC_URI("PYROPSK") # updates self.URI
- elif msg[:len(self.denyMSG)]==self.denyMSG:
+ msg = self._sendConnect(sock, self.newConnValidator.createAuthToken(self.ident, authChallenge, conn.addr, self.URI, None)) + if msg == self.acceptMSG: + self.conn.connected = 1 + Log.msg('PYROAdapter', 'connected to', str(URI)) + if URI.protocol == 'PYROLOCPSK': + self.resolvePYROLOC_URI("PYROPSK") # updates self.URI + elif msg[:len(self.denyMSG)] == self.denyMSG: raise ConnectionDeniedError(Pyro.constants.deniedReasons[int(msg[-1])])
- except (KeyError,ValueError):
+ except (KeyError, ValueError): raise ConnectionDeniedError('invalid response')
- Log.msg('PYROAdapter','connection failed to URI',str(URI))
+ Log.msg('PYROAdapter', 'connection failed to URI', str(URI)) raise ProtocolError('connection failed')
_getProtocolAdapter = Pyro.protocol.getProtocolAdapter
def getProtocolAdapter(protocol):
if protocol in ('PYROPSK', 'PYROLOCPSK'):
return _getProtocolAdapter(protocol)
Pyro.protocol.getProtocolAdapter = getProtocolAdapter
_processStringURI = Pyro.core.processStringURI
def processStringURI(URI):
- x=re.match(r'(?P<protocol>PYROLOCPSK)://(?P<hostname>[^\s:]+):?(?P<port>\d+)?/(?P<name>\S*)',URI)
+ x = re.match(r'(?P<protocol>PYROLOCPSK)://(?P<hostname>[^\s:]+):?(?P<port>\d+)?/(?P<name>\S*)', URI) - protocol=x.group('protocol')
- hostname=x.group('hostname')
+ protocol = x.group('protocol') + hostname = x.group('hostname')
- return PyroURI(hostname,name,port,protocol)
+ return PyroURI(hostname, name, port, protocol) return _processStringURI(URI)
Pyro.core.processStringURI = processStringURI
--- a/connectors/PYRO/__init__.py Thu Mar 07 21:57:18 2019 +0100
+++ b/connectors/PYRO/__init__.py Mon Mar 11 01:03:32 2019 +0100
@@ -55,8 +55,9 @@
scheme, location = uri.split("://")
import connectors.PYRO.PSK_Adapter
+ _unused_module_imported_for_monkey_patching_pylint_sucks = connectors.PYRO.PSK_Adapter schemename = "PYROLOCPSK"
- url, ID = location.split('#') #TODO fix exception when # not found
+ url, ID = location.split('#') # TODO fix exception when # not found secpath = os.path.join(str(confnodesroot.ProjectPath), 'psk', ID+'.secret')
if not os.path.exists(secpath):
@@ -73,9 +74,10 @@
# Try to get the proxy object
RemotePLCObjectProxy = Pyro.core.getAttrProxyForURI(schemename + "://" + location + "/PLCObject")
- confnodesroot.logger.write_error(_("Connection to '%s' failed with exception '%s'\n") % (location, str(e)))
- #confnodesroot.logger.write_error(traceback.format_exc())
+ confnodesroot.logger.write_error( + _("Connection to {loc} failed with exception {ex}\n").format( + loc=location, exo=str(e))) RemotePLCObjectProxy.adapter.setTimeout(60)
@@ -108,10 +110,9 @@
confnodesroot.logger.write_warning(_("PLC did not provide identity and security infomation.\n"))
PSK.UpdateID(confnodesroot.ProjectPath, ID, secret, uri)
_special_return_funcs = {
"GetTraceVariables": (PlcStatus.Broken, None),
--- a/connectors/PYRO_dialog.py Thu Mar 07 21:57:18 2019 +0100
+++ b/connectors/PYRO_dialog.py Mon Mar 11 01:03:32 2019 +0100
@@ -11,27 +11,28 @@
from connectors.SchemeEditor import SchemeEditor
-model = [('host',_("Host:")),
+model = [('host', _("Host:")), # (scheme, model, secure)
models = [("LOCAL", [], False), ("PYRO", model, False), ("PYROS", model, True)]
Schemes = list(zip(*models)[0])
-_PerSchemeConf = {sch : (mod,sec) for sch,mod,sec in models}
+_PerSchemeConf = {sch: (mod, sec) for sch, mod, sec in models} class PYRO_dialog(SchemeEditor):
def __init__(self, scheme, *args, **kwargs):
# ID selector is enabled only on PYROS (secure)
self.model, self.EnableIDSelector = _PerSchemeConf[scheme]
SchemeEditor.__init__(self, scheme, *args, **kwargs)
+ # pylint: disable=unused-variable - hostport, ID = list(islice(chain(loc.split("#"), repeat("")),2))
- host, port = list(islice(chain(hostport.split(":"), repeat("")),2))
+ hostport, ID = list(islice(chain(loc.split("#"), repeat("")), 2)) + host, port = list(islice(chain(hostport.split(":"), repeat("")), 2)) @@ -39,10 +40,9 @@
fields = self.GetFields()
return template.format(**fields)
--- a/connectors/SchemeEditor.py Thu Mar 07 21:57:18 2019 +0100
+++ b/connectors/SchemeEditor.py Mon Mar 11 01:03:32 2019 +0100
@@ -5,15 +5,15 @@
from __future__ import absolute_import
-from itertools import repeat, izip_longest
from functools import partial
from controls.IDBrowser import IDBrowser
class SchemeEditor(wx.Panel):
def __init__(self, scheme, parent, *args, **kwargs):
wx.Panel.__init__(self, parent, *args, **kwargs)
self.fieldsizer = wx.FlexGridSizer(cols=2, hgap=10, vgap=10)
@@ -25,8 +25,9 @@
txtctrl = wx.TextCtrl(parent=self, size=wx.Size(200, -1))
self.txtctrls[tag] = txtctrl
- (wx.StaticText(self, label=label), wx.ALIGN_CENTER_VERTICAL),
+ (wx.StaticText(self, label=label), + wx.ALIGN_CENTER_VERTICAL), self.fieldsizer.AddWindow(win, flag=flag)
self.fieldsizer.AddSpacer(20)
@@ -45,9 +46,8 @@
self.SetSizer(self.fieldsizer)
def SetFields(self, fields):
- for tag, label in self.model:
+ for tag, _label in self.model: self.txtctrls[tag].SetValue(fields[tag])
- return {tag: self.txtctrls[tag].GetValue() for tag,label in self.model}
+ return {tag: self.txtctrls[tag].GetValue() for tag, _label in self.model} --- a/connectors/WAMP_dialog.py Thu Mar 07 21:57:18 2019 +0100
+++ b/connectors/WAMP_dialog.py Mon Mar 11 01:03:32 2019 +0100
@@ -6,15 +6,15 @@
from __future__ import absolute_import
from itertools import repeat, islice, chain
from connectors.SchemeEditor import SchemeEditor
Schemes = ["WAMP", "WAMPS"]
-model = [('host',_("Host:")),
+model = [('host', _("Host:")), + ('realm', _("Realm:"))] class WAMP_dialog(SchemeEditor):
def __init__(self, *args, **kwargs):
@@ -22,19 +22,19 @@
self.EnableIDSelector = True
SchemeEditor.__init__(self, *args, **kwargs)
+ # pylint: disable=unused-variable - hostport, realm, ID = list(islice(chain(loc.split("#"), repeat("")),3))
- host, port = list(islice(chain(hostport.split(":"), repeat("")),2))
+ hostport, realm, ID = list(islice(chain(loc.split("#"), repeat("")), 3)) + host, port = list(islice(chain(hostport.split(":"), repeat("")), 2)) fields = self.GetFields()
- #TODO : input validation test
+ # TODO : input validation test (":{port}" if fields['port'] else '') +\
return template.format(**fields)
--- a/connectors/__init__.py Thu Mar 07 21:57:18 2019 +0100
+++ b/connectors/__init__.py Mon Mar 11 01:03:32 2019 +0100
@@ -32,7 +32,7 @@
from connectors.ConnectorBase import ConnectorBase
from types import ClassType
-connectors_packages = ["PYRO","WAMP"]
+connectors_packages = ["PYRO", "WAMP"] def _GetLocalConnectorClassFactory(name):
@@ -44,17 +44,18 @@
_dialogs_imported = False
per_URI_connectors = None
# lazy import of connectors dialogs, only if used
global per_URI_connectors, schemes, _dialogs_imported
- if not _dialogs_imported:
+ if not _dialogs_imported: for con_name in connectors_packages:
- module = __import__(con_name + '_dialog', globals(), locals())
+ module = __import__(con_name + '_dialog', globals(), locals()) for scheme in module.Schemes:
per_URI_connectors[scheme] = getattr(module, con_name + '_dialog')
@@ -110,20 +111,22 @@
# import module according to uri type and get connector specific baseclass
- # first call to import the module,
+ # first call to import the module, # then call with parameters to create the class
connector_specific_class = connectors[scheme]()(uri, confnodesroot)
if connector_specific_class is None:
# new class inheriting from generic and specific connector base classes
- return ClassType(_scheme + "_connector",
+ return ClassType(_scheme + "_connector", (ConnectorBase, connector_specific_class), {})()
def EditorClassFromScheme(scheme):
- return per_URI_connectors.get(scheme, None)
+ return per_URI_connectors.get(scheme, None) --- a/controls/DiscoveryPanel.py Thu Mar 07 21:57:18 2019 +0100
+++ b/controls/DiscoveryPanel.py Mon Mar 11 01:03:32 2019 +0100
@@ -30,7 +30,6 @@
import wx.lib.mixins.listctrl as listmix
from zeroconf import ServiceBrowser, Zeroconf, get_all_addresses
service_type = '_Beremiz._tcp.local.'
@@ -41,6 +40,7 @@
wx.ListCtrl.__init__(self, parent, id, pos, size, style, name=name)
listmix.ListCtrlAutoWidthMixin.__init__(self)
class DiscoveryPanel(wx.Panel, listmix.ColumnSorterMixin):
def _init_coll_MainSizer_Items(self, parent):
@@ -129,7 +129,7 @@
self.IfacesMonitorState = None
self.IfacesMonitorTimer = wx.Timer(self)
self.IfacesMonitorTimer.Start(2000)
- self.Bind(wx.EVT_TIMER, self.IfacesMonitor , self.IfacesMonitorTimer)
+ self.Bind(wx.EVT_TIMER, self.IfacesMonitor, self.IfacesMonitorTimer) self.IfacesMonitorTimer.Stop()
@@ -139,7 +139,7 @@
def IfacesMonitor(self, event):
NewState = get_all_addresses(socket.AF_INET)
- if self.IfacesMonitorState != NewState:
+ if self.IfacesMonitorState != NewState: if self.IfacesMonitorState is not None:
# refresh only if a new address appeared
@@ -192,7 +192,7 @@
if self.LatestSelection is not None:
# if self.ByIPCheck.IsChecked():
svcname, scheme, host, port = \
- map(lambda col:self.getColumnText(self.LatestSelection, col),
+ map(lambda col: self.getColumnText(self.LatestSelection, col), return ("%s://%s:%s#%s" % (scheme, host, port, svcname)) \
--- a/controls/IDBrowser.py Thu Mar 07 21:57:18 2019 +0100
+++ b/controls/IDBrowser.py Mon Mar 11 01:03:32 2019 +0100
@@ -4,13 +4,13 @@
# See COPYING file for copyrights details.
from __future__ import absolute_import
import PSKManagement as PSK
from PSKManagement import *
from dialogs.IDMergeDialog import IDMergeDialog
class IDBrowserModel(dv.PyDataViewIndexListModel):
def __init__(self, project_path, columncount):
self.project_path = project_path
@@ -36,9 +36,9 @@
def Compare(self, item1, item2, col, ascending):
- if not ascending: # swap sort order?
+ if not ascending: # swap sort order? item2, item1 = item1, item2
row1 = self.GetRow(item1)
row2 = self.GetRow(item2)
@@ -50,13 +50,13 @@
def DeleteRows(self, rows):
PSK.DeleteID(self.project_path, self.data[row][COL_ID])
@@ -66,16 +66,18 @@
data = PSK.ImportIDs(self.project_path, filepath, sircb)
- self.Reset(len(self.data))
+ self.Reset(len(self.data)) def Export(self, filepath):
PSK.ExportIDs(self.project_path, filepath)
-colflags = dv.DATAVIEW_COL_RESIZABLE|dv.DATAVIEW_COL_SORTABLE
+colflags = dv.DATAVIEW_COL_RESIZABLE | dv.DATAVIEW_COL_SORTABLE class IDBrowser(wx.Panel):
def __init__(self, parent, ctr, SelectURICallBack=None, SelectIDCallBack=None, **kwargs):
- big = self.isManager = SelectURICallBack is None and SelectIDCallBack is None
+ big = self.isManager = SelectURICallBack is None and SelectIDCallBack is None wx.Panel.__init__(self, parent, -1, size=(800 if big else 450,
@@ -83,66 +85,66 @@
self.SelectIDCallBack = SelectIDCallBack
dvStyle = wx.BORDER_THEME | dv.DV_ROW_LINES
# no multiple selection in selector mode
dvStyle |= dv.DV_MULTIPLE
- self.dvc = dv.DataViewCtrl(self, style = dvStyle)
- args = lambda *a,**k:(a,k)
+ self.dvc = dv.DataViewCtrl(self, style=dvStyle) - args(_("ID"), COL_ID, width = 70),
- args(_("Last URI"), COL_URI, width = 300 if big else 80),
- args(_("Description"), COL_DESC, width = 300 if big else 200,
- mode = dv.DATAVIEW_CELL_EDITABLE
- else dv.DATAVIEW_CELL_INERT),
- args(_("Last connection"), COL_LAST, width = 120),
+ args(_("ID"), COL_ID, width=70), + args(_("Last URI"), COL_URI, width=300 if big else 80), + args(_("Description"), COL_DESC, width=300 if big else 200, + mode=dv.DATAVIEW_CELL_EDITABLE + else dv.DATAVIEW_CELL_INERT), + args(_("Last connection"), COL_LAST, width=120), self.model = IDBrowserModel(ctr.ProjectPath, len(ColumnsDesc))
self.dvc.AssociateModel(self.model)
- for a,k in ColumnsDesc:
+ for a, k in ColumnsDesc: - self.dvc.AppendTextColumn(*a,**dict(k, flags = colflags)))
+ self.dvc.AppendTextColumn(*a, **dict(k, flags=colflags))) col_list[COL_LAST].SetSortOrder(False)
# TODO : sort by last bvisit by default
- self.Sizer = wx.BoxSizer(wx.VERTICAL)
+ self.Sizer = wx.BoxSizer(wx.VERTICAL) self.Sizer.Add(self.dvc, 1, wx.EXPAND)
btnbox = wx.BoxSizer(wx.HORIZONTAL)
# deletion of secret and metadata
deleteButton = wx.Button(self, label=_("Delete ID"))
self.Bind(wx.EVT_BUTTON, self.OnDeleteButton, deleteButton)
- btnbox.Add(deleteButton, 0, wx.LEFT|wx.RIGHT, 5)
+ btnbox.Add(deleteButton, 0, wx.LEFT | wx.RIGHT, 5) exportButton = wx.Button(self, label=_("Export all"))
self.Bind(wx.EVT_BUTTON, self.OnExportButton, exportButton)
- btnbox.Add(exportButton, 0, wx.LEFT|wx.RIGHT, 5)
+ btnbox.Add(exportButton, 0, wx.LEFT | wx.RIGHT, 5) # import with a merge -> duplicates are asked for
importButton = wx.Button(self, label=_("Import"))
self.Bind(wx.EVT_BUTTON, self.OnImportButton, importButton)
- btnbox.Add(importButton, 0, wx.LEFT|wx.RIGHT, 5)
+ btnbox.Add(importButton, 0, wx.LEFT | wx.RIGHT, 5)
self.useURIButton = wx.Button(self, label=_("Use last URI"))
self.Bind(wx.EVT_BUTTON, self.OnUseURIButton, self.useURIButton)
self.useURIButton.Disable()
- btnbox.Add(self.useURIButton, 0, wx.LEFT|wx.RIGHT, 5)
+ btnbox.Add(self.useURIButton, 0, wx.LEFT | wx.RIGHT, 5) - self.Sizer.Add(btnbox, 0, wx.TOP|wx.BOTTOM, 5)
+ self.Sizer.Add(btnbox, 0, wx.TOP | wx.BOTTOM, 5) self.Bind(dv.EVT_DATAVIEW_SELECTION_CHANGED, self.OnSelectionChanged, self.dvc)
def OnDeleteButton(self, evt):
items = self.dvc.GetSelections()
rows = [self.model.GetRow(item) for item in items]
@@ -150,13 +152,13 @@
# Ask if user really wants to delete
if wx.MessageBox(_('Are you sure to delete selected IDs?'),
- wx.YES_NO | wx.CENTRE | wx.NO_DEFAULT) != wx.YES:
+ wx.YES_NO | wx.CENTRE | wx.NO_DEFAULT) != wx.YES: self.model.DeleteRows(rows)
def OnSelectionChanged(self, evt):
- if not self.isManager :
items = self.dvc.GetSelections()
somethingSelected = len(items) > 0
self.useURIButton.Enable(somethingSelected)
@@ -165,7 +167,6 @@
ID = self.model.GetValueByRow(row, COL_ID)
self.SelectIDCallBack(ID)
def OnUseURIButton(self, evt):
row = self.model.GetRow(self.dvc.GetSelections()[0])
URI = self.model.GetValueByRow(row, COL_URI)
@@ -174,16 +175,18 @@
def OnExportButton(self, evt):
dialog = wx.FileDialog(self, _("Choose a file"),
- wildcard = _("PSK ZIP files (*.zip)|*.zip"),
- style = wx.SAVE | wx.OVERWRITE_PROMPT)
+ wildcard=_("PSK ZIP files (*.zip)|*.zip"), + style=wx.SAVE | wx.OVERWRITE_PROMPT) if dialog.ShowModal() == wx.ID_OK:
self.model.Export(dialog.GetPath())
- def ShouldIReplaceCallback(self,existing,replacement):
- ID,URI,DESC,LAST = existing
- _ID,_URI,_DESC,_LAST = replacement
- dlg = IDMergeDialog(self,
+ # pylint: disable=unused-variable + def ShouldIReplaceCallback(self, existing, replacement): + ID, URI, DESC, LAST = existing + _ID, _URI, _DESC, _LAST = replacement (_("Replace information for ID {ID} ?") + "\n\n" +
_("Description:") + " {DESC}\n " +
@@ -194,9 +197,9 @@
_("Last known URI:") + " {_URI}\n " +
_("Last connection:") + " {_LAST}\n").format(**locals()),
_("Do the same for following IDs"),
- [_("Replace"), _("Keep"),_("Cancel")])
+ [_("Replace"), _("Keep"), _("Cancel")]) - answer = dlg.ShowModal() # return value ignored as we have "Ok" only anyhow
+ answer = dlg.ShowModal() # return value ignored as we have "Ok" only anyhow if answer == wx.ID_CANCEL:
@@ -211,9 +214,8 @@
def OnImportButton(self, evt):
dialog = wx.FileDialog(self, _("Choose a file"),
- wildcard = _("PSK ZIP files (*.zip)|*.zip"),
- style = wx.FD_OPEN | wx.FD_FILE_MUST_EXIST)
+ wildcard=_("PSK ZIP files (*.zip)|*.zip"), + style=wx.FD_OPEN | wx.FD_FILE_MUST_EXIST) if dialog.ShowModal() == wx.ID_OK:
self.model.Import(dialog.GetPath(),
self.ShouldIReplaceCallback)
--- a/dialogs/IDManager.py Thu Mar 07 21:57:18 2019 +0100
+++ b/dialogs/IDManager.py Mon Mar 11 01:03:32 2019 +0100
@@ -1,10 +1,9 @@
from __future__ import absolute_import
-from connectors import ConnectorSchemes, EditorClassFromScheme
-from controls.DiscoveryPanel import DiscoveryPanel
from controls.IDBrowser import IDBrowser
class IDManager(wx.Dialog):
def __init__(self, parent, ctr):
@@ -12,7 +11,7 @@
name='IDManager', parent=parent,
style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER,
# start IDBrowser in manager mode
self.browser = IDBrowser(self, ctr)
self.Bind(wx.EVT_CHAR_HOOK, self.OnEscapeKey)
@@ -23,5 +22,3 @@
self.EndModal(wx.ID_CANCEL)
--- a/dialogs/IDMergeDialog.py Thu Mar 07 21:57:18 2019 +0100
+++ b/dialogs/IDMergeDialog.py Mon Mar 11 01:03:32 2019 +0100
@@ -6,7 +6,8 @@
from __future__ import absolute_import
-# class RichMessageDialog is still not available in wxPython 3.0.2
+# class RichMessageDialog is still not available in wxPython 3.0.2 class IDMergeDialog(wx.Dialog):
def __init__(self, parent, title, question, optiontext, button_texts):
wx.Dialog.__init__(self, parent, title=title)
@@ -15,17 +16,19 @@
message = wx.StaticText(self, label=question)
main_sizer.AddWindow(message, border=20,
- flag = wx.ALIGN_CENTER_HORIZONTAL | wx.TOP | wx.LEFT | wx.RIGHT)
+ flag=wx.ALIGN_CENTER_HORIZONTAL | wx.TOP | wx.LEFT | wx.RIGHT) self.check = wx.CheckBox(self, label=optiontext)
main_sizer.AddWindow(self.check, border=20,
flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.ALIGN_CENTER_HORIZONTAL)
buttons_sizer = wx.BoxSizer(wx.HORIZONTAL)
- for label,wxID in zip(button_texts, [wx.ID_YES, wx.ID_NO, wx.ID_CANCEL]):
+ for label, wxID in zip(button_texts, [wx.ID_YES, wx.ID_NO, wx.ID_CANCEL]): Button = wx.Button(self, label=label)
def OnButtonFactory(_wxID):
return lambda event: self.EndModal(_wxID)
self.Bind(wx.EVT_BUTTON, OnButtonFactory(wxID), Button)
buttons_sizer.AddWindow(Button)
--- a/dialogs/UriEditor.py Thu Mar 07 21:57:18 2019 +0100
+++ b/dialogs/UriEditor.py Mon Mar 11 01:03:32 2019 +0100
@@ -4,6 +4,7 @@
from connectors import ConnectorSchemes, EditorClassFromScheme
from controls.DiscoveryPanel import DiscoveryPanel
class UriEditor(wx.Dialog):
def _init_ctrls(self, parent):
self.UriTypeChoice = wx.Choice(parent=self, choices=self.choices)
@@ -16,7 +17,7 @@
self.mainSizer = wx.BoxSizer(wx.VERTICAL)
typeSizer = wx.BoxSizer(wx.HORIZONTAL)
typeSizer.Add(wx.StaticText(self, wx.ID_ANY, _("Scheme :")), border=5,
- flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL)
+ flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL) typeSizer.Add(self.UriTypeChoice, border=5, flag=wx.ALL)
self.mainSizer.Add(typeSizer)
@@ -46,9 +47,9 @@
- scheme, loc = uri.strip().split("://",1)
+ scheme, loc = uri.strip().split("://", 1)
if scheme in ConnectorSchemes():
@@ -62,7 +63,6 @@
self.scheme_editor.SetLoc(loc)
return self.scheme_editor.GetURI()
@@ -71,23 +71,22 @@
def _replaceSchemeEditor(self, scheme):
if self.scheme_editor is not None:
self.editor_sizer.Detach(self.scheme_editor)
self.scheme_editor.Destroy()
self.scheme_editor = None
- if scheme is not None :
EditorClass = EditorClassFromScheme(scheme)
- self.scheme_editor = EditorClass(scheme,self)
+ self.scheme_editor = EditorClass(scheme, self) # None is for searching local network
- self.scheme_editor = DiscoveryPanel(self)
+ self.scheme_editor = DiscoveryPanel(self) self.editor_sizer.Add(self.scheme_editor)
self.scheme_editor.Refresh()
self.editor_sizer.Layout()
--- a/runtime/PLCObject.py Thu Mar 07 21:57:18 2019 +0100
+++ b/runtime/PLCObject.py Mon Mar 11 01:03:32 2019 +0100
@@ -30,14 +30,12 @@
import _ctypes # pylint: disable=wrong-import-order
+from six.moves import xrange from past.builtins import execfile
-import Pyro.core as pyro
-from six.moves import _thread, xrange
from tempfile import mkstemp
-from functools import wraps
+from functools import wraps, partial from runtime.typemapping import TypeTranslator
from runtime.loglevels import LogLevelsDefault, LogLevelsCount
@@ -79,7 +77,7 @@
def __init__(self, WorkingDir, argv, statuschange, evaluator, pyruntimevars):
- self.workingdir = WorkingDir # must exits already
+ self.workingdir = WorkingDir # must exits already self.tmpdir = os.path.join(WorkingDir, 'tmp')
if os.path.exists(self.tmpdir):
shutil.rmtree(self.tmpdir)
@@ -457,18 +455,18 @@
+ return getPSKID(partial(self.LogMessage, 0)) if os.path.exists(self.tmpdir):
shutil.rmtree(self.tmpdir)
def SeedBlob(self, seed):
blob = (mkstemp(dir=self.tmpdir) + (md5.new(),))
- fobj, path, md5sum = blob
+ _fobj, _path, md5sum = blob newBlobID = md5sum.digest()
self.blobs[newBlobID] = blob
@@ -481,17 +479,17 @@
- fobj, path, md5sum = blob
+ fobj, _path, md5sum = blob newBlobID = md5sum.digest()
self.blobs[newBlobID] = blob
- for fobj, path, md5sum in self.blobs:
+ for fobj, _path, _md5sum in self.blobs: def _BlobAsFile(self, blobID, newpath):
@@ -500,10 +498,10 @@
raise Exception(_("Missing data to create file: {}").format(newpath))
- fobj, path, md5sum = blob
+ fobj, path, _md5sum = blob shutil.move(path, newpath)
def NewPLC(self, md5sum, plc_object, extrafiles):
if self.PLCStatus in [PlcStatus.Stopped, PlcStatus.Empty, PlcStatus.Broken]:
@@ -608,8 +606,7 @@
def GetTraceVariables(self, DebugToken):
- if (DebugToken is not None and
- DebugToken == self.DebugToken):
+ if (DebugToken is not None and DebugToken == self.DebugToken): return self.PLCStatus, self._TracesSwap()
return PlcStatus.Broken, []
--- a/runtime/spawn_subprocess.py Thu Mar 07 21:57:18 2019 +0100
+++ b/runtime/spawn_subprocess.py Mon Mar 11 01:03:32 2019 +0100
@@ -3,14 +3,16 @@
# subset of subprocess built-in module using posix_spawn rather than fork.
+from __future__ import absolute_import - def __init__(self, args,stdin=None, stdout=None):
+ def __init__(self, args, stdin=None, stdout=None): @@ -40,7 +42,7 @@
if self.returncode is None:
- self.returncode = os.waitpid(self.pid,0)[1]
+ self.returncode = os.waitpid(self.pid, 0)[1] if self.stdin is not None:
@@ -50,7 +52,7 @@
stdoutdata = self.stdout.read()
@@ -58,7 +60,7 @@
if self.stdout is not None:
return (stdoutdata, stderrdata)
@@ -74,7 +76,7 @@
if self.returncode is None:
pid, ret = os.waitpid(self.pid, os.WNOHANG)
+ if (pid, ret) != (0, 0): if self.stdin is not None:
@@ -85,7 +87,7 @@
os.kill(self.pid, signal.SIGKILL)
@@ -96,23 +98,23 @@
if isinstance(args[0], str):
# oversimplified splitting of arguments,
# TODO: care about use of simple and double quotes
- elif isinstance(args[0], list) and len(args)==1:
+ elif isinstance(args[0], list) and len(args) == 1: raise Exception("Wrong arguments passed to subprocess.call")
pid = posix_spawn.posix_spawnp(cmd[0], cmd)
- return os.waitpid(pid,0)
+ return os.waitpid(pid, 0) if __name__ == '__main__':
@@ -120,12 +122,12 @@
p = Popen(["tr", "abc", "def"], stdin=PIPE, stdout=PIPE)
p = Popen(["tr", "abc", "def"], stdin=PIPE, stdout=PIPE)