cache PropertyHolder.property_list and use O(1) property name lookups
This commit is contained in:
parent
f2b8ad7d38
commit
d183ab1c18
@ -496,7 +496,7 @@ class PropertyHolder(qubes.events.Emitter):
|
|||||||
|
|
||||||
propvalues = {}
|
propvalues = {}
|
||||||
|
|
||||||
all_names = set(prop.__name__ for prop in self.property_list())
|
all_names = self.property_dict()
|
||||||
for key in list(kwargs):
|
for key in list(kwargs):
|
||||||
if not key in all_names:
|
if not key in all_names:
|
||||||
continue
|
continue
|
||||||
@ -509,8 +509,6 @@ class PropertyHolder(qubes.events.Emitter):
|
|||||||
|
|
||||||
if self.xml is not None:
|
if self.xml is not None:
|
||||||
# check if properties are appropriate
|
# check if properties are appropriate
|
||||||
all_names = set(prop.__name__ for prop in self.property_list())
|
|
||||||
|
|
||||||
for node in self.xml.xpath('./properties/property'):
|
for node in self.xml.xpath('./properties/property'):
|
||||||
name = node.get('name')
|
name = node.get('name')
|
||||||
if name not in all_names:
|
if name not in all_names:
|
||||||
@ -518,6 +516,39 @@ class PropertyHolder(qubes.events.Emitter):
|
|||||||
'property {!r} not applicable to {!r}'.format(
|
'property {!r} not applicable to {!r}'.format(
|
||||||
name, self.__class__.__name__))
|
name, self.__class__.__name__))
|
||||||
|
|
||||||
|
# pylint: disable=too-many-nested-blocks
|
||||||
|
@classmethod
|
||||||
|
def property_dict(cls, load_stage=None):
|
||||||
|
'''List all properties attached to this VM's class
|
||||||
|
|
||||||
|
:param load_stage: Filter by load stage
|
||||||
|
:type load_stage: :py:func:`int` or :py:obj:`None`
|
||||||
|
'''
|
||||||
|
|
||||||
|
# use cls.__dict__ since we must not look at parent classes
|
||||||
|
if "_property_dict" not in cls.__dict__:
|
||||||
|
cls._property_dict = {}
|
||||||
|
memo = cls._property_dict
|
||||||
|
|
||||||
|
if load_stage not in memo:
|
||||||
|
props = dict()
|
||||||
|
if load_stage is None:
|
||||||
|
for class_ in cls.__mro__:
|
||||||
|
for name in class_.__dict__:
|
||||||
|
# don't overwrite props with those from base classes
|
||||||
|
if name not in props:
|
||||||
|
prop = class_.__dict__[name]
|
||||||
|
if isinstance(prop, property):
|
||||||
|
assert name == prop.__name__
|
||||||
|
props[name] = prop
|
||||||
|
else:
|
||||||
|
for prop in cls.property_dict().values():
|
||||||
|
if prop.load_stage == load_stage:
|
||||||
|
props[prop.__name__] = prop
|
||||||
|
memo[load_stage] = props
|
||||||
|
|
||||||
|
return memo[load_stage]
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def property_list(cls, load_stage=None):
|
def property_list(cls, load_stage=None):
|
||||||
'''List all properties attached to this VM's class
|
'''List all properties attached to this VM's class
|
||||||
@ -526,14 +557,15 @@ class PropertyHolder(qubes.events.Emitter):
|
|||||||
:type load_stage: :py:func:`int` or :py:obj:`None`
|
:type load_stage: :py:func:`int` or :py:obj:`None`
|
||||||
'''
|
'''
|
||||||
|
|
||||||
props = set()
|
# use cls.__dict__ since we must not look at parent classes
|
||||||
for class_ in cls.__mro__:
|
if "_property_list" not in cls.__dict__:
|
||||||
props.update(prop for prop in class_.__dict__.values()
|
cls._property_list = {}
|
||||||
if isinstance(prop, property))
|
memo = cls._property_list
|
||||||
if load_stage is not None:
|
|
||||||
props = set(prop for prop in props
|
if load_stage not in memo:
|
||||||
if prop.load_stage == load_stage)
|
memo[load_stage] = sorted(cls.property_dict(load_stage).values())
|
||||||
return sorted(props)
|
|
||||||
|
return memo[load_stage]
|
||||||
|
|
||||||
def _property_init(self, prop, value):
|
def _property_init(self, prop, value):
|
||||||
'''Initialise property to a given value, without side effects.
|
'''Initialise property to a given value, without side effects.
|
||||||
@ -588,9 +620,9 @@ class PropertyHolder(qubes.events.Emitter):
|
|||||||
if isinstance(prop, qubes.property):
|
if isinstance(prop, qubes.property):
|
||||||
return prop
|
return prop
|
||||||
|
|
||||||
for p in cls.property_list():
|
props = cls.property_dict()
|
||||||
if p.__name__ == prop:
|
if prop in props:
|
||||||
return p
|
return props[prop]
|
||||||
|
|
||||||
raise AttributeError('No property {!r} found in {!r}'.format(
|
raise AttributeError('No property {!r} found in {!r}'.format(
|
||||||
prop, cls))
|
prop, cls))
|
||||||
|
Loading…
Reference in New Issue
Block a user