4.2. CIM objects
CIM objects are local representations of CIM instances, classes, properties, etc., as Python objects. They are used as input to and output from WBEM operations:
CIM object |
Purpose |
---|---|
|
Instance path of a CIM instance |
|
CIM instance |
|
Name of a CIM class, optionally with class path |
|
CIM class |
|
CIM property, both as property value in a CIM instance and as property declaration in a CIM class |
|
CIM method declaration in a CIM class |
|
CIM parameter, both as a parameter value in a method invocation and as a parameter declaration in a CIM method declaration in a CIM class |
|
CIM qualifier value |
|
CIM qualifier type/declaration |
4.2.1. Putting CIM objects in sets
Using sets for holding the result of WBEM operations is not uncommon, because that allows comparison of results without regard to the (undefined) order in which the objects are returned.
CIM objects are mutable and unchanged-hashable. This requires some caution when putting them in sets, or using them in any other way that relies on their hash values.
The caution that is needed is that the public attributes, and therefore the state of the CIM objects, must not change as long as they are a member of a set, or used in any other way that relies on their hash values.
The following example shows what happens if a CIM object is modified while being a member of a set:
import pywbem
s = set()
# Create CIM object c1 and show its identity and hash value:
c1 = pywbem.CIMClass('C')
print(id(c1), hash(c1)) # (140362966049680, -7623128493967117119)
# Add c1 to the set and verify the set content:
s.add(c1)
print([id(c) for c in s]) # [140362966049680]
# Modify the c1 object; it now has changed its hash value:
c1.superclass = 'B'
print(id(c1), hash(c1)) # (140362966049680, 638672161836520435)
# Create a CIM object c2 with the same attribute values as c1, and show
# that they compare equal and that c2 has the same hash value as c1 now has:
c2 = pywbem.CIMClass('C', superclass='B')
print(c1 == c2) # True
print(id(c2), hash(c2)) # (140362970983696, 638672161836520435)
# Add c2 to the set and verify the set content:
s.add(c2)
print([id(c) for c in s]) # [140362966049680, 140362970983696] !!
At the end, the set contains both objects even though they have the same hash value. This is not what one would expect from set types.
The reason is that at the time the object c1 was added to the set, it had a different hash value, and the set uses the hash value it found at insertion time of its member for identifying the object. When the second object is added, it finds it has a yet unknown hash value, and adds it.
While the set type in this particular Python implementation was able to still look up the first member object even though its hash value has changed meanwhile, other collection types or other Python implementations may not be as forgiving and may not even be able to look up the object once its hash value has changed.
Therefore, always make sure that the public attributes of CIM objects that are put into a set remain unchanged while the object is in the set. The same applies to any other usage of CIM objects that relies on their hash values.
4.2.2. Order of CIM child objects
CIM objects have zero or more lists of child objects. For example, a CIM class (the parent object) has a list of CIM properties, CIM methods and CIM qualifiers (the child objects).
In pywbem, the parent CIM object allows initializing each list of child objects
via an init parameter. For example, the CIMClass
init method
has a parameter named properties
that allows specifying the CIM properties
of the CIM class.
Once the parent CIM object exists, each list of child objects can be modified
via a settable attribute. For example, the CIMClass
class has
a properties
attribute for its list of CIM properties.
For such attributes and init parameters that specify lists of child objects, pywbem supports a number of different ways the child objects can be specified.
Some of these ways preserve the order of child objects and some don’t.
This section uses CIM properties in CIM classes as an example, but it applies to all kinds of child objects in CIM objects.
The possible input objects for the properties
init parameter
and for the properties
attribute of
CIMClass
is described in the type
properties input object, and must be one of these objects:
iterable of
CIMProperty
iterable of tuple(key, value)
OrderedDict
with key and valuepy:dict
with key and value (will not preserve order)
The keys are always the property names, and the values are always
CIMProperty
objects (at least when initializing classes).
Even though the OrderedDict
class preserves the order
of its items, intializing the dictionary with keyword arguments causes the
order of items to be lost before the dictionary is even initialized (before
Python 3.6). The only way to initialize a dictionary without loosing order of
items is by providing a list of tuples(key,value).
The following examples work but loose the order of properties in the class:
# Examples where order of properties in class is not as specified:
# Using an OrderedDict object, initialized with keyword arguments
# (before Python 3.6):
c1_props = OrderedDict(
Prop1=CIMProperty('Prop1', value='abc'),
Prop2=CIMProperty('Prop2', value=None, type='string'),
)
# Using a dict object, initialized with keyword arguments (This time
# specified using key:value notation):
c1_props = {
'Prop1': CIMProperty('Prop1', value='abc'),
'Prop2': CIMProperty('Prop2', value=None, type='string'),
}
# Using a dict object, initialized with list of tuple(key,value):
c1_props = dict([
('Prop1', CIMProperty('Prop1', value='abc')),
('Prop2', CIMProperty('Prop2', value=None, type='string')),
])
# Any of the above objects can be used to initialize the class properties:
c1 = CIMClass('CIM_Foo', properties=c1_props)
The following examples all preserve the order of properties in the class:
# Examples where order of properties in class is as specified:
# Using a list of CIMProperty objects (starting with pywbem 0.12):
c1_props = [
CIMProperty('Prop1', value='abc'),
CIMProperty('Prop2', value=None, type='string'),
]
# Using an OrderedDict object, initialized with list of tuple(key,value):
c1_props = OrderedDict([
('Prop1', CIMProperty('Prop1', value='abc')),
('Prop2', CIMProperty('Prop2', value=None, type='string')),
])
# Using a list of tuple(key,value):
c1_props = [
('Prop1', CIMProperty('Prop1', value='abc')),
('Prop2', CIMProperty('Prop2', value=None, type='string')),
]
# Any of the above objects can be used to initialize the class properties:
c1 = CIMClass('CIM_Foo', properties=c1_props)
4.2.3. NocaseDict
Class NocaseDict
is a dictionary implementation with case-insensitive but
case-preserving keys, and with preservation of the order of its items.
It is used for lists of child objects of CIM objects (e.g. the list of CIM properties in a CIM class, or the list of CIM parameters in a CIM method).
Users of pywbem will notice NocaseDict
objects only as a result of pywbem
functions. Users cannot create NocaseDict
objects.
Except for the case-insensitivity of its keys, it behaves like the built-in
OrderedDict
. Therefore, NocaseDict
is not
described in detail in this documentation.