# HG changeset patch # User Edouard Tisserant # Date 1683907795 -7200 # Node ID a5a6ee271e652e2e74a0609b0554365d172258d4 # Parent 2b995a4963a480abe1f2cb03e00299ac30234916 WIP python3 support for runtime diff -r 2b995a4963a4 -r a5a6ee271e65 Beremiz_service.py --- a/Beremiz_service.py Wed May 10 17:02:05 2023 +0200 +++ b/Beremiz_service.py Fri May 12 18:09:55 2023 +0200 @@ -31,7 +31,7 @@ import shlex import traceback import threading -from threading import Thread, Semaphore, Lock, currentThread +from threading import Thread, Semaphore, Lock, current_thread import builtins from functools import partial @@ -208,19 +208,7 @@ # Define locale domain loc.AddCatalog(domain) - global default_locale - default_locale = locale.getdefaultlocale()[1] - - # sys.stdout.encoding = default_locale - # if Beremiz_service is started from Beremiz IDE - # sys.stdout.encoding is None (that means 'ascii' encoding'). - # And unicode string returned by wx.GetTranslation() are - # automatically converted to 'ascii' string. - def unicode_translation(message): - return wx.GetTranslation(message).encode(default_locale) - - builtins.__dict__['_'] = unicode_translation - # builtins.__dict__['_'] = wx.GetTranslation + builtins.__dict__['_'] = wx.GetTranslation # Life is hard... have a candy. @@ -371,7 +359,7 @@ _servicename = self.pyroserver.servicename _servicename = '' if _servicename is None else _servicename dlg = ParamsEntryDialog(None, _("Enter a name "), defaultValue=_servicename) - dlg.SetTests([(lambda name: len(name) is not 0, _("Name must not be null!"))]) + dlg.SetTests([(lambda name: len(name) != 0, _("Name must not be null!"))]) if dlg.ShowModal() == wx.ID_OK: self.pyroserver.servicename = dlg.GetValue() self.pyroserver.Restart() @@ -448,10 +436,10 @@ obj.res = default_evaluator(tocall, *args, **kwargs) wx_eval_lock.release() - main_thread_id = currentThread().ident + main_thread_id = current_thread().ident def evaluator(tocall, *args, **kwargs): # To prevent deadlocks, check if current thread is not one already main - current_id = currentThread().ident + current_id = current_thread().ident if main_thread_id != current_id: o = type('', (object,), dict(call=(tocall, args, kwargs), res=None)) diff -r 2b995a4963a4 -r a5a6ee271e65 runtime/NevowServer.py --- a/runtime/NevowServer.py Wed May 10 17:02:05 2023 +0200 +++ b/runtime/NevowServer.py Fri May 12 18:09:55 2023 +0200 @@ -29,7 +29,7 @@ import collections import shutil import platform as platform_module -from zope.interface import implements +from zope.interface import implementer from nevow import appserver, inevow, tags, loaders, athena, url, rend from nevow.page import renderer from nevow.static import File @@ -44,7 +44,7 @@ PAGE_TITLE = 'Beremiz Runtime Web Interface' -xhtml_header = ''' +xhtml_header = b''' ''' @@ -248,6 +248,7 @@ extensions_settings_od = collections.OrderedDict() +@implementer(ISettings) class SettingsPage(rend.Page): # We deserve a slash addSlash = True @@ -255,8 +256,6 @@ # This makes webform_css url answer some default CSS child_webform_css = webform.defaultCSS child_webinterface_css = File(paths.AbsNeighbourFile(__file__, 'webinterface.css'), 'text/css') - - implements(ISettings) def __getattr__(self, name): global extensions_settings_od diff -r 2b995a4963a4 -r a5a6ee271e65 runtime/PyroServer.py --- a/runtime/PyroServer.py Wed May 10 17:02:05 2023 +0200 +++ b/runtime/PyroServer.py Fri May 12 18:09:55 2023 +0200 @@ -14,11 +14,42 @@ import sys import os -import Pyro -import Pyro.core as pyro +import Pyro5 +import Pyro5.server + import runtime from runtime.ServicePublisher import ServicePublisher +def make_pyro_exposed_stub(method_name): + stub = lambda self, *args, **kwargs: \ + getattr(self.plc_object_instance, method_name)(self, *args, **kwargs) + stub.__name__ = method_name + Pyro5.server.expose(stub) + return stub + + +class PLCObjectPyroAdapter(type("PLCObjectPyroStubs", (), { + name: make_pyro_exposed_stub(name) for name in [ + "AppendChunkToBlob", + "GetLogMessage", + "GetPLCID", + "GetPLCstatus", + "GetTraceVariables", + "MatchMD5", + "NewPLC", + "PurgeBlobs", + "RemoteExec", + "RepairPLC", + "ResetLogCount", + "SeedBlob", + "SetTraceVariablesList", + "StartPLC", + "StopPLC" + ] +})): + def __init__(self, plc_object_instance): + self.plc_object_instance = plc_object_instance + class PyroServer(object): def __init__(self, servicename, ip_addr, port): @@ -47,33 +78,14 @@ self.Publish() while self.continueloop: - Pyro.config.PYRO_MULTITHREADED = 0 - pyro.initServer() - self.daemon = pyro.Daemon(host=self.ip_addr, port=self.port) + self.daemon = Pyro5.server.Daemon(host=self.ip_addr, port=self.port) - # pyro never frees memory after connection close if no timeout set - # taking too small timeout value may cause - # unwanted diconnection when IDE is kept busy for long periods - self.daemon.setTimeout(60) - - pyro_obj = Pyro.core.ObjBase() - pyro_obj.delegateTo(runtime.GetPLCObjectSingleton()) - - self.daemon.connect(pyro_obj, "PLCObject") + self.daemon.register(PLCObjectPyroAdapter(runtime.GetPLCObjectSingleton()), "PLCObject") when_ready() - # "pipe to self" trick to to accelerate runtime shutdown - # instead of waiting for arbitrary pyro timeout. - others = [] - if not sys.platform.startswith('win'): - self.piper, self.pipew = os.pipe() - others.append(self.piper) + self.daemon.requestLoop() - self.daemon.requestLoop(others=others, callback=lambda x: None) - self.piper, self.pipew = None, None - if hasattr(self, 'sock'): - self.daemon.sock.close() self.Unpublish() def Restart(self): @@ -81,8 +93,7 @@ def Quit(self): self.continueloop = False - self.daemon.shutdown(True) - self.daemon.closedown() + self.daemon.shutdown() if not sys.platform.startswith('win'): if self.pipew is not None: os.write(self.pipew, "goodbye")