Package pywbem :: Module cim_obj |
[frames] | no frames]

# Source Code for Module pywbem.cim_obj

       1  #
       2  # (C) Copyright 2003-2007 Hewlett-Packard Development Company, L.P.
       3  # (C) Copyright 2006-2007 Novell, Inc.
       4  #
       5  # This library is free software; you can redistribute it and/or
       6  # modify it under the terms of the GNU Lesser General Public
       7  # License as published by the Free Software Foundation; either
       8  # version 2.1 of the License, or (at your option) any later version.
       9  #
      10  # This program is distributed in the hope that it will be useful, but
      11  # WITHOUT ANY WARRANTY; without even the implied warranty of
      12  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13  # Lesser General Public License for more details.
      14  #
      15  # You should have received a copy of the GNU Lesser General Public
      16  # License along with this program; if not, write to the Free Software
      17  # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
      18  #
      19  # Author: Tim Potter <tpot@hp.com>
      20  # Author: Martin Pool <mbp@hp.com>
      21  # Author: Bart Whiteley <bwhiteley@suse.de>
      22  #
      23
      24  """Representations of CIM objects, and a case-insensitive dictionary.
      25
      26  In general we try to map CIM objects directly into Python primitives,
      27  except when that is not possible or would be ambiguous.  For example,
      28  CIM class names are simply Python strings, but a class path is
      29  represented as a special Python object.
      30
      31  These objects can also be mapped back into CIM-XML, by their `tocimxml()`
      32  method which returns a CIM-XML string.
      33  """
      34
      35  # This module is meant to be safe for 'import *'.
      36
      37  import string
      38  import re
      39  from types import StringTypes
      40  from datetime import datetime, timedelta
      41
      42  from pywbem import cim_xml, cim_types
      43
      44  __all__ = ['NocaseDict', 'cmpname', 'CIMClassName', 'CIMProperty',
      45             'CIMInstanceName', 'CIMInstance', 'CIMClass', 'CIMMethod',
      46             'CIMParameter', 'CIMQualifier', 'CIMQualifierDeclaration',
      47             'tocimxml', 'tocimobj', 'byname']
      48
      49 -class NocaseDict(object):
      50      """
      51      Yet another implementation of a case-insensitive dictionary.
      52
      53      Whenever keys are looked up, that is done case-insensitively. Whenever
      54      keys are returned, they are returned with the lexical case that was
      55      originally specified.
      56
      57      In addition to the methods listed, the dictionary supports:
      58
      59        * Retrieval of values based on key: `val = d[key]`
      60
      61        * Assigning values for a key: `d[key] = val`
      62
      63        * Deleting a key/value pair: `del d[key]`
      64
      65        * Equality comparison (`==`, `!=`)
      66
      67        * Ordering comparison (`<`, `<=`, `>=`, `>`)
      68
      69        * Containment test: `key in d`
      70
      71        * For loops: `for key in d`
      72
      73        * Determining length: `len(d)`
      74      """
      75
      76 -    def __init__(self, *args, **kwargs):
      77          """
      78          Initialize the new dictionary from at most one positional argument and
      79          optionally from additional keyword arguments.
      80
      81          Initialization happens in two steps, first from the positional
      82          argument:
      83
      84            * If no positional argument is provided, or if one argument with the
      85              value None is provided, the new dictionary will be left empty in
      86              this step.
      87
      88            * If one positional argument of sequence type is provided, the items
      89              in that sequence must be tuples of key and value, respectively.
      90              The key/value pairs will be put into the new dictionary (without
      91              copying them).
      92
      93            * If one positional argument of dictionary (mapping) or `NocaseDict`
      94              type is provided, its key/value pairs are put into the new
      95              dictionary (without copying them).
      96
      97            * Otherwise, `TypeError` is raised.
      98
      99          After that, any provided keyword arguments are put into the so
     100          initialized dictionary as key/value pairs (without copying them).
     101          """
     102
     103          self._data = {}
     104
     105          # Step 1: Initialize from at most one positional argument
     106          if len(args) == 1:
     107              if isinstance(args[0], list):
     108                  # Initialize from sequence object
     109                  for item in args[0]:
     110                      self[item[0]] = item[1]
     111              elif isinstance(args[0], dict):
     112                  # Initialize from mapping object
     113                  self.update(args[0])
     114              elif isinstance(args[0], NocaseDict):
     115                  # Initialize from another NocaseDict object
     116                  self._data = args[0]._data.copy() # pylint: disable=protected-access
     117              elif args[0] is None:
     118                  # Leave empty
     119                  pass
     120              else:
     121                  raise TypeError("Invalid type for NocaseDict " \
     122                                  "initialization: %s" % repr(args[0]))
     123          elif len(args) > 1:
     124              raise TypeError("Too many positional arguments for NocaseDict " \
     125                                  "initialization: %s" % repr(args))
     126
     127          # Step 2: Add any keyword arguments
     128          self.update(kwargs)
     129
     130      # Basic accessor and settor methods
     131
     132 -    def __getitem__(self, key):
     133          """
     134          Invoked when retrieving the value for a key, using `val = d[key]`.
     135
     136          The key is looked up case-insensitively. Raises `KeyError` if the
     137          specified key does not exist. Note that __setitem__() ensures that
     138          only string typed keys will exist, so the key type is not tested here
     139          and specifying non-string typed keys will simply lead to a KeyError.
     140          """
     141          k = key
     142          if isinstance(key, (str, unicode)):
     143              k = k.lower()
     144          try:
     145              return self._data[k][1]
     146          except KeyError:
     147              raise KeyError('Key %s not found in %r' % (key, self))
     148
     149 -    def __setitem__(self, key, value):
     150          """
     151          Invoked when assigning a value for a key using `d[key] = val`.
     152
     153          The key is looked up case-insensitively. If the key does not exist,
     154          it is added with the new value. Otherwise, its value is overwritten
     155          with the new value.
     156
     157          Raises `TypeError` if the specified key does not have string type.
     158          """
     159          if not isinstance(key, (str, unicode)):
     160              raise TypeError('NocaseDict key %s must be string type, ' \
     161                              'but is %s' %  (key, type(key)))
     162          k = key.lower()
     163          self._data[k] = (key, value)
     164
     165 -    def __delitem__(self, key):
     166          """
     167          Invoked when deleting a key/value pair using `del d[key]`.
     168
     169          The key is looked up case-insensitively. Raises `KeyError` if the
     170          specified key does not exist. Note that __setitem__() ensures that
     171          only string typed keys will exist, so the key type is not tested here
     172          and specifying non-string typed keys will simply lead to a KeyError.
     173          """
     174          k = key
     175          if isinstance(key, (str, unicode)):
     176              k = k.lower()
     177          try:
     178              del self._data[k]
     179          except KeyError:
     180              raise KeyError('Key %s not found in %r' % (key, self))
     181
     182 -    def __len__(self):
     183          """
     184          Invoked when determining the number of key/value pairs in the
     185          dictionary using `len(d)`.
     186          """
     187          return len(self._data)
     188
     189 -    def has_key(self, key):
     190          """
     191          Return a boolean indicating whether a specific key is in the
     192          dictionary.
     193
     194          The key is looked up case-insensitively.
     195
     196          This method is deprecated in favor of using `key in d`.
     197          """
     198          return key in self # delegate to __contains__()
     199
     200 -    def __contains__(self, key):
     201          """
     202          Invoked when determining whether a specific key is in the dictionary
     203          using `key in d`.
     204
     205          The key is looked up case-insensitively.
     206          """
     207          k = key
     208          if isinstance(key, (str, unicode)):
     209              k = k.lower()
     210          return k in self._data
     211
     212 -    def get(self, key, default=None):
     213          """
     214          Get the value for a specific key, or the specified default value if
     215          the key does not exist.
     216
     217          The key is looked up case-insensitively.
     218          """
     219          try:
     220              return self[key]
     221          except KeyError:
     222              return default
     223
     224 -    def setdefault(self, key, default):
     225          """
     226          Assign the specified default value for a specific key if the key did
     227          not exist and return the value for the key.
     228
     229          The key is looked up case-insensitively.
     230          """
     231          if not self.has_key(key):
     232              self[key] = default
     233          return self[key]
     234
     235      # Other accessor expressed in terms of iterators
     236
     237 -    def keys(self):
     238          """
     239          Return a copied list of the dictionary keys, in their original case.
     240          """
     241          return list(self.iterkeys())
     242
     243 -    def values(self):
     244          """
     245          Return a copied list of the dictionary values.
     246          """
     247          return list(self.itervalues())
     248
     249 -    def items(self):
     250          """
     251          Return a copied list of the dictionary items, where each item is a
     252          tuple of its original key and its value.
     253          """
     254          return list(self.iteritems())
     255
     256      # Iterators
     257
     258 -    def iterkeys(self):
     259          """
     260          Return an iterator through the dictionary keys in their original
     261          case.
     262          """
     263          for item in self._data.iteritems():
     264              yield item[1][0]
     265
     266 -    def itervalues(self):
     267          """
     268          Return an iterator through the dictionary values.
     269          """
     270          for item in self._data.iteritems():
     271              yield item[1][1]
     272
     273 -    def iteritems(self):
     274          """
     275          Return an iterator through the dictionary items, where each item is a
     276          tuple of its original key and its value.
     277          """
     278          for item in self._data.iteritems():
     279              yield item[1]
     280
     281 -    def __iter__(self):
     282          """
     283          Invoked when iterating through the dictionary using `for key in d`.
     284
     285          The returned keys have their original case.
     286          """
     287          return self.iterkeys()
     288
     289      # Other stuff
     290
     291 -    def __repr__(self):
     292          """
     293          Invoked when using `repr(d)`.
     294
     295          The representation hides the implementation data structures and shows
     296          a dictionary that can be used for the constructor.
     297          """
     298          items = ', '.join([('%r: %r' % (key, value))
     299                             for key, value in self.iteritems()])
     300          return 'NocaseDict({%s})' % items
     301
     302 -    def update(self, *args, **kwargs):
     303          """
     304          Update the dictionary from sequences of key/value pairs provided in any
     305          positional arguments, and from key/value pairs provided in any keyword
     306          arguments. The key/value pairs are not copied.
     307
     308          Each positional argument can be:
     309
     310            * an object with a method `items()` that returns an iterable of
     311              tuples containing key and value.
     312
     313            * an object without such a method, that is an iterable of tuples
     314              containing key and value.
     315
     316          Each keyword argument is a key/value pair.
     317          """
     318          for mapping in args:
     319              if hasattr(mapping, 'items'):
     320                  for k, v in mapping.items():
     321                      self[k] = v
     322              else:
     323                  for k, v in mapping:
     324                      self[k] = v
     325          for k, v in kwargs.items():
     326              self[k] = v
     327
     328 -    def clear(self):
     329          """
     330          Remove all items from the dictionary.
     331          """
     332          self._data.clear()
     333
     334 -    def popitem(self):
     335          """
     336          This function does nothing.
     337
     338          In a standard mapping implementation, it would remove and return an
     339          arbitrary item from the dictionary.
     340
     341          TODO: Why does popitem() do nothing; was it simply not implemented?
     342          """
     343          pass
     344
     345 -    def copy(self):
     346          """
     347          Return a shallow copy of the dictionary (i.e. the keys and values are
     348          not copied).
     349          """
     350          result = NocaseDict()
     351          result._data = self._data.copy() # pylint: disable=protected-access
     352          return result
     353
     354 -    def __eq__(self, other):
     355          """
     356          Invoked when two dictionaries are compared for equality or inequality.
     357
     358          The keys are looked up case-insensitively.
     359
     360          The comparison is delegated to equality comparison of matching
     361          key/value pairs.
     362          """
     363          for key, value in self.iteritems():
     364              if not key in other or not other[key] == value:
     365                  return 0
     366          return len(self) == len(other)
     367
     368 -    def __cmp__(self, other):
     369          """
     370          Invoked when two dictionaries are compared for equality, inequality,
     371          and greater-than/less-than comparisons.
     372
     373          The keys are looked up case-insensitively.
     374
     375          `Self` is less than `other`, if:
     376
     377            * a key in `self` is not in `other`, or
     378
     379            * the value for a key in `self` is less than the value for that key
     380              in `other`, or
     381
     382            * `self` has less key/value pairs than `other`.
     383          """
     384          for key, value in self.iteritems():
     385              if not key in other:
     386                  return -1
     387              rv = cmp(value, other[key])
     388              if rv != 0:
     389                  return rv
     390          return len(self) - len(other)
     391
     392 -def _intended_value(intended, unspecified, actual, name, msg):
     393      """
     394      Return the intended value if the actual value is unspecified or has
     395      the intended value already, and otherwise raise a ValueError with the
     396      specified error message.
     397
     398      Arguments:
     399
     400        * `intended`: The intended value, or sequence of values. The first
     401          item in the sequence will act as the intended value, the others
     402          are also valid values.
     403        * `unspecified`: A value indicating 'unspecified' (usually `None`).
     404        * `actual`: The actual value.
     405        * `name`: The name of the attribute that this is about, for use in the
     406          exception message.
     407        * `msg`: A context setting message, for use in the exception message.
     408      """
     409
     410      if isinstance(intended, (tuple, list)):
     411          if actual == unspecified:
     412              return intended[0] # the default
     413          elif actual in intended:
     414              return actual
     415          else:
     416              raise ValueError(msg + ", but specifies %s=%r (must be one of %r)"\
     417                               % (name, actual, intended))
     418      else:
     419          if actual == unspecified:
     420              return intended
     421          elif actual == intended:
     422              return actual
     423          else:
     424              raise ValueError(msg + ", but specifies %s=%r (must be %r)"\
     425                               % (name, actual, intended))
     426
     427 -def cmpname(name1, name2):
     428      """
     429      Compare two CIM names.  The comparison is done
     430      case-insensitively, and one or both of the names may be `None`.
     431      """
     432
     433      if name1 is None and name2 is None:
     434          return 0
     435
     436      if name1 is None:
     437          return -1
     438
     439      if name2 is None:
     440          return 1
     441
     442      lower_name1 = name1.lower()
     443      lower_name2 = name2.lower()
     444
     445      return cmp(lower_name1, lower_name2)
     446
     447 -def _makequalifiers(qualifiers, indent):
     448      """Return a MOF fragment for a NocaseDict of qualifiers."""
     449
     450      if len(qualifiers) == 0:
     451          return ''
     452
     453      return '[%s]' % ',\n '.ljust(indent+2).\
     454          join([q.tomof(indent) for q in sorted(qualifiers.values())])
     455
     456 -def mofstr(strvalue, indent=7, maxline=80):
     457      """Converts the input string value to a MOF literal string value, including
     458      the surrounding double quotes.
     459
     460      In doing so, all characters that have MOF escape characters (except for
     461      single quotes) are escaped by adding a leading backslash (\), if not yet
     462      present. This conditional behavior is needed for WBEM servers that return
     463      the MOF escape sequences in their CIM-XML representation of any strings,
     464      instead of converting them to the binary characters as required by the CIM
     465      standards.
     466
     467      Single quotes do not need to be escaped because the returned literal
     468      string uses double quotes.
     469
     470      After escaping, the string is broken into multiple lines, for better
     471      readability. The maximum line size is specified via the ``maxline``
     472      argument. The indentation for any spilled over lines (i.e. not the first
     473      line) is specified via the ``indent`` argument.
     474      """
     475
     476      # escape \n, \r, \t, \f, \b
     477      escaped_str = strvalue.replace("\n","\\n").replace("\r","\\r").\
     478                    replace("\t","\\t").replace("\f","\\f").replace("\b","\\b")
     479
     480      # escape double quote (") if not already escaped.
     481      # TODO: Add support for two consecutive double quotes ("").
     482      escaped_str = re.sub(r'([^\\])"', r'\1\\"', escaped_str)
     483
     484      # escape special case of a single double quote (")
     485      escaped_str = re.sub(r'^"$', r'\"', escaped_str)
     486
     487      # escape backslash (\) not followed by any of: nrtfb"'
     488      escaped_str = re.sub(r'\\([^nrtfb"\'])', r'\\\1', escaped_str)
     489
     490      # escape special case of a single backslash (\)
     491      escaped_str = re.sub(r'^\\$', r'\\\\', escaped_str)
     492
     493      # Break into multiple strings for better readability
     494      blankfind = maxline - indent - 2
     495      indent_str = ' '.ljust(indent, ' ')
     496      ret_str_list = list()
     497      if escaped_str == '':
     498          ret_str_list.append('""')
     499      else:
     500          while escaped_str != '':
     501              if len(escaped_str) <= blankfind:
     502                  ret_str_list.append('"' + escaped_str + '"')
     503                  escaped_str = ''
     504              else:
     505                  splitpos = escaped_str.rfind(' ',0,blankfind)
     506                  if splitpos < 0:
     507                      splitpos = blankfind-1
     508                  ret_str_list.append('"' + escaped_str[0:splitpos+1] + '"')
     509                  escaped_str = escaped_str[splitpos+1:]
     510
     511      ret_str = ('\n'+indent_str).join(ret_str_list)
     512      return ret_str
     513
     514 -def moftype(cimtype, refclass):
     515      """Converts a CIM type name to MOF syntax."""
     516
     517      if cimtype == 'reference':
     518          _moftype = refclass + " REF"
     519      else:
     520          _moftype = cimtype
     521
     522      return _moftype
     523
     524 -class CIMClassName(object):
     525      """
     526      A CIM class path.
     527
     528      A CIM class path references a CIM class in a namespace in a WBEM server.
     529      Namespace and WBEM server may be unknown.
     530
     531      :Ivariables:
     532
     533        ...
     534          All parameters of `__init__` are set as instance variables.
     535      """
     536
     537 -    def __init__(self, classname, host=None, namespace=None):
     538          """
     539          Initialize the `CIMClassName` object.
     540
     541          :Parameters:
     542
     543            classname : `unicode` or UTF-8 encoded `str`
     544              Name of the referenced class.
     545
     546            host : `unicode` or UTF-8 encoded `str`
     547              Optional: URL of the WBEM server that contains the CIM namespace
     548              of this class path.
     549
     550              If `None`, the class path will not specify a WBEM server.
     551
     552              Default: `None`.
     553
     554            namespace : `unicode` or UTF-8 encoded `str`
     555              Optional: Name of the CIM namespace that contains the referenced
     556              class.
     557
     558              If `None`, the class path will not specify a CIM namespace.
     559
     560              Default: `None`.
     561
     562          :Raises:
     563            :raise TypeError:
     564            :raise ValueError:
     565          """
     566
     567          if not isinstance(classname, StringTypes):
     568              raise TypeError('classname argument has an invalid type: %s '\
     569                      '(expected string)' % type(classname))
     570
     571          # TODO: There are some odd restrictions on what a CIM
     572          # classname can look like (i.e must start with a
     573          # non-underscore and only one underscore per classname).
     574
     575          self.classname = classname
     576          self.host = host
     577          self.namespace = namespace
     578
     579 -    def copy(self):
     580          return CIMClassName(self.classname, host=self.host,
     581                              namespace=self.namespace)
     582
     583 -    def __cmp__(self, other):
     584
     585          if self is other:
     586              return 0
     587          elif not isinstance(other, CIMClassName):
     588              return 1
     589
     590          return (cmpname(self.classname, other.classname) or
     591                  cmpname(self.host, other.host) or
     592                  cmpname(self.namespace, other.namespace))
     593
     594 -    def __str__(self):
     595
     596          s = ''
     597
     598          if self.host is not None:
     599              s += '//%s/' % self.host
     600
     601          if self.namespace is not None:
     602              s += '%s:' % self.namespace
     603
     604          s += self.classname
     605
     606          return s
     607
     608 -    def __repr__(self):
     609
     610          r = '%s(classname=%r' % (self.__class__.__name__, self.classname)
     611
     612          if self.host is not None:
     613              r += ', host=%r' % self.host
     614
     615          if self.namespace is not None:
     616              r += ', namespace=%r' % self.namespace
     617
     618          r += ')'
     619
     620          return r
     621
     622 -    def tocimxml(self):
     623
     624          classname = cim_xml.CLASSNAME(self.classname)
     625
     626          if self.namespace is not None:
     627
     628              localnsp = cim_xml.LOCALNAMESPACEPATH(
     629                  [cim_xml.NAMESPACE(ns)
     630                   for ns in string.split(self.namespace, '/')])
     631
     632              if self.host is not None:
     633
     634                  # Classname + namespace + host = CLASSPATH
     635
     636                  return cim_xml.CLASSPATH(
     637                      cim_xml.NAMESPACEPATH(cim_xml.HOST(self.host), localnsp),
     638                      classname)
     639
     640              # Classname + namespace = LOCALCLASSPATH
     641
     642              return cim_xml.LOCALCLASSPATH(localnsp, classname)
     643
     644          # Just classname = CLASSNAME
     645
     646          return cim_xml.CLASSNAME(self.classname)
     647
     648 -class CIMProperty(object):
     649      """
     650      A CIM property.
     651
     652      The property can be used in a CIM instance (as part of a `CIMInstance`
     653      object) or in a CIM class (as part of a `CIMClass` object).
     654
     655      For properties in CIM instances:
     656
     657        * The `value` instance variable is the actual value of the property.
     658        * Qualifiers are not allowed.
     659
     660      For properties in CIM classes:
     661
     662        * The `value` instance variable is the default value for the property.
     663        * Qualifiers are allowed.
     664
     665      Scalar (=non-array) properties may have a value of NULL (= `None`), any
     666      primitive CIM type, reference type, and string type with embedded instance
     667      or embedded object.
     668
     669      Array properties may be Null or may have elements with a value of NULL, any
     670      primitive CIM type, and string type with embedded instance or embedded
     671      object. Reference types are not allowed in property arrays in CIM, as per
     672      DMTF DSP0004.
     673
     674      :Ivariables:
     675
     676        ...
     677          All parameters of `__init__` are set as instance variables.
     678      """
     679
     680 -    def __init__(self, name, value, type=None,
     681                   class_origin=None, array_size=None, propagated=None,
     682                   is_array=None, reference_class=None, qualifiers=None,
     683                   embedded_object=None):
     684          """
     685          Initialize the `CIMProperty` object.
     686
     687          This function infers optional arguments that are not specified (for
     688          example, it infers `type` from the Python type of `value` and other
     689          information). If the specified arguments are inconsistent, an
     690          exception is raised. If an optional argument is needed for some reason,
     691          an exception is raised.
     692
     693          :Parameters:
     694
     695            name : `unicode` or UTF-8 encoded `str`
     696              Name of the property. Must not be `None`.
     697
     698            value
     699              Value of the property (interpreted as actual value when the
     700              property object is used in an instance, and as default value when
     701              it is used in a class).
     702              For valid types for CIM values, see `cim_types`.
     703
     704            type : string
     705              Name of the CIM type of the property (e.g. `'uint8'`).
     706              `None` means that the argument is unspecified, causing the
     707              corresponding instance variable to be inferred. An exception is
     708              raised if it cannot be inferred.
     709
     710            class_origin : `unicode` or UTF-8 encoded `str`
     711              The CIM class origin of the property (the name
     712              of the most derived class that defines or overrides the property in
     713              the class hierarchy of the class owning the property).
     714              `None` means that class origin information is not available.
     715
     716            array_size : `int`
     717              The size of the array property, for fixed-size arrays.
     718              `None` means that the array property has variable size.
     719
     720            propagated : `unicode` or UTF-8 encoded `str`
     721              The CIM *propagated* attribute of the property (the effective value
     722              of the `Propagated` qualifier of the property, which is a string
     723              that specifies the name of the source property from which the
     724              property value should be propagated).
     725              `None` means that propagation information is not available.
     726
     727            is_array : `bool`
     728              A boolean indicating whether the property is an array (`True`) or a
     729              scalar (`False`).
     730              `None` means that the argument is unspecified, causing the
     731              corresponding instance variable to be inferred from the `value`
     732              parameter, and if that is `None` it defaults to `False` (scalar).
     733
     734            reference_class : `unicode` or UTF-8 encoded `str`
     735              The name of the referenced class, for reference properties.
     736              `None` means that the argument is unspecified, causing the
     737              corresponding instance variable  to be inferred. An exception is
     738              raised if it cannot be inferred.
     739
     740            qualifiers : `dict` or `NocaseDict`
     741              A dictionary specifying CIM qualifier values.
     742              The dictionary keys must be the qualifier names. The dictionary
     743              values must be `CIMQualifier` objects specifying the qualifier
     744              values.
     745              `None` means that there are no qualifier values. In all cases,
     746              the `qualifiers` instance variable will be a `NocaseDict` object.
     747
     748            embedded_object : string
     749              A string value indicating the kind of
     750              embedded object represented by the property value. The following
     751              values are defined for this argument:
     752              `'instance'`: The property is declared with the
     753              `EmbeddedInstance` qualifier, indicating that the property
     754              value is an embedded instance of a known class name (or Null).
     755              `'object'`: The property is declared with the
     756              `EmbeddedObject` qualifier, indicating that the property
     757              value is an embedded object (instance or class) of which the
     758              class name is not known (or Null).
     759              `None` means that the argument is unspecified, causing the
     760              corresponding instance variable to be inferred. An exception is
     761              raised if it cannot be inferred.
     762
     763          Examples:
     764
     765            * `CIMProperty("MyString", "abc")`
     766              -> a string property
     767            * `CIMProperty("MyNum", 42, "uint8")`
     768              -> a uint8 property
     769            * `CIMProperty("MyNum", Uint8(42))`
     770              -> a uint8 property
     771            * `CIMProperty("MyNumArray", [1,2,3], "uint8")`
     772              -> a uint8 array property
     773            * `CIMProperty("MyRef", CIMInstanceName(...))`
     774              -> a reference property
     775            * `CIMProperty("MyEmbObj", CIMClass(...))`
     776              -> an embedded object property containing a class
     777            * `CIMProperty("MyEmbObj", CIMInstance(...),
     778              embedded_object='object')`
     779              -> an embedded object property containing an instance
     780            * `CIMProperty("MyEmbInst", CIMInstance(...))`
     781              -> an embedded instance property
     782            * `CIMProperty("MyString", None, "string")`
     783              -> a string property that is Null
     784            * `CIMProperty("MyNum", None, "uint8")`
     785              -> a uint8 property that is Null
     786            * `CIMProperty("MyRef", None, reference_class="MyClass")`
     787              -> a reference property that is Null
     788            * `CIMProperty("MyEmbObj", None, embedded_object='object')`
     789              -> an embedded object property that is Null
     790            * `CIMProperty("MyEmbInst", None, embedded_object='instance')`
     791              -> an embedded instance property that is Null
     792
     793          :Raises:
     794            :raise TypeError:
     795            :raise ValueError:
     796          """
     797
     798          from __builtin__ import type as __type
     799
     800          # Check `name`
     801
     802          if name is None:
     803              raise ValueError('Property must have a name')
     804
     805          # General checks:
     806
     807          if embedded_object not in (None, 'instance', 'object'):
     808              raise ValueError('Property %r specifies an invalid ' \
     809                               'embedded_object=%r' % (name, embedded_object))
     810
     811          if is_array not in (None, True, False):
     812              raise ValueError('Property %r specifies an invalid ' \
     813                               'is_array=%r' % (name, is_array))
     814
     815          # Set up is_array
     816
     817          if isinstance(value, (list, tuple)):
     818              is_array = _intended_value(True,
     819                      None, is_array, 'is_array',
     820                      'Property %r has a value that is an array (%s)' % \
     821                      (name, __type(value)))
     822          elif value is not None: # Scalar value
     823              is_array = _intended_value(False,
     824                      None, is_array, 'is_array',
     825                      'Property %r has a value that is a scalar (%s)' % \
     826                      (name, __type(value)))
     827          else: # Null value
     828              if is_array is None:
     829                  is_array = False # For compatibility with old default
     830
     831          if not is_array and array_size is not None:
     832              raise ValueError('Scalar property %r specifies array_size=%r ' \
     833                               '(must be None)' % (name, array_size))
     834
     835          # Determine type, embedded_object, and reference_class attributes.
     836          # Make sure value is CIM-typed.
     837
     838          if is_array: # Array property
     839              if reference_class is not None:
     840                  raise ValueError(
     841                      'Array property %r cannot specify reference_class' % name)
     842              elif value is None or len(value) == 0 or value[0] is None:
     843                  # Cannot infer from value, look at embedded_object and type
     844                  if embedded_object == 'instance':
     845                      msg = 'Array property %r contains embedded instances' % name
     846                      type = _intended_value('string',
     847                              None, type, 'type', msg)
     848                  elif embedded_object == 'object':
     849                      msg = 'Array property %r contains embedded objects' % name
     850                      type = _intended_value('string',
     851                              None, type, 'type', msg)
     852                  elif type is not None:
     853                      # Leave type as specified, but check it for validity
     854                      dummy_type_obj = cim_types.type_from_name(type)
     855                  else:
     856                      raise ValueError(
     857                              'Cannot infer type of array property %r that is ' \
     858                              'Null, empty, or has Null as its first element' % \
     859                              name)
     860              elif isinstance(value[0], CIMInstance):
     861                  msg = 'Array property %r contains CIMInstance values' % name
     862                  type = _intended_value('string',
     863                          None, type, 'type', msg)
     864                  embedded_object = _intended_value(('instance', 'object'),
     865                          None, embedded_object, 'embedded_object', msg)
     866              elif isinstance(value[0], CIMClass):
     867                  msg = 'Array property %r contains CIMClass values' % name
     868                  type = _intended_value('string',
     869                          None, type, 'type', msg)
     870                  embedded_object = _intended_value('object',
     871                          None, embedded_object, 'embedded_object', msg)
     872              elif isinstance(value[0], (datetime, timedelta)):
     873                  value = [cim_types.CIMDateTime(val) if val is not None
     874                           else val for val in value]
     875                  msg = 'Array property %r contains datetime or timedelta ' \
     876                          'values' % name
     877                  type = _intended_value('datetime',
     878                          None, type, 'type', msg)
     879                  embedded_object = _intended_value(None,
     880                          None, embedded_object, 'embedded_object', msg)
     881              elif type == 'datetime':
     882                  value = [cim_types.CIMDateTime(val) if val is not None
     883                           and not isinstance(val, cim_types.CIMDateTime)
     884                           else val for val in value]
     885                  msg = 'Array property %r specifies CIM type %r' % (name, type)
     886                  embedded_object = _intended_value(None,
     887                         None, embedded_object, 'embedded_object', msg)
     888              elif type is None:
     889                  # Determine simple type from (non-Null) value
     890                  type = cim_types.cimtype(value[0])
     891                  msg = 'Array property %r contains simple typed values ' \
     892                          'with no CIM type specified' % name
     893                  embedded_object = _intended_value(None,
     894                          None, embedded_object, 'embedded_object', msg)
     895              else: # type is specified and value (= entire array) is not Null
     896                  # Make sure the array elements are of the corresponding Python
     897                  # type.
     898                  value = [cim_types.type_from_name(type)(val) if val is not None
     899                           else val for val in value]
     900                  msg = 'Array property %r contains simple typed values ' \
     901                          'and specifies CIM type %r' % (name, type)
     902                  embedded_object = _intended_value(None,
     903                          None, embedded_object, 'embedded_object', msg)
     904          else: # Scalar property
     905              if value is None:
     906                  # Try to infer from embedded_object, reference_class, and type
     907                  if embedded_object == 'instance':
     908                      msg = 'Property %r contains embedded instance' % name
     909                      type = _intended_value('string',
     910                              None, type, 'type', msg)
     911                      reference_class = _intended_value(None,
     912                              None, reference_class, 'reference_class', msg)
     913                  elif embedded_object == 'object':
     914                      msg = 'Property %r contains embedded object' % name
     915                      type = _intended_value('string',
     916                              None, type, 'type', msg)
     917                      reference_class = _intended_value(None,
     918                              None, reference_class, 'reference_class', msg)
     919                  elif reference_class is not None:
     920                      msg = 'Property %r is a reference' % name
     921                      embedded_object = _intended_value(None,
     922                              None, embedded_object, 'embedded_object', msg)
     923                      type = _intended_value('reference',
     924                              None, type, 'type', msg)
     925                  elif type is not None:
     926                      # Leave type as specified, but check it for validity
     927                      dummy_type_obj = cim_types.type_from_name(type)
     928                  else:
     929                      raise ValueError('Cannot infer type of simple ' \
     930                                       'property %r that is Null' % name)
     931              elif isinstance(value, CIMInstanceName):
     932                  msg = 'Property %r has a CIMInstanceName value with ' \
     933                          'classname=%r' % (name, value.classname)
     934                  reference_class = _intended_value(value.classname,
     935                          None, reference_class, 'reference_class', msg)
     936                  type = _intended_value('reference',
     937                          None, type, 'type', msg)
     938                  embedded_object = _intended_value(None,
     939                          None, embedded_object, 'embedded_object', msg)
     940              elif isinstance(value, CIMInstance):
     941                  msg = 'Property %r has a CIMInstance value' % name
     942                  type = _intended_value('string',
     943                          None, type, 'type', msg)
     944                  embedded_object = _intended_value(('instance', 'object'),
     945                          None, embedded_object, 'embedded_object', msg)
     946                  reference_class = _intended_value(None,
     947                          None, reference_class, 'reference_class', msg)
     948              elif isinstance(value, CIMClass):
     949                  msg = 'Property %r has a CIMClass value' % name
     950                  type = _intended_value('string',
     951                          None, type, 'type', msg)
     952                  embedded_object = _intended_value('object',
     953                          None, embedded_object, 'embedded_object', msg)
     954                  reference_class = _intended_value(None,
     955                          None, reference_class, 'reference_class', msg)
     956              elif isinstance(value, (datetime, timedelta)):
     957                  value = cim_types.CIMDateTime(value)
     958                  msg = 'Property %r has a datetime or timedelta value' % name
     959                  type = _intended_value('datetime',
     960                          None, type, 'type', msg)
     961                  embedded_object = _intended_value(None,
     962                          None, embedded_object, 'embedded_object', msg)
     963                  reference_class = _intended_value(None,
     964                          None, reference_class, 'reference_class', msg)
     965              elif type == 'datetime':
     966                  if not isinstance(value, cim_types.CIMDateTime):
     967                      value = cim_types.CIMDateTime(value)
     968                  msg = 'Property %r specifies CIM type %r' % (name, type)
     969                  embedded_object = _intended_value(None,
     970                          None, embedded_object, 'embedded_object', msg)
     971                  reference_class = _intended_value(None,
     972                          None, reference_class, 'reference_class', msg)
     973              elif type is None:
     974                  # Determine simple type from (non-Null) value
     975                  type = cim_types.cimtype(value)
     976                  msg = 'Property %r has a simple typed value ' \
     977                          'with no CIM type specified' % name
     978                  embedded_object = _intended_value(None,
     979                          None, embedded_object, 'embedded_object', msg)
     980                  reference_class = _intended_value(None,
     981                          None, reference_class, 'reference_class', msg)
     982              else: # type is specified and value is not Null
     983                  # Make sure the value is of the corresponding Python type.
     984                  _type_obj = cim_types.type_from_name(type)
     985                  value = _type_obj(value)
     986                  msg = 'Property %r has a simple typed value ' \
     987                          'and specifies CIM type %r' % (name, type)
     988                  embedded_object = _intended_value(None,
     989                          None, embedded_object, 'embedded_object', msg)
     990                  reference_class = _intended_value(None,
     991                          None, reference_class, 'reference_class', msg)
     992
     993          # Initialize members
     994          self.name = name
     995          self.value = value
     996          self.type = type
     997          self.class_origin = class_origin
     998          self.array_size = array_size
     999          self.propagated = propagated
    1000          self.is_array = is_array
    1001          self.reference_class = reference_class
    1002          self.qualifiers = NocaseDict(qualifiers)
    1003          self.embedded_object = embedded_object
    1004
    1005 -    def copy(self):
    1006
    1007          return CIMProperty(self.name,
    1008                             self.value,
    1009                             type=self.type,
    1010                             class_origin=self.class_origin,
    1011                             array_size=self.array_size,
    1012                             propagated=self.propagated,
    1013                             is_array=self.is_array,
    1014                             reference_class=self.reference_class,
    1015                             qualifiers=self.qualifiers.copy())
    1016
    1017 -    def __repr__(self):
    1018
    1019          return '%s(name=%r, value=%r, type=%r, class_origin=%r, ' \
    1020                 'array_size=%r, propagated=%r, is_array=%r, ' \
    1021                 'reference_class=%r, qualifiers=%r, embedded_object=%r)' % \
    1022                 (self.__class__.__name__, self.name, self.value, self.type,
    1023                  self.class_origin, self.array_size, self.propagated,
    1024                  self.is_array, self.reference_class, self.qualifiers,
    1025                  self.embedded_object)
    1026
    1027 -    def tocimxml(self):
    1028
    1029          if self.is_array:
    1030
    1031              value = self.value
    1032              if value is not None:
    1033                  if value:
    1034                      if self.embedded_object is not None:
    1035                          value = [v.tocimxml().toxml() for v in value]
    1036                  value = cim_xml.VALUE_ARRAY(
    1037                      [cim_xml.VALUE(
    1038                          cim_types.atomic_to_cim_xml(v)) for v in value])
    1039
    1040              return cim_xml.PROPERTY_ARRAY(
    1041                  self.name,
    1042                  self.type,
    1043                  value,
    1044                  self.array_size,
    1045                  self.class_origin,
    1046                  self.propagated,
    1047                  qualifiers=[q.tocimxml() for q in self.qualifiers.values()],
    1048                  embedded_object=self.embedded_object)
    1049
    1050          elif self.type == 'reference':
    1051
    1052              value_reference = None
    1053              if self.value is not None:
    1054                  value_reference = cim_xml.VALUE_REFERENCE(self.value.tocimxml())
    1055
    1056              return cim_xml.PROPERTY_REFERENCE(
    1057                  self.name,
    1058                  value_reference,
    1059                  reference_class=self.reference_class,
    1060                  class_origin=self.class_origin,
    1061                  propagated=self.propagated,
    1062                  qualifiers=[q.tocimxml() for q in self.qualifiers.values()])
    1063
    1064          else:
    1065              value = self.value
    1066              if value is not None:
    1067                  if self.embedded_object is not None:
    1068                      value = value.tocimxml().toxml()
    1069                  else:
    1070                      value = cim_types.atomic_to_cim_xml(value)
    1071                  value = cim_xml.VALUE(value)
    1072
    1073              return cim_xml.PROPERTY(
    1074                  self.name,
    1075                  self.type,
    1076                  value,
    1077                  class_origin=self.class_origin,
    1078                  propagated=self.propagated,
    1079                  qualifiers=[q.tocimxml() for q in self.qualifiers.values()],
    1080                  embedded_object=self.embedded_object)
    1081
    1082 -    def __cmp__(self, other):
    1083
    1084          if self is other:
    1085              return 0
    1086          elif not isinstance(other, self.__class__):
    1087              return 1
    1088
    1089          return (cmpname(self.name, other.name)
    1090                  or cmp(self.value, other.value)
    1091                  or cmp(self.type, other.type)
    1092                  or cmp(self.class_origin, other.class_origin)
    1093                  or cmp(self.array_size, other.array_size)
    1094                  or cmp(self.propagated, other.propagated)
    1095                  or cmp(self.qualifiers, other.qualifiers)
    1096                  or cmp(self.is_array, other.is_array)
    1097                  or cmpname(self.reference_class, other.reference_class))
    1098
    1099 -class CIMInstanceName(object):
    1100      """
    1101      A CIM instance path (aka *instance name*).
    1102
    1103      A CIM instance path references a CIM instance in a namespace in a WBEM
    1104      server.
    1105      Namespace and WBEM server may be unknown.
    1106
    1107      This object can be used like a dictionary to retrieve the key bindings.
    1108
    1109      :Ivariables:
    1110
    1111        ...
    1112          All parameters of `__init__` are set as instance variables.
    1113      """
    1114
    1115 -    def __init__(self, classname, keybindings=None, host=None, namespace=None):
    1116          """
    1117          Initialize the `CIMInstanceName` object.
    1118
    1119          :Parameters:
    1120
    1121            classname : `unicode` or UTF-8 encoded `str`
    1122              Name of the creation class of the referenced instance.
    1123
    1124            keybindings : `dict` or `NocaseDict`
    1125              Optional: Dictionary of key bindings, specifying key properties
    1126              that identify the referenced instance.
    1127              The dictionary must contain one item for each key property, where:
    1128
    1129              - its key is the property name.
    1130              - its value is the property value, as a CIM typed value as
    1131                described in `cim_types`.
    1132
    1133              If `None`, an empty dictionary of key bindings will be created.
    1134
    1135              Default: `None`.
    1136
    1137            host : `unicode` or UTF-8 encoded `str`
    1138              Optional: URL of the WBEM server that contains the CIM namespace
    1139              of this instance path.
    1140
    1141              If `None`, the instance path will not specify a WBEM server.
    1142
    1143              Default: `None`.
    1144
    1145            namespace : `unicode` or UTF-8 encoded `str`
    1146              Optional: Name of the CIM namespace that contains the referenced
    1147              instance.
    1148
    1149              If `None`, the instance path will not specify a CIM namespace.
    1150
    1151              Default: `None`.
    1152
    1153          :Raises:
    1154            :raise TypeError:
    1155            :raise ValueError:
    1156          """
    1157
    1158          if classname is None:
    1159              raise ValueError('Instance path must have a class name')
    1160
    1161          self.classname = classname
    1162          self.keybindings = NocaseDict(keybindings)
    1163          self.host = host
    1164          self.namespace = namespace
    1165
    1166 -    def copy(self):
    1167
    1168          result = CIMInstanceName(self.classname)
    1169          result.keybindings = self.keybindings.copy()
    1170          result.host = self.host
    1171          result.namespace = self.namespace
    1172
    1173          return result
    1174
    1175 -    def __cmp__(self, other):
    1176
    1177          if self is other:
    1178              return 0
    1179          elif not isinstance(other, CIMInstanceName):
    1180              return 1
    1181
    1182          return (cmpname(self.classname, other.classname) or
    1183                  cmp(self.keybindings, other.keybindings) or
    1184                  cmpname(self.host, other.host) or
    1185                  cmpname(self.namespace, other.namespace))
    1186
    1187 -    def __str__(self):
    1188
    1189          s = ''
    1190
    1191          if self.host is not None:
    1192              s += '//%s/' % self.host
    1193
    1194          if self.namespace is not None:
    1195              s += '%s:' % self.namespace
    1196
    1197          s += '%s.' % self.classname
    1198
    1199          for key, value in self.keybindings.items():
    1200
    1201              s += '%s=' % key
    1202
    1203              if isinstance(value, (int, long, bool, float)):
    1204                  s += str(value)
    1205              elif isinstance(value, CIMInstanceName):
    1206                  s += '"%s"' % str(value).replace('\\', '\\\\').replace(
    1207                      '"', '\\"')
    1208              else:
    1209                  s += '"%s"' % value
    1210
    1211              s += ','
    1212
    1213          return s[:-1]
    1214
    1215 -    def __repr__(self):
    1216
    1217          r = '%s(classname=%r, keybindings=%r' % \
    1218              (self.__class__.__name__, self.classname, self.keybindings)
    1219
    1220          if self.host is not None:
    1221              r += ', host=%r' % self.host
    1222
    1223          if self.namespace is not None:
    1224              r += ', namespace=%r' % self.namespace
    1225
    1226          r += ')'
    1227
    1228          return r
    1229
    1230      # A whole bunch of dictionary methods that map to the equivalent
    1231      # operation on self.keybindings.
    1232
    1233 -    def __getitem__(self, key): return self.keybindings[key]
    1234 -    def __contains__(self, key): return key in self.keybindings
    1235 -    def __delitem__(self, key): del self.keybindings[key]
    1236 -    def __setitem__(self, key, value): self.keybindings[key] = value
    1237 -    def __len__(self): return len(self.keybindings)
    1238 -    def has_key(self, key): return self.keybindings.has_key(key)
    1239 -    def keys(self): return self.keybindings.keys()
    1240 -    def values(self): return self.keybindings.values()
    1241 -    def items(self): return self.keybindings.items()
    1242 -    def iterkeys(self): return self.keybindings.iterkeys()
    1243 -    def itervalues(self): return self.keybindings.itervalues()
    1244 -    def iteritems(self): return self.keybindings.iteritems()
    1245 -    def update(self, *args, **kwargs): self.keybindings.update(*args, **kwargs)
    1246
    1247 -    def get(self, key, default=None):
    1248          """
    1249          Get the value of a specific key property, or the specified default
    1250          value if a key binding with that name does not exist.
    1251          """
    1252          return self.keybindings.get(key, default)
    1253
    1254 -    def tocimxml(self):
    1255          """Generate a CIM-XML representation of the instance name (class name
    1256          and key bindings)."""
    1257
    1258          if type(self.keybindings) == str:
    1259
    1260              # Class with single key string property
    1261
    1262              # This cannot happen; self.keybindings is always a NocaseDict:
    1263              # TODO: Remove this if clause after verifying that it works.
    1264              raise TypeError("Unexpected: keybindings has string type: %s" % \
    1265                              repr(self.keybindings))
    1266
    1267              instancename_xml = cim_xml.INSTANCENAME(
    1268                  self.classname,
    1269                  cim_xml.KEYVALUE(self.keybindings, 'string'))
    1270
    1271          elif isinstance(self.keybindings, (long, float, int)):
    1272
    1273              # Class with single key numeric property
    1274
    1275              # This cannot happen; self.keybindings is always a NocaseDict:
    1276              # TODO: Remove this if clause after verifying that it works.
    1277              raise TypeError("Unexpected: keybindings has numeric type: %s" % \
    1278                              repr(self.keybindings))
    1279
    1280              instancename_xml = cim_xml.INSTANCENAME(
    1281                  self.classname,
    1282                  cim_xml.KEYVALUE(str(self.keybindings), 'numeric'))
    1283
    1284          elif isinstance(self.keybindings, NocaseDict):
    1285
    1286              kbs = []
    1287
    1288              for kb in self.keybindings.items():
    1289
    1290                  # Keybindings can be integers, booleans, strings or
    1291                  # value references.
    1292
    1293                  if hasattr(kb[1], 'tocimxml'):
    1294                      kbs.append(cim_xml.KEYBINDING(
    1295                          kb[0],
    1296                          cim_xml.VALUE_REFERENCE(kb[1].tocimxml())))
    1297                      continue
    1298
    1299                  if type(kb[1]) == bool:
    1300                      _type = 'boolean'
    1301                      if kb[1]:
    1302                          value = 'TRUE'
    1303                      else:
    1304                          value = 'FALSE'
    1305                  elif isinstance(kb[1], (long, float, int)):
    1306                      # pywbem.cim_type.{Sint32, Real64, ... } derive from
    1307                      # long or float
    1308                      _type = 'numeric'
    1309                      value = str(kb[1])
    1310                  elif isinstance(kb[1], basestring):
    1311                      _type = 'string'
    1312                      value = kb[1].decode('utf-8') if isinstance(kb[1], str) \
    1313                                                    else kb[1]
    1314                  else:
    1315                      raise TypeError('Invalid keybinding type for keybinding '\
    1316                              '%s: %s' % (kb[0], type(kb[1])))
    1317
    1318                  kbs.append(cim_xml.KEYBINDING(
    1319                      kb[0],
    1320                      cim_xml.KEYVALUE(value, _type)))
    1321
    1322              instancename_xml = cim_xml.INSTANCENAME(self.classname, kbs)
    1323
    1324          else:
    1325
    1326              # Value reference
    1327
    1328              # This cannot happen; self.keybindings is always a NocaseDict:
    1329              # TODO: Remove this if clause after verifying that it works.
    1330              raise TypeError("Unexpected: keybindings has type: %s" % \
    1331                              repr(self.keybindings))
    1332
    1333              instancename_xml = cim_xml.INSTANCENAME(
    1334                  self.classname,
    1335                  cim_xml.VALUE_REFERENCE(self.keybindings.tocimxml()))
    1336
    1337          # Instance name plus namespace = LOCALINSTANCEPATH
    1338
    1339          if self.host is None and self.namespace is not None:
    1340              return cim_xml.LOCALINSTANCEPATH(
    1341                  cim_xml.LOCALNAMESPACEPATH(
    1342                      [cim_xml.NAMESPACE(ns)
    1343                       for ns in string.split(self.namespace, '/')]),
    1344                  instancename_xml)
    1345
    1346          # Instance name plus host and namespace = INSTANCEPATH
    1347
    1348          if self.host is not None and self.namespace is not None:
    1349              return cim_xml.INSTANCEPATH(
    1350                  cim_xml.NAMESPACEPATH(
    1351                      cim_xml.HOST(self.host),
    1352                      cim_xml.LOCALNAMESPACEPATH([
    1353                          cim_xml.NAMESPACE(ns)
    1354                          for ns in string.split(self.namespace, '/')])),
    1355                  instancename_xml)
    1356
    1357          # Just a regular INSTANCENAME
    1358
    1359          return instancename_xml
    1360
    1361 -class CIMInstance(object):
    1362      """
    1363      A CIM instance, optionally including its instance path.
    1364
    1365      This object can be used like a dictionary to retrieve the property values.
    1366
    1367      :Ivariables:
    1368
    1369        ...
    1370          All parameters of `__init__` are set as instance variables.
    1371      """
    1372
    1373 -    def __init__(self, classname, properties={}, qualifiers={},
    1374                   path=None, property_list=None):
    1375          """
    1376          Initialize the `CIMInstance` object.
    1377
    1378          :Parameters:
    1379
    1380            classname : `unicode` or UTF-8 encoded `str`
    1381              Name of the creation class of the instance.
    1382
    1383            properties : `dict` or `NocaseDict`
    1384              Optional: Dictionary of properties, specifying property values of
    1385              the instance.
    1386              The dictionary must contain one item for each property, where:
    1387
    1388              - its key is the property name.
    1389              - its value is a `CIMProperty` object representing the property
    1390                value.
    1391
    1392            qualifiers : `dict` or `NocaseDict`
    1393              Optional: Dictionary of qualifier values of the instance.
    1394              Note that CIM-XML has deprecated the presence of qualifier values
    1395              on CIM instances.
    1396
    1397            path : `CIMInstanceName`
    1398              Optional: Instance path of the instance.
    1399
    1400              If `None`, the instance is not addressable or the instance path is
    1401              unknown or not needed.
    1402
    1403              Default: `None`.
    1404
    1405            property_list : list of strings
    1406              Optional: List of property names for use by some operations on this
    1407              object.
    1408
    1409          :Raises:
    1410            :raise TypeError:
    1411            :raise ValueError:
    1412          """
    1413
    1414          self.classname = classname
    1415          self.qualifiers = NocaseDict(qualifiers)
    1416          # TODO: Add support for accepting qualifiers as plain dict
    1417          self.path = path
    1418          if property_list is not None:
    1419              self.property_list = [x.lower() for x in property_list]
    1420          else:
    1421              self.property_list = None
    1422
    1423          # Assign initialised property values and run through
    1424          # __setitem__ to enforce CIM types for each property.
    1425
    1426          self.properties = NocaseDict()
    1427          [self.__setitem__(k, v) for k, v in properties.items()]
    1428
    1429 -    def update(self, *args, **kwargs):
    1430          """D.update(E, **F) -> None.
    1431
    1432          Update D from E and F: for k in E: D[k] = E[k]
    1433          (if E has keys else: for (k, v) in E: D[k] = v)
    1434          then: for k in F: D[k] = F[k] """
    1435
    1436          for mapping in args:
    1437              if hasattr(mapping, 'items'):
    1438                  for k, v in mapping.items():
    1439                      self[k] = v
    1440              else:
    1441                  for (k, v) in mapping:
    1442                      self[k] = v
    1443          for k, v in kwargs.items():
    1444              self[k] = v
    1445
    1446 -    def update_existing(self, *args, **kwargs):
    1447          """Update property values iff the property previously exists.
    1448
    1449          Update D from E and F: for k in E: D[k] = E[k]
    1450          (if E has keys else: for (k, v) in E: D[k] = v)
    1451          then: for k in F: D[k] = F[k]
    1452
    1453          Like update, but properties that are not already present in the
    1454          instance are skipped. """
    1455
    1456          for mapping in args:
    1457              if hasattr(mapping, 'items'):
    1458                  for k, v in mapping.items():
    1459                      try:
    1460                          prop = self.properties[k]
    1461                      except KeyError:
    1462                          continue
    1463                      prop.value = tocimobj(prop.type, v)
    1464              else:
    1465                  for (k, v) in mapping:
    1466                      try:
    1467                          prop = self.properties[k]
    1468                      except KeyError:
    1469                          continue
    1470                      prop.value = tocimobj(prop.type, v)
    1471          for k, v in kwargs.items():
    1472              try:
    1473                  prop = self.properties[k]
    1474              except KeyError:
    1475                  continue
    1476              prop.value = tocimobj(prop.type, v)
    1477
    1478 -    def copy(self):
    1479
    1480          result = CIMInstance(self.classname)
    1481          result.properties = self.properties.copy()
    1482          result.qualifiers = self.qualifiers.copy()
    1483          result.path = (self.path is not None and \
    1484                         [self.path.copy()] or [None])[0]
    1485
    1486          return result
    1487
    1488 -    def __cmp__(self, other):
    1489
    1490          if self is other:
    1491              return 0
    1492          elif not isinstance(other, CIMInstance):
    1493              return 1
    1494
    1495          return (cmpname(self.classname, other.classname) or
    1496                  cmp(self.path, other.path) or
    1497                  cmp(self.properties, other.properties) or
    1498                  cmp(self.qualifiers, other.qualifiers))
    1499
    1500 -    def __repr__(self):
    1501          # Don't show all the properties and qualifiers because they're
    1502          # just too big
    1503          return '%s(classname=%r, path=%r, ...)' % \
    1504              (self.__class__.__name__, self.classname, self.path)
    1505
    1506      # A whole bunch of dictionary methods that map to the equivalent
    1507      # operation on self.properties.
    1508
    1509 -    def __contains__(self, key):
    1510          return key in self.properties
    1511
    1512 -    def __getitem__(self, key):
    1513          return self.properties[key].value
    1514
    1515 -    def __delitem__(self, key):
    1516          del self.properties[key]
    1517
    1518 -    def __len__(self):
    1519          return len(self.properties)
    1520
    1521 -    def has_key(self, key):
    1522          return self.properties.has_key(key)
    1523
    1524 -    def keys(self):
    1525          return self.properties.keys()
    1526
    1527 -    def values(self):
    1528          return [v.value for v in self.properties.values()]
    1529
    1530 -    def items(self):
    1531          return [(k, v.value) for k, v in self.properties.items()]
    1532
    1533 -    def iterkeys(self):
    1534          return self.properties.iterkeys()
    1535
    1536 -    def itervalues(self):
    1537          for k, v in self.properties.iteritems():
    1538              yield v.value
    1539
    1540 -    def iteritems(self):
    1541          for k, v in self.properties.iteritems():
    1542              yield (k, v.value)
    1543
    1544 -    def __setitem__(self, key, value):
    1545
    1546          # Don't let anyone set integer or float values.  You must use
    1547          # a subclass from the cim_type module.
    1548
    1549          if type(value) == int or type(value) == float or type(value) == long:
    1550              raise TypeError('Type of numeric value must be a CIM type but is '\
    1551                      '%s' % type(value))
    1552
    1553          if self.property_list is not None and key.lower() not in \
    1554                  self.property_list:
    1555              if self.path is not None and key not in self.path.keybindings:
    1556                  return
    1557          # Convert value to appropriate PyWBEM type
    1558
    1559          if isinstance(value, CIMProperty):
    1560              v = value
    1561          else:
    1562              v = CIMProperty(key, value)
    1563
    1564          self.properties[key] = v
    1565          if self.path is not None and key in self.path.keybindings:
    1566              self.path[key] = v.value
    1567
    1568 -    def get(self, key, default=None):
    1569          """
    1570          Get the value of a specific property, or the specified default
    1571          value if a property with that name does not exist.
    1572          """
    1573          prop = self.properties.get(key, None)
    1574          return default if prop is None else prop.value
    1575
    1576 -    def tocimxml(self):
    1577
    1578          props = []
    1579
    1580          for key, value in self.properties.items():
    1581
    1582              # Value has already been converted into a CIM object
    1583              # property type (e.g for creating null property values).
    1584
    1585              if isinstance(value, CIMProperty):
    1586                  props.append(value)
    1587                  continue
    1588
    1589              props.append(CIMProperty(key, value))
    1590
    1591          instance_xml = cim_xml.INSTANCE(
    1592              self.classname,
    1593              properties=[p.tocimxml() for p in props],
    1594              qualifiers=[q.tocimxml() for q in self.qualifiers.values()])
    1595
    1596          if self.path is None:
    1597              return instance_xml
    1598
    1599          return cim_xml.VALUE_NAMEDINSTANCE(self.path.tocimxml(),
    1600                                             instance_xml)
    1601
    1602 -    def tomof(self):
    1603
    1604          def _prop2mof(_type, value):
    1605              if value is None:
    1606                  val = 'NULL'
    1607              elif isinstance(value, list):
    1608                  val = '{'
    1609                  for i, x in enumerate(value):
    1610                      if i > 0:
    1611                          val += ', '
    1612                      val += _prop2mof(_type, x)
    1613                  val += '}'
    1614              elif _type == 'string':
    1615                  val = mofstr(value)
    1616              else:
    1617                  val = str(value)
    1618              return val
    1619
    1620          s = 'instance of %s {\n' % self.classname
    1621          for p in self.properties.values():
    1622              s += '\t%s = %s;\n' % (p.name, _prop2mof(p.type, p.value))
    1623          s += '};\n'
    1624
    1625          return s
    1626
    1627
    1628 -class CIMClass(object):
    1629      """
    1630      A CIM class.
    1631
    1632      :Ivariables:
    1633
    1634        ...
    1635          All parameters of `__init__` are set as instance variables.
    1636      """
    1637
    1638 -    def __init__(self, classname, properties={}, methods={},
    1639                   superclass=None, qualifiers={}):
    1640          """
    1641          Initialize the `CIMClass` object.
    1642
    1643          TODO: add description
    1644          """
    1645          self.classname = classname
    1646          self.properties = NocaseDict(properties)
    1647          self.qualifiers = NocaseDict(qualifiers)
    1648          self.methods = NocaseDict(methods)
    1649          self.superclass = superclass
    1650
    1651 -    def copy(self):
    1652
    1653          result = CIMClass(self.classname)
    1654          result.properties = self.properties.copy()
    1655          result.methods = self.methods.copy()
    1656          result.superclass = self.superclass
    1657          result.qualifiers = self.qualifiers.copy()
    1658
    1659          return result
    1660
    1661 -    def __repr__(self):
    1662          return "%s(classname=%r, ...)" % (self.__class__.__name__,
    1663                                            self.classname)
    1664
    1665 -    def __cmp__(self, other):
    1666
    1667          if self is other:
    1668              return 0
    1669          elif not isinstance(other, CIMClass):
    1670              return 1
    1671
    1672          return (cmpname(self.classname, other.classname)
    1673                  or cmpname(self.superclass, other.superclass)
    1674                  or cmp(self.properties, other.properties)
    1675                  or cmp(self.qualifiers, other.qualifiers)
    1676                  or cmp(self.methods, other.methods))
    1677
    1678 -    def tocimxml(self):
    1679          return cim_xml.CLASS(
    1680              self.classname,
    1681              properties=[p.tocimxml() for p in self.properties.values()],
    1682              methods=[m.tocimxml() for m in self.methods.values()],
    1683              qualifiers=[q.tocimxml() for q in self.qualifiers.values()],
    1684              superclass=self.superclass)
    1685
    1686 -    def tomof(self):
    1687
    1688          # Class definition
    1689
    1690          s = '   %s\n' % _makequalifiers(self.qualifiers, 4)
    1691
    1692          s += 'class %s ' % self.classname
    1693
    1694          # Superclass
    1695
    1696          if self.superclass is not None:
    1697              s += ': %s ' % self.superclass
    1698
    1699          s += '{\n'
    1700
    1701          # Properties
    1702
    1703          for p in self.properties.values():
    1704              if p.is_array and p.array_size is not None:
    1705                  array_str = "[%s]" % p.array_size
    1706              else:
    1707                  array_str = ''
    1708              s += '\n'
    1709              s += '      %s\n' % (_makequalifiers(p.qualifiers, 7))
    1710              s += '   %s %s%s;\n' % (moftype(p.type, p.reference_class),
    1711                                      p.name, array_str)
    1712
    1713          # Methods
    1714
    1715          for m in self.methods.values():
    1716              s += '\n'
    1717              s += '   %s\n' % m.tomof()
    1718
    1719          s += '};\n'
    1720
    1721          return s
    1722
    1723 -class CIMMethod(object):
    1724      """
    1725      A CIM method.
    1726
    1727      :Ivariables:
    1728
    1729        ...
    1730          All parameters of `__init__` are set as instance variables.
    1731      """
    1732
    1733 -    def __init__(self, methodname, return_type=None, parameters={},
    1734                   class_origin=None, propagated=False, qualifiers={}):
    1735          """
    1736          Initialize the `CIMMethod` object.
    1737
    1738          TODO: add description
    1739          """
    1740          self.name = methodname
    1741          self.return_type = return_type
    1742          self.parameters = NocaseDict(parameters)
    1743          self.class_origin = class_origin
    1744          self.propagated = propagated
    1745          self.qualifiers = NocaseDict(qualifiers)
    1746
    1747 -    def copy(self):
    1748
    1749          result = CIMMethod(self.name,
    1750                             return_type=self.return_type,
    1751                             class_origin=self.class_origin,
    1752                             propagated=self.propagated)
    1753
    1754          result.parameters = self.parameters.copy()
    1755          result.qualifiers = self.qualifiers.copy()
    1756
    1757          return result
    1758
    1759 -    def tocimxml(self):
    1760          return cim_xml.METHOD(
    1761              self.name,
    1762              parameters=[p.tocimxml() for p in self.parameters.values()],
    1763              return_type=self.return_type,
    1764              class_origin=self.class_origin,
    1765              propagated=self.propagated,
    1766              qualifiers=[q.tocimxml() for q in self.qualifiers.values()])
    1767
    1768 -    def __repr__(self):
    1769          return '%s(name=%r, return_type=%r, ...)' % \
    1770                 (self.__class__.__name__, self.name, self.return_type)
    1771
    1772 -    def __cmp__(self, other):
    1773
    1774          if self is other:
    1775              return 0
    1776          elif not isinstance(other, CIMMethod):
    1777              return 1
    1778
    1779          return (cmpname(self.name, other.name) or
    1780                  cmp(self.parameters, other.parameters) or
    1781                  cmp(self.qualifiers, other.qualifiers) or
    1782                  cmp(self.class_origin, other.class_origin) or
    1783                  cmp(self.propagated, other.propagated) or
    1784                  cmp(self.return_type, other.return_type))
    1785
    1786 -    def tomof(self):
    1787
    1788          s = ''
    1789
    1790          s += '      %s\n' % (_makequalifiers(self.qualifiers, 7))
    1791
    1792          if self.return_type is not None:
    1793              s += '%s ' % moftype(self.return_type, None)
    1794              # CIM-XML does not support methods returning reference types
    1795              # (the CIM architecture does).
    1796
    1797          s += '%s(\n' % (self.name)
    1798          s += string.join(
    1799              ['       '+p.tomof() for p in self.parameters.values()], ',\n')
    1800          s += ');\n'
    1801
    1802          return s
    1803
    1804 -class CIMParameter(object):
    1805      """
    1806      A CIM parameter.
    1807
    1808      :Ivariables:
    1809
    1810        ...
    1811          All parameters of `__init__` are set as instance variables.
    1812      """
    1813
    1814 -    def __init__(self, name, type, reference_class=None, is_array=None,
    1815                   array_size=None, qualifiers={}, value=None):
    1816          """
    1817          Initialize the `CIMParameter` object.
    1818
    1819          TODO: add description
    1820          """
    1821          self.name = name
    1822          self.type = type
    1823          self.reference_class = reference_class
    1824          self.is_array = is_array
    1825          self.array_size = array_size
    1826          self.qualifiers = NocaseDict(qualifiers)
    1827          self.value = value
    1828
    1829 -    def copy(self):
    1830
    1831          result = CIMParameter(self.name,
    1832                                self.type,
    1833                                reference_class=self.reference_class,
    1834                                is_array=self.is_array,
    1835                                array_size=self.array_size,
    1836                                value=self.value)
    1837
    1838          result.qualifiers = self.qualifiers.copy()
    1839
    1840          return result
    1841
    1842 -    def __repr__(self):
    1843
    1844          return '%s(name=%r, type=%r, reference_class=%r, is_array=%r, ...)' % \
    1845                 (self.__class__.__name__, self.name, self.type,
    1846                  self.reference_class, self.is_array)
    1847
    1848 -    def __cmp__(self, other):
    1849
    1850          if self is other:
    1851              return 0
    1852          elif not isinstance(other, self.__class__):
    1853              return 1
    1854
    1855          return (cmpname(self.name, other.name) or
    1856                  cmp(self.type, other.type) or
    1857                  cmpname(self.reference_class, other.reference_class) or
    1858                  cmp(self.is_array, other.is_array) or
    1859                  cmp(self.array_size, other.array_size) or
    1860                  cmp(self.qualifiers, other.qualifiers) or
    1861                  cmp(self.value, other.value))
    1862
    1863 -    def tocimxml(self):
    1864
    1865          if self.type == 'reference':
    1866
    1867              if self.is_array:
    1868
    1869                  array_size = None
    1870
    1871                  if self.array_size is not None:
    1872                      array_size = str(self.array_size)
    1873
    1874                  return cim_xml.PARAMETER_REFARRAY(
    1875                      self.name,
    1876                      self.reference_class,
    1877                      array_size,
    1878                      qualifiers=[q.tocimxml()
    1879                                  for q in self.qualifiers.values()])
    1880
    1881              else:
    1882
    1883                  return cim_xml.PARAMETER_REFERENCE(
    1884                      self.name,
    1885                      self.reference_class,
    1886                      qualifiers=[q.tocimxml()
    1887                                  for q in self.qualifiers.values()])
    1888
    1889          elif self.is_array:
    1890
    1891              array_size = None
    1892
    1893              if self.array_size is not None:
    1894                  array_size = str(self.array_size)
    1895
    1896              return cim_xml.PARAMETER_ARRAY(
    1897                  self.name,
    1898                  self.type,
    1899                  array_size,
    1900                  qualifiers=[q.tocimxml() for q in self.qualifiers.values()])
    1901
    1902          else:
    1903
    1904              return cim_xml.PARAMETER(
    1905                  self.name,
    1906                  self.type,
    1907                  qualifiers=[q.tocimxml() for q in self.qualifiers.values()])
    1908
    1909 -    def tomof(self):
    1910          if self.is_array and self.array_size is not None:
    1911              array_str = "[%s]" % self.array_size
    1912          else:
    1913              array_str = ''
    1914          s = '\n'
    1915          s += '         %s\n' % (_makequalifiers(self.qualifiers, 10))
    1916          s += '      %s %s%s' % (moftype(self.type, self.reference_class),
    1917                                  self.name, array_str)
    1918          return s
    1919
    1920 -class CIMQualifier(object):
    1921      """
    1922      A CIM qualifier value.
    1923
    1924      A qualifier represents metadata on a class, method, property, etc., and
    1925      specifies information such as a documentation string or whether a property
    1926      is a key.
    1927
    1928      :Ivariables:
    1929
    1930        ...
    1931          All parameters of `__init__` are set as instance variables.
    1932      """
    1933
    1934 -    def __init__(self, name, value, type=None, propagated=None,
    1935                   overridable=None, tosubclass=None, toinstance=None,
    1936                   translatable=None):
    1937          """
    1938          Initialize the `CIMQualifier` object.
    1939
    1940          TODO: add description
    1941          """
    1942          self.name = name
    1943          self.type = type
    1944          self.propagated = propagated
    1945          self.overridable = overridable
    1946          self.tosubclass = tosubclass
    1947          self.toinstance = toinstance
    1948          self.translatable = translatable
    1949
    1950          # Determine type of value if not specified
    1951
    1952          import __builtin__
    1953
    1954          if type is None:
    1955
    1956              # Can't work out what is going on if type and value are
    1957              # both not set.
    1958
    1959              if value is None:
    1960                  raise TypeError('Null qualifier "%s" must have a type' % name)
    1961
    1962              if __builtin__.type(value) == list:
    1963
    1964                  # Determine type for list value
    1965
    1966                  if len(value) == 0:
    1967                      raise TypeError('Empty qualifier array "%s" must have a '\
    1968                              'type' % name)
    1969
    1970                  self.type = cim_types.cimtype(value[0])
    1971
    1972              else:
    1973
    1974                  # Determine type for regular value
    1975
    1976                  self.type = cim_types.cimtype(value)
    1977
    1978          # Don't let anyone set integer or float values.  You must use
    1979          # a subclass from the cim_type module.
    1980
    1981          if __builtin__.type(value) in (int, float, long):
    1982              raise TypeError('Must use a CIM type for numeric qualifiers.')
    1983
    1984          self.value = value
    1985
    1986 -    def copy(self):
    1987
    1988          return CIMQualifier(self.name,
    1989                              self.value,
    1990                              type=self.type,
    1991                              propagated=self.propagated,
    1992                              overridable=self.overridable,
    1993                              tosubclass=self.tosubclass,
    1994                              toinstance=self.toinstance,
    1995                              translatable=self.translatable)
    1996
    1997 -    def __repr__(self):
    1998          return "%s(name=%r, value=%r, type=%r, ...)" % \
    1999                 (self.__class__.__name__, self.name, self.value, self.type)
    2000
    2001 -    def __cmp__(self, other):
    2002
    2003          if self is other:
    2004              return 0
    2005          elif not isinstance(other, CIMQualifier):
    2006              return 1
    2007
    2008          return (cmpname(self.name, other.name) or
    2009                  cmp(self.value, other.value) or
    2010                  cmp(self.type, other.type) or
    2011                  cmp(self.propagated, other.propagated) or
    2012                  cmp(self.overridable, other.overridable) or
    2013                  cmp(self.tosubclass, other.tosubclass) or
    2014                  cmp(self.toinstance, other.toinstance) or
    2015                  cmp(self.translatable, other.translatable))
    2016
    2017 -    def tocimxml(self):
    2018
    2019          value = None
    2020
    2021          if type(self.value) == list:
    2022              value = cim_xml.VALUE_ARRAY([cim_xml.VALUE(v) for v in self.value])
    2023          elif self.value is not None:
    2024              value = cim_xml.VALUE(self.value)
    2025
    2026          return cim_xml.QUALIFIER(self.name,
    2027                                   self.type,
    2028                                   value,
    2029                                   propagated=self.propagated,
    2030                                   overridable=self.overridable,
    2031                                   tosubclass=self.tosubclass,
    2032                                   toinstance=self.toinstance,
    2033                                   translatable=self.translatable)
    2034
    2035 -    def tomof(self, indent=7):
    2036
    2037          def valstr(v):
    2038              if isinstance(v, basestring):
    2039                  return mofstr(v, indent)
    2040              return str(v)
    2041
    2042          if type(self.value) == list:
    2043              return '%s {' % self.name + \
    2044                     ', '.join([valstr(v) for v in self.value]) + '}'
    2045
    2046          return '%s (%s)' % (self.name, valstr(self.value))
    2047
    2048 -class CIMQualifierDeclaration(object):
    2049      """
    2050      A CIM qualifier type.
    2051
    2052      A qualifier type is the declaration of a qualifier.
    2053
    2054      :Ivariables:
    2055
    2056        ...
    2057          All parameters of `__init__` are set as instance variables.
    2058      """
    2059
    2060      # TODO: Scope and qualifier flavors
    2061
    2062 -    def __init__(self, name, type, value=None, is_array=False,
    2063                   array_size=None, scopes={},
    2064                   overridable=None, tosubclass=None, toinstance=None,
    2065                   translatable=None):
    2066          """
    2067          Initialize the `CIMQualifierDeclaration` object.
    2068
    2069          TODO: add description
    2070          """
    2071          self.name = name
    2072          self.type = type
    2073          self.value = value
    2074          self.is_array = is_array
    2075          self.array_size = array_size
    2076          self.scopes = NocaseDict(scopes)
    2077          self.overridable = overridable
    2078          self.tosubclass = tosubclass
    2079          self.toinstance = toinstance
    2080          self.translatable = translatable
    2081
    2082 -    def copy(self):
    2083
    2084          return CIMQualifierDeclaration(self.name,
    2085                                         self.type,
    2086                                         value=self.value,
    2087                                         is_array=self.is_array,
    2088                                         array_size=self.array_size,
    2089                                         scopes=self.scopes,
    2090                                         overridable=self.overridable,
    2091                                         tosubclass=self.tosubclass,
    2092                                         toinstance=self.toinstance,
    2093                                         translatable=self.translatable)
    2094
    2095 -    def __repr__(self):
    2096          return "%s(name=%r, type=%r, is_array=%r, ...)" % \
    2097              (self.__class__.__name__, self.name, self.type, self.is_array)
    2098
    2099 -    def __cmp__(self, other):
    2100
    2101          if self is other:
    2102              return 0
    2103          elif not isinstance(other, CIMQualifierDeclaration):
    2104              return 1
    2105
    2106          return (cmpname(self.name, other.name) or
    2107                  cmp(self.type, other.type) or
    2108                  cmp(self.value, other.value) or
    2109                  cmp(self.is_array, other.is_array) or
    2110                  cmp(self.array_size, other.array_size) or
    2111                  cmp(self.scopes, other.scopes) or
    2112                  cmp(self.overridable, other.overridable) or
    2113                  cmp(self.tosubclass, other.tosubclass) or
    2114                  cmp(self.toinstance, other.toinstance) or
    2115                  cmp(self.translatable, other.translatable))
    2116
    2117 -    def tocimxml(self):
    2118
    2119          return cim_xml.QUALIFIER_DECLARATION(self.name,
    2120                                               self.type,
    2121                                               self.value,
    2122                                               is_array=self.is_array,
    2123                                               array_size=self.array_size,
    2124                                               qualifier_scopes=self.scopes,
    2125                                               overridable=self.overridable,
    2126                                               tosubclass=self.tosubclass,
    2127                                               toinstance=self.toinstance,
    2128                                               translatable=self.translatable)
    2129
    2130 -    def tomof(self):
    2131          mof = 'Qualifier %s : %s' % (self.name, self.type)
    2132          if self.is_array:
    2133              mof += '['
    2134              if self.array_size is not None:
    2135                  mof += str(self.array_size)
    2136              mof += ']'
    2137          if self.value is not None:
    2138              if isinstance(self.value, list):
    2139                  mof += ' = {'
    2140                  mof += ', '.join([cim_types.atomic_to_cim_xml(
    2141                      tocimobj(self.type, x)) for x in self.value])
    2142                  mof += '}'
    2143              else:
    2144                  mof += ' = %s' % cim_types.atomic_to_cim_xml(
    2145                      tocimobj(self.type, self.value))
    2146          mof += ',\n    '
    2147          mof += 'Scope('
    2148          mof += ', '.join([x.lower() for x, y in self.scopes.items() if y]) + ')'
    2149          if not self.overridable and not self.tosubclass \
    2150                  and not self.toinstance and not self.translatable:
    2151              mof += ';'
    2152              return mof
    2153          mof += ',\n    Flavor('
    2154          mof += self.overridable and 'EnableOverride' or 'DisableOverride'
    2155          mof += ', '
    2156          mof += self.tosubclass and 'ToSubclass' or 'Restricted'
    2157          if self.toinstance:
    2158              mof += ', ToInstance'
    2159          if self.translatable:
    2160              mof += ', Translatable'
    2161          mof += ');'
    2162          return mof
    2163
    2164 -def tocimxml(value):
    2165      """Convert an arbitrary object to CIM xml.  Works with cim_obj
    2166      objects and builtin types."""
    2167
    2168      # Python cim_obj object
    2169
    2170      if hasattr(value, 'tocimxml'):
    2171          return value.tocimxml()
    2172
    2173      # CIMType or builtin type
    2174
    2175      if isinstance(value, (cim_types.CIMType, unicode, int)):
    2176          return cim_xml.VALUE(unicode(value))
    2177
    2178      if isinstance(value, str):
    2179          return cim_xml.VALUE(value.decode('utf-8'))
    2180
    2181      if isinstance(value, bool):
    2182          if value:
    2183              return cim_xml.VALUE('TRUE')
    2184          else:
    2185              return cim_xml.VALUE('FALSE')
    2186
    2187      # List of values
    2188
    2189      if type(value) == list:
    2190          return cim_xml.VALUE_ARRAY(map(tocimxml, value))
    2191
    2192      raise ValueError("Can't convert %s (%s) to CIM XML" % (value, type(value)))
    2193
    2194
    2195 -def tocimobj(_type, value):
    2196      """Convert a CIM type and a string value into an appropriate
    2197      builtin type."""
    2198
    2199      if value is None or _type is None:
    2200          return None
    2201
    2202      if _type != 'string' and isinstance(value, basestring) and not value:
    2203          return None
    2204
    2205      # Lists of values
    2206
    2207      if type(value) == list:
    2208          return map(lambda x: tocimobj(_type, x), value)
    2209
    2210      # Boolean type
    2211
    2212      if _type == 'boolean':
    2213          if isinstance(value, bool):
    2214              return value
    2215          elif isinstance(value, basestring):
    2216              if value.lower() == 'true':
    2217                  return True
    2218              elif value.lower() == 'false':
    2219                  return False
    2220          raise ValueError('Invalid boolean value: "%s"' % value)
    2221
    2222      # String type
    2223
    2224      if _type == 'string':
    2225          return value
    2226
    2227      # Integer types
    2228
    2229      if _type == 'uint8':
    2230          return cim_types.Uint8(value)
    2231
    2232      if _type == 'sint8':
    2233          return cim_types.Sint8(value)
    2234
    2235      if _type == 'uint16':
    2236          return cim_types.Uint16(value)
    2237
    2238      if _type == 'sint16':
    2239          return cim_types.Sint16(value)
    2240
    2241      if _type == 'uint32':
    2242          return cim_types.Uint32(value)
    2243
    2244      if _type == 'sint32':
    2245          return cim_types.Sint32(value)
    2246
    2247      if _type == 'uint64':
    2248          return cim_types.Uint64(value)
    2249
    2250      if _type == 'sint64':
    2251          return cim_types.Sint64(value)
    2252
    2253      # Real types
    2254
    2255      if _type == 'real32':
    2256          return cim_types.Real32(value)
    2257
    2258      if _type == 'real64':
    2259          return cim_types.Real64(value)
    2260
    2261      # Char16
    2262
    2263      if _type == 'char16':
    2264          raise ValueError('CIMType char16 not handled')
    2265
    2266      # Datetime
    2267
    2268      if _type == 'datetime':
    2269          return cim_types.CIMDateTime(value)
    2270
    2271      # REF
    2272      def partition(s, seq):
    2273          """ S.partition(sep) -> (head, sep, tail)
    2274
    2275          Searches for the separator sep in S, and returns the part before it,
    2276          the separator itself, and the part after it.  If the separator is not
    2277          found, returns S and two empty strings.
    2278          """
    2279          try:
    2280              return s.partition(seq)
    2281          except AttributeError:
    2282              try:
    2283                  idx = s.index(seq)
    2284              except ValueError:
    2285                  return (s, '', '')
    2286              return (s[:idx], seq, s[idx+len(seq):])
    2287
    2288      if _type == 'reference':
    2289          # TODO doesn't handle double-quoting, as in refs to refs.  Example:
    2290          # r'ex_composedof.composer="ex_sampleClass.label1=9921,' +
    2291          #  'label2=\"SampleLabel\"",component="ex_sampleClass.label1=0121,' +
    2292          #  'label2=\"Component\""')
    2293          if isinstance(value, (CIMInstanceName, CIMClassName)):
    2294              return value
    2295          elif isinstance(value, basestring):
    2296              ns = host = None
    2297              head, sep, tail = partition(value, '//')
    2298              if sep and head.find('"') == -1:
    2299                  # we have a namespace type
    2300                  head, sep, tail = partition(tail, '/')
    2301                  host = head
    2302              else:
    2303                  tail = head
    2304              head, sep, tail = partition(tail, ':')
    2305              if sep:
    2306                  ns = head
    2307              else:
    2308                  tail = head
    2309              head, sep, tail = partition(tail, '.')
    2310              if not sep:
    2311                  return CIMClassName(head, host=host, namespace=ns)
    2312              classname = head
    2313              kb = {}
    2314              while tail:
    2315                  head, sep, tail = partition(tail, ',')
    2316                  if head.count('"') == 1: # quoted string contains comma
    2317                      tmp, sep, tail = partition(tail, '"')
    2318                      head = '%s,%s' % (head, tmp)
    2319                      tail = partition(tail, ',')[2]
    2320                  head = head.strip()
    2321                  key, sep, val = partition(head, '=')
    2322                  if sep:
    2323                      cn, s, k = partition(key, '.')
    2324                      if s:
    2325                          if cn != classname:
    2326                              raise ValueError('Invalid object path: "%s"' % \
    2327                                               value)
    2328                          key = k
    2329                      val = val.strip()
    2330                      if val[0] == '"' and val[-1] == '"':
    2331                          val = val.strip('"')
    2332                      else:
    2333                          if val.lower() in ('true', 'false'):
    2334                              val = val.lower() == 'true'
    2335                          elif val.isdigit():
    2336                              val = int(val)
    2337                          else:
    2338                              try:
    2339                                  val = float(val)
    2340                              except ValueError:
    2341                                  try:
    2342                                      val = cim_types.CIMDateTime(val)
    2343                                  except ValueError:
    2344                                      raise ValueError('Invalid key binding: %s'\
    2345                                              % val)
    2346
    2347
    2348                      kb[key] = val
    2349              return CIMInstanceName(classname, host=host, namespace=ns,
    2350                                     keybindings=kb)
    2351          else:
    2352              raise ValueError('Invalid reference value: "%s"' % value)
    2353
    2354      raise ValueError('Invalid CIM type: "%s"' % _type)
    2355
    2356
    2357 -def byname(nlist):
    2358      """Convert a list of named objects into a map indexed by name"""
    2359      return dict([(x.name, x) for x in nlist])
    2360