From 517eb8be59ba469d839618e5dceed58a3f82566b Mon Sep 17 00:00:00 2001 From: Vincent Aranega Date: Sun, 20 May 2018 00:15:49 +0200 Subject: [PATCH] Backport performances improvement from Python 3 PyEcore version --- pyecore/ecore.py | 68 +++++++++++++++++++---------------- pyecore/resources/resource.py | 2 +- pyecore/valuecontainer.py | 15 ++++---- tests/test_dynamic.py | 18 ++++++++-- 4 files changed, 63 insertions(+), 40 deletions(-) diff --git a/pyecore/ecore.py b/pyecore/ecore.py index 1ebc8ed..6607002 100644 --- a/pyecore/ecore.py +++ b/pyecore/ecore.py @@ -22,7 +22,7 @@ from decimal import Decimal from datetime import datetime from ordered_set import OrderedSet -from .notification import ENotifer, Kind, EObserver +from .notification import ENotifer, Kind from .innerutils import ignored, javaTransMap @@ -67,20 +67,20 @@ def getEClassifier(name, searchspace=None): class Core(object): @staticmethod - def _promote(cls, abstract=False): - cls.eClass = EClass(cls.__name__, metainstance=cls) - cls.eClass.abstract = abstract - cls._staticEClass = True + def _promote(rcls, abstract=False): + rcls.eClass = EClass(rcls.__name__, metainstance=rcls) + rcls.eClass.abstract = abstract + rcls._staticEClass = True # init super types - eSuperTypes_add = cls.eClass.eSuperTypes.append - for _cls in cls.__bases__: + eSuperTypes_add = rcls.eClass.eSuperTypes.append + for _cls in rcls.__bases__: if _cls is EObject: continue with ignored(Exception): eSuperTypes_add(_cls.eClass) # init eclass by reflection - eStructuralFeatures_add = cls.eClass.eStructuralFeatures.append - for k, feature in cls.__dict__.items(): + eStructuralFeatures_add = rcls.eClass.eStructuralFeatures.append + for k, feature in rcls.__dict__.items(): if isinstance(feature, EStructuralFeature): if not feature.name: feature.name = k @@ -101,13 +101,13 @@ def _promote(cls, abstract=False): if i < nb_required: parameter.required = True operation.eParameters.append(parameter) - cls.eClass.eOperations.append(operation) + rcls.eClass.eOperations.append(operation) - @staticmethod - def register_classifier(cls, abstract=False, promote=False): + @classmethod + def register_classifier(cls, rcls, abstract=False, promote=False): if promote: - Core._promote(cls, abstract) - epackage = sys.modules[cls.__module__] + cls._promote(rcls, abstract) + epackage = sys.modules[rcls.__module__] if not hasattr(epackage, 'eClassifiers'): eclassifs = {} epackage.eClassifiers = eclassifs @@ -121,14 +121,14 @@ def register_classifier(cls, abstract=False, promote=False): nsURI='http://{}/'.format(pack_name)) if not hasattr(epackage, 'eURIFragment'): epackage.eURIFragment = eURIFragment - cname = cls.name if isinstance(cls, EClassifier) else cls.__name__ - epackage.eClassifiers[cname] = cls - if isinstance(cls, EDataType): - epackage.eClass.eClassifiers.append(cls) - cls._container = epackage + cname = rcls.name if isinstance(rcls, EClassifier) else rcls.__name__ + epackage.eClassifiers[cname] = rcls + if isinstance(rcls, EDataType): + epackage.eClass.eClassifiers.append(rcls) + rcls._container = epackage else: - epackage.eClass.eClassifiers.append(cls.eClass) - cls.eClass._container = epackage + epackage.eClass.eClassifiers.append(rcls.eClass) + rcls.eClass._container = epackage class EObject(ENotifer): @@ -332,6 +332,17 @@ def __init__(self, name=None, eType=None, ordered=True, unique=True, self.ordered = ordered self.unique = unique self.required = required + self._many_cache = self._compute_many() + self._eternal_listener.append(self) + + def _compute_many(self): + upper = self.upperBound + lower = self.lowerBound + return upper < 0 or upper > 1 and upper - lower > 1 + + def notifyChanged(self, notif): + if notif.feature is ETypedElement.upperBound: + self._many_cache = self._compute_many() @property def upper(self): @@ -343,8 +354,7 @@ def lower(self): @property def many(self): - upperbound = self.upperBound - return upperbound < 0 or upperbound > 1 + return self._many_cache class EOperation(ETypedElement): @@ -542,9 +552,9 @@ def __init__(self, name=None, eType=None, changeable=True, volatile=False, self.derived = derived self.derived_class = derived_class or ECollection self._name = name - self._eternal_listener.append(self) def notifyChanged(self, notif): + super(EStructuralFeature, self).notifyChanged(notif) if notif.feature is ENamedElement.name: self._name = notif.new @@ -561,9 +571,9 @@ def __get__(self, instance, owner=None): instance_dict[name] = new_value return new_value._get() value = instance_dict[name] - if type(value) is EValue: + try: return value._get() - else: + except AttributeError: return value def __set__(self, instance, value): @@ -666,15 +676,13 @@ def new_init(self, *args, **kwargs): instance.__compute_supertypes(), attr_dict) instance.__name__ = name - instance.supertypes_updater = EObserver() - instance.supertypes_updater.notifyChanged = instance.__update - instance._eternal_listener.append(instance.supertypes_updater) return instance def __init__(self, name=None, superclass=None, abstract=False, metainstance=None, **kwargs): super(EClass, self).__init__(name, **kwargs) self.abstract = abstract + self._eternal_listener.append(self) def __call__(self, *args, **kwargs): if self.abstract: @@ -682,7 +690,7 @@ def __call__(self, *args, **kwargs): .format(self.name)) return self.python_class(*args, **kwargs) - def __update(self, notif): + def notifyChanged(self, notif): # We do not update in case of static metamodel (could be changed) if getattr(self.python_class, '_staticEClass', False): return diff --git a/pyecore/resources/resource.py b/pyecore/resources/resource.py index f8f3bba..e9efbd7 100644 --- a/pyecore/resources/resource.py +++ b/pyecore/resources/resource.py @@ -297,7 +297,7 @@ def resolve(self, fragment, resource=None): @staticmethod def extract_rootnum_and_frag(fragment): - if re.match('^/\d+.*', fragment): + if re.match(r'^/\d+.*', fragment): fragment = fragment[1:] if '/' in fragment: index = fragment.index('/') diff --git a/pyecore/valuecontainer.py b/pyecore/valuecontainer.py index db1e89f..450b879 100644 --- a/pyecore/valuecontainer.py +++ b/pyecore/valuecontainer.py @@ -26,7 +26,7 @@ def isinstance(obj, _type): return False @staticmethod - def getRoot(obj): + def get_root(obj): if not obj: return None previous = obj @@ -40,13 +40,14 @@ def __init__(self, owner, efeature): super(PyEcoreValue, self).__init__() self.owner = owner self.feature = efeature + self.is_ref = isinstance(efeature, EReference) def check(self, value): if not EcoreUtils.isinstance(value, self.feature.eType): raise BadValueError(value, self.feature.eType) def _update_container(self, value, previous_value=None): - if not isinstance(self.feature, EReference): + if not self.is_ref: return if not self.feature.containment: return @@ -82,7 +83,7 @@ def _set(self, value, update_opposite=True): owner.notify(notif) owner._isset.add(efeature) - if not isinstance(efeature, EReference): + if not self.is_ref: return self._update_container(value, previous_value) if not update_opposite: @@ -141,7 +142,7 @@ def _get(self): return self def _update_opposite(self, owner, new_value, remove=False): - if not isinstance(self.feature, EReference): + if not self.is_ref: return eOpposite = self.feature.eOpposite if not eOpposite: @@ -365,14 +366,14 @@ def __setitem__(self, index, item): raise AttributeError('Operation not permited for "{}" feature' .format(self.feature.name)) - def add(self, item): + def add(self, value): raise AttributeError('Operation not permited for "{}" feature' .format(self.feature.name)) - def discard(self, item): + def discard(self, value): raise AttributeError('Operation not permited for "{}" feature' .format(self.feature.name)) - def insert(self, index, item): + def insert(self, index, value): raise AttributeError('Operation not permited for "{}" feature' .format(self.feature.name)) diff --git a/tests/test_dynamic.py b/tests/test_dynamic.py index 9d7a8b8..62b9955 100644 --- a/tests/test_dynamic.py +++ b/tests/test_dynamic.py @@ -406,8 +406,8 @@ def test_create_dynamic_contaiment_getroot(): a1 = A() b1 = B() a1.b = b1 - assert EcoreUtils.getRoot(b1) is a1 - assert EcoreUtils.getRoot(None) is None + assert EcoreUtils.get_root(b1) is a1 + assert EcoreUtils.get_root(None) is None assert b1.eRoot() is a1 @@ -1009,3 +1009,17 @@ def test_containerswitching(): assert a3.eContainer() is a1 assert a2.eContainer() is None assert a2.eContainmentFeature() is None + + +def test_structuralfeature_many_computation(): + attrib = EAttribute('attrib') + assert attrib.many is False + + attrib.upperBound = -1 + assert attrib.many is True + + attrib.lowerBound = 2 + assert attrib.many is True + + attrib.upperBound = attrib.lowerBound + assert attrib.many is False