Omaha #4120 Improve PythonOverriderInterface and PythonOverriderCore to handle incremental overrides for HS.
Change-Id: I04ae6553624237e909dbeabbccff40113303aeda Former-commit-id: e79792fddfcb80e72a406a5e817bb7878cb692c0
This commit is contained in:
parent
923fb69061
commit
d9f635e8c7
2 changed files with 59 additions and 22 deletions
|
@ -33,6 +33,7 @@
|
||||||
# 01/20/14 2712 bkowal Improve python class merging. Classes
|
# 01/20/14 2712 bkowal Improve python class merging. Classes
|
||||||
# will now truly override each other
|
# will now truly override each other
|
||||||
# instead of extending each other.
|
# instead of extending each other.
|
||||||
|
# 02/09/15 4120 reblum Fixed bugs in the class merging.
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
@ -42,14 +43,16 @@ import ModuleUtil
|
||||||
|
|
||||||
def _internalOverride(files):
|
def _internalOverride(files):
|
||||||
"""
|
"""
|
||||||
Takes the files and overrides them
|
Combines the different localization levels of the same class/module into a single
|
||||||
|
class/module with the lower localization level methods taking precedence over the
|
||||||
|
higher localization level methods.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
files : the files that are to be overridden
|
files : the files that are to be overridden
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
a new module that contains all the necessary elements
|
a new module that contains all the necessary elements
|
||||||
"""
|
"""
|
||||||
themodule = imp.new_module('tmpmodule')
|
themodule = imp.new_module('tmpmodule')
|
||||||
# modules = list of all the modules
|
# modules = list of all the modules
|
||||||
for module in files :
|
for module in files :
|
||||||
|
@ -126,12 +129,17 @@ def _mergeClasses(source, target, className):
|
||||||
|
|
||||||
attributeName = className + '.' + attr
|
attributeName = className + '.' + attr
|
||||||
target = _mergeAttributes(source, target, attributeName)
|
target = _mergeAttributes(source, target, attributeName)
|
||||||
|
|
||||||
|
# Get the set of unimplemented abstractmethods from the sourceClass
|
||||||
|
abstractMethods = set()
|
||||||
|
if sourceClass.__dict__.has_key('__abstractmethods__'):
|
||||||
|
for method in sourceClass.__abstractmethods__:
|
||||||
|
abstractMethods.add(method)
|
||||||
|
|
||||||
# make new class "extend" the original class
|
# make new class "extend" the original class
|
||||||
for attr in dir(targetClass):
|
for attr in dir(targetClass):
|
||||||
if attr != '__init__' \
|
if isinstance(getattr(targetClass, attr), types.MethodType) \
|
||||||
and isinstance(getattr(targetClass, attr), types.MethodType) \
|
and not attr in sourceClass.__dict__:
|
||||||
and not attr in dir(sourceClass):
|
|
||||||
# complete the merge / override of methods for any method that
|
# complete the merge / override of methods for any method that
|
||||||
# the new class does not implement
|
# the new class does not implement
|
||||||
|
|
||||||
|
@ -141,7 +149,17 @@ def _mergeClasses(source, target, className):
|
||||||
# copy the method implementation to the other class and give it
|
# copy the method implementation to the other class and give it
|
||||||
# the same name as the original
|
# the same name as the original
|
||||||
classMethodDirective = _buildReplaceClassMethodDirective(className, attr)
|
classMethodDirective = _buildReplaceClassMethodDirective(className, attr)
|
||||||
exec(classMethodDirective)
|
exec(classMethodDirective)
|
||||||
|
# If the method we just merged was an abstractmethod remove it from
|
||||||
|
# abstractMethods since it now has been implemented.
|
||||||
|
if attr in abstractMethods:
|
||||||
|
abstractMethods.remove(attr)
|
||||||
|
|
||||||
|
# Update __abstractmethods__ so that it correctly reflects if there are any
|
||||||
|
# unimplemented abstactmethods for the merged class.
|
||||||
|
if sourceClass.__dict__.has_key('__abstractmethods__'):
|
||||||
|
directive = 'sourceClass.__abstractmethods__ = frozenset(abstractMethods)'
|
||||||
|
exec(directive)
|
||||||
|
|
||||||
return _mergeAttributes(source, target, className)
|
return _mergeAttributes(source, target, className)
|
||||||
|
|
||||||
|
@ -164,8 +182,13 @@ def _compareClasses(clazz1, clazz2):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# compare the attributes directly
|
# compare the attributes directly
|
||||||
attr1 = getattr(clazz1, clazz1Attr[i])
|
attr1 = None
|
||||||
attr2 = getattr(clazz2, clazz2Attr[i])
|
attr2 = None
|
||||||
|
# see http://bugs.python.org/issue10006
|
||||||
|
if clazz1Attr[i] != '__abstractmethods__':
|
||||||
|
attr1 = getattr(clazz1, clazz1Attr[i])
|
||||||
|
if clazz2Attr[i] != '__abstractmethods__':
|
||||||
|
attr2 = getattr(clazz2, clazz2Attr[i])
|
||||||
if (attr1 != attr2):
|
if (attr1 != attr2):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
|
@ -23,25 +23,31 @@
|
||||||
# Python RollbackMasterInterface. The objective of this class is
|
# Python RollbackMasterInterface. The objective of this class is
|
||||||
# to prevent the MasterInterface from completing imports because the
|
# to prevent the MasterInterface from completing imports because the
|
||||||
# MasterInterface will overwrite modules instead of merging them.
|
# MasterInterface will overwrite modules instead of merging them.
|
||||||
#
|
#
|
||||||
|
# TODO: njensen thinks it may be safer and more stable to dynamically
|
||||||
|
# create a new type with the appropriate inheritance tree and then
|
||||||
|
# utilize normal object-oriented inheritance to provide the incremental/selective
|
||||||
|
# overrides capability. Investigate as necessary.
|
||||||
#
|
#
|
||||||
# SOFTWARE HISTORY
|
# SOFTWARE HISTORY
|
||||||
#
|
#
|
||||||
# Date Ticket# Engineer Description
|
# Date Ticket# Engineer Description
|
||||||
# ------------ ---------- ----------- --------------------------
|
# ------------ ---------- ----------- --------------------------
|
||||||
# 01/14/2014 #2766 bkowal Initial Creation.
|
# 01/14/2014 #2766 bkowal Initial Creation.
|
||||||
|
# 02/09/2015 #4120 reblum Inherit straight from MasterInterface.
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
|
||||||
import os, sys, string, traceback
|
import os, sys, string, traceback
|
||||||
import RollbackMasterInterface
|
import MasterInterface
|
||||||
import PythonOverrider
|
import PythonOverrider
|
||||||
|
|
||||||
class PythonOverriderInterface(RollbackMasterInterface.RollbackMasterInterface):
|
class PythonOverriderInterface(MasterInterface.MasterInterface):
|
||||||
def __init__(self, scriptPath, localizationPath=None):
|
def __init__(self, scriptPath, localizationPath=None):
|
||||||
super(PythonOverriderInterface, self).__init__(scriptPath)
|
super(PythonOverriderInterface, self).__init__()
|
||||||
self._localizationPath = localizationPath
|
self._localizationPath = localizationPath
|
||||||
|
self._scriptPath = scriptPath
|
||||||
|
|
||||||
def importModules(self):
|
def importModules(self):
|
||||||
modulesToImport = []
|
modulesToImport = []
|
||||||
|
@ -58,22 +64,23 @@ class PythonOverriderInterface(RollbackMasterInterface.RollbackMasterInterface):
|
||||||
|
|
||||||
for moduleName in modulesToImport:
|
for moduleName in modulesToImport:
|
||||||
self._importModule(moduleName)
|
self._importModule(moduleName)
|
||||||
|
|
||||||
def addModule(self, moduleName):
|
def addModule(self, moduleName):
|
||||||
if not moduleName in self.scripts:
|
if not moduleName in self.scripts:
|
||||||
self.scripts.append(moduleName)
|
self.scripts.append(moduleName)
|
||||||
self.reloadModules()
|
self.reloadModules()
|
||||||
|
|
||||||
|
def reloadModule(self, moduleName):
|
||||||
|
if sys.modules.has_key(moduleName):
|
||||||
|
self.clearModuleAttributes(moduleName)
|
||||||
|
self._importModule(moduleName)
|
||||||
|
|
||||||
def reloadModules(self):
|
def reloadModules(self):
|
||||||
for script in self.scripts:
|
for script in self.scripts:
|
||||||
# first remove all references to the existing module
|
self.clearModuleAttributes(script)
|
||||||
if sys.modules.has_key(script):
|
|
||||||
self.clearModuleAttributes(script)
|
|
||||||
sys.modules.pop(script)
|
|
||||||
|
|
||||||
# now use PythonOverrider to re-import the module
|
# now use PythonOverrider to re-import the module
|
||||||
self._importModule(script)
|
self._importModule(script)
|
||||||
|
|
||||||
def _importModule(self, moduleName):
|
def _importModule(self, moduleName):
|
||||||
scriptName = moduleName + '.py'
|
scriptName = moduleName + '.py'
|
||||||
if self._localizationPath:
|
if self._localizationPath:
|
||||||
|
@ -86,4 +93,11 @@ class PythonOverriderInterface(RollbackMasterInterface.RollbackMasterInterface):
|
||||||
return
|
return
|
||||||
|
|
||||||
if not moduleName in self.scripts:
|
if not moduleName in self.scripts:
|
||||||
self.scripts.append(moduleName)
|
self.scripts.append(moduleName)
|
||||||
|
|
||||||
|
def getStartupErrors(self):
|
||||||
|
from java.util import ArrayList
|
||||||
|
errorList = ArrayList()
|
||||||
|
for err in self.getImportErrors():
|
||||||
|
errorList.add(str(err))
|
||||||
|
return errorList
|
Loading…
Add table
Reference in a new issue