This list is closed, nobody may subscribe to it.
| 2014 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
(1) |
Dec
|
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 2015 |
Jan
(40) |
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
(14) |
Dec
|
|
From: <ma...@us...> - 2015-01-21 18:29:03
|
Revision: 719
http://sourceforge.net/p/pywbem/code/719
Author: maiera
Date: 2015-01-21 18:29:01 +0000 (Wed, 21 Jan 2015)
Log Message:
-----------
Addition to fix for bug 32: Moved check for invalid utf-8 and xml characters into error path, to make the good path faster. Changed exceptions that are raised, by using pywbem.ParseError instead of CIMError(0,..)
Modified Paths:
--------------
pywbem/trunk/pywbem/cim_operations.py
pywbem/trunk/testsuite/test_cim_operations.py
Modified: pywbem/trunk/pywbem/cim_operations.py
===================================================================
--- pywbem/trunk/pywbem/cim_operations.py 2015-01-21 16:48:36 UTC (rev 718)
+++ pywbem/trunk/pywbem/cim_operations.py 2015-01-21 18:29:01 UTC (rev 719)
@@ -36,12 +36,13 @@
from types import StringTypes
from xml.dom import minidom
from datetime import datetime, timedelta
+from xml.parsers.expat import ExpatError
from pywbem import cim_obj, cim_xml, cim_http, cim_types, tupletree, tupleparse
from pywbem.cim_obj import CIMInstance, CIMInstanceName, CIMClass, \
CIMClassName, NocaseDict
-__all__ = ['DEFAULT_NAMESPACE', 'CharError', 'check_utf8_xml_chars',
+__all__ = ['DEFAULT_NAMESPACE', 'check_utf8_xml_chars',
'CIMError', 'WBEMConnection', 'is_subclass',
'PegasusUDSConnection', 'SFCBUDSConnection',
'OpenWBEMUDSConnection']
@@ -70,21 +71,12 @@
if not isinstance(val, StringTypes):
raise ValueError("string expected for classname, not %s" % `val`)
-class CharError(Exception):
- """Raised when the `check_utf8_xml_chars()` function finds an invalid UTF-8
- Byte sequence, or a valid Unicode character that cannot be represented in
- XML.
-
- The value is a string describing the error.
- """
-
- pass
-
def check_utf8_xml_chars(utf8_xml, meaning):
"""
- Examine a UTF-8 encoded XML string and raise a `CharError` exception if
- the response contains Bytes that are invalid UTF-8 sequences (incorrectly
- encoded or ill-formed) or that are invalid XML characters.
+ Examine a UTF-8 encoded XML string and raise a `pywbem.ParseError`
+ exception if the response contains Bytes that are invalid UTF-8
+ sequences (incorrectly encoded or ill-formed) or that are invalid XML
+ characters.
This function works in both "wide" and "narrow" Unicode builds of Python
and supports the full range of Unicode characters from U+0000 to U+10FFFF.
@@ -92,7 +84,7 @@
This function is just a workaround for the bad error handling of Python's
`xml.dom.minidom` package. It replaces the not very informative
`ExpatError` "not well-formed (invalid token): line: x, column: y" with a
- `CharError` providing more useful information.
+ `pywbem.ParseError` providing more useful information.
:Parameters:
@@ -104,10 +96,9 @@
:Exceptions:
- `TypeError`, if invoked with incorrect Python object type for
- `utf8_xml`.
+ `TypeError`, if invoked with incorrect Python object type for `utf8_xml`.
- `CharError`, if `utf8_xml` contains Bytes that are invalid UTF-8
+ `pywbem.ParseError`, if `utf8_xml` contains Bytes that are invalid UTF-8
sequences (incorrectly encoded or ill-formed) or invalid XML characters.
Notes on Unicode support in Python:
@@ -137,9 +128,9 @@
code points is ill-formed, but it is technically possible that such a
sequence is in a UTF-8 encoded XML string.
- (3) The Python escapes \\u and \\U used in literal strings can represent
- the surrogate code points (as well as all other code points, regardless
- of whether they are assigned to Unicode characters).
+ (3) The Python escapes ``\\u`` and ``\\U`` used in literal strings can
+ represent the surrogate code points (as well as all other code points,
+ regardless of whether they are assigned to Unicode characters).
(4) The Python `str.encode()` and `str.decode()` functions successfully
translate the surrogate code points back and forth for encoding UTF-8.
@@ -190,18 +181,16 @@
ic_seq = m.group(1)
ic_list.append((ic_pos,ic_seq))
if len(ic_list) > 0:
- exc_txt = "Ill-formed UTF-8 Byte sequences found in %s:" % meaning
+ exc_txt = "Ill-formed (surrogate) UTF-8 Byte sequences found in %s:" %\
+ meaning
for (ic_pos,ic_seq) in ic_list:
exc_txt += "\n At offset %d:" % ic_pos
for c in ic_seq:
exc_txt += " 0x%02X" % ord(c)
cpos1 = max(ic_pos-context_before,0)
cpos2 = min(ic_pos+context_after,len(utf8_xml))
- context = utf8_xml[cpos1:cpos2]
- exc_txt += ", context(-%d,+%d): %s" % (context_before,
- context_after,
- repr(context))
- raise CharError(exc_txt)
+ exc_txt += ", CIM-XML snippet: %r" % utf8_xml[cpos1:cpos2]
+ raise tupleparse.ParseError(exc_txt)
# Check for incorrectly encoded UTF-8 sequences.
# @ibm.13@ Simplified logic (removed loop).
@@ -215,17 +204,15 @@
# information about the first one is returned in the exception object.
# Also, the stated reason (in _msg) is not always correct.
_codec, _str, _p1, _p2, _msg = exc.args
- exc_txt = "Invalid UTF-8 Byte sequences found in %s" % meaning
+ exc_txt = "Incorrectly encoded UTF-8 Byte sequences found in %s" %\
+ meaning
exc_txt += "\n At offset %d:" % _p1
for c in utf8_xml[_p1:_p2+1]:
exc_txt += " 0x%02X" % ord(c)
cpos1 = max(_p1-context_before,0)
cpos2 = min(_p2+context_after,len(utf8_xml))
- context = utf8_xml[cpos1:cpos2]
- exc_txt += ", context(-%d,+%d): %s" % (context_before,
- context_after,
- repr(context))
- raise CharError(exc_txt)
+ exc_txt += ", CIM-XML snippet: %r" % utf8_xml[cpos1:cpos2]
+ raise tupleparse.ParseError(exc_txt)
# Now we know the Unicode characters are valid.
# Check for Unicode characters that cannot legally be represented as XML
@@ -243,11 +230,9 @@
for (ic_pos,ic_char) in ic_list:
cpos1 = max(ic_pos-context_before,0)
cpos2 = min(ic_pos+context_after,len(utf8_xml_u))
- context_u = utf8_xml_u[cpos1:cpos2]
- exc_txt += "\n At offset %d: U+%04X, context(-%d,+%d): %s" % \
- (ic_pos, ord(ic_char), context_before, context_after,
- repr(context_u))
- raise CharError(exc_txt)
+ exc_txt += "\n At offset %d: U+%04X, CIM-XML snippet: %r" % \
+ (ic_pos, ord(ic_char), utf8_xml_u[cpos1:cpos2])
+ raise tupleparse.ParseError(exc_txt)
return utf8_xml
@@ -334,11 +319,16 @@
For the possible CIM errors that can be returned by each operation, see
DMTF DSP0200.
- - `pywbem.ParseError` - CIM-XML validation problem in the response from
- the WBEM server.
+ - `pywbem.ParseError` - CIM-XML parsing problem in the response from
+ the WBEM server. The exception message provides details.
+ Possible reasons are:
- - `xml.parsers.expat.ExpatError` - XML error in the response from the
- WBEM server, such as ill-formed XML or illegal XML characters.
+ * Response contains ill-formed UTF-8 Byte sequences (uses surrogates).
+ * Response contains incorrectly encoded UTF-8 Byte sequences.
+ * Response contains invalid XML characters (e.g. ``\\x00`` or
+ ``�``).
+ * Response is not well-formed XML.
+ * Response does not validate against the CIM-XML DTD/schema.
* Exceptions indicating programming errors in PyWBEM or layers below:
@@ -594,7 +584,7 @@
# Get XML response
try:
- resp_xml = cim_http.wbem_request(
+ reply_xml = cim_http.wbem_request(
self.url, req_xml.toxml(), self.creds, headers,
x509=self.x509,
verify_callback=self.verify_callback,
@@ -609,13 +599,23 @@
## TODO: Perhaps only compute this if it's required? Should not be
## all that expensive.
- # Set the raw response before parsing and checking (which can fail)
+ # Set the raw response before parsing (which can fail)
if self.debug:
- self.last_raw_reply = resp_xml
+ self.last_raw_reply = reply_xml
- check_utf8_xml_chars(resp_xml, "CIM-XML response")
+ try:
+ reply_dom = minidom.parseString(reply_xml)
+ except ExpatError:
+ parsing_error = True
+ else:
+ parsing_error = False
- reply_dom = minidom.parseString(resp_xml)
+ if parsing_error or self.debug:
+ # Here we just improve the quality of the exception information,
+ # so we do this only if it already has failed. Because the check
+ # function we invoke catches more errors than minidom.parseString,
+ # we call it also when debug is turned on.
+ check_utf8_xml_chars(reply_xml, "CIM-XML response")
if self.debug:
self.last_reply = reply_dom.toprettyxml(indent=' ')
@@ -780,7 +780,7 @@
# Get XML response
try:
- resp_xml = cim_http.wbem_request(
+ reply_xml = cim_http.wbem_request(
self.url, req_xml.toxml(), self.creds, headers,
x509=self.x509,
verify_callback=self.verify_callback,
@@ -792,16 +792,29 @@
# Set the raw response before parsing and checking (which can fail)
if self.debug:
- self.last_raw_reply = resp_xml
+ self.last_raw_reply = reply_xml
- check_utf8_xml_chars(resp_xml, "CIM-XML response")
+ try:
+ reply_dom = minidom.parseString(reply_xml)
+ except ExpatError:
+ parsing_error = True
+ else:
+ parsing_error = False
+ if parsing_error or self.debug:
+ # Here we just improve the quality of the exception information,
+ # so we do this only if it already has failed. Because the check
+ # function we invoke catches more errors than minidom.parseString,
+ # we call it also when debug is turned on.
+ check_utf8_xml_chars(reply_xml, "CIM-XML response")
+
if self.debug:
- resp_dom = minidom.parseString(resp_xml)
- self.last_reply = resp_dom.toprettyxml(indent=' ')
+ self.last_reply = reply_dom.toprettyxml(indent=' ')
- tt = tupleparse.parse_cim(tupletree.xml_to_tupletree(resp_xml))
+ # Parse response
+ tt = tupleparse.parse_cim(tupletree.dom_to_tupletree(reply_dom))
+
if tt[0] != 'CIM':
raise CIMError(0, 'Expecting CIM element, got %s' % tt[0])
tt = tt[2]
Modified: pywbem/trunk/testsuite/test_cim_operations.py
===================================================================
--- pywbem/trunk/testsuite/test_cim_operations.py 2015-01-21 16:48:36 UTC (rev 718)
+++ pywbem/trunk/testsuite/test_cim_operations.py 2015-01-21 18:29:01 UTC (rev 719)
@@ -16,11 +16,10 @@
WBEMConnection, CIMError, \
Uint8, Uint16, Uint32, Uint64, \
Sint8, Sint16, Sint32, Sint64, \
- Real32, Real64, CIMDateTime
+ Real32, Real64, CIMDateTime, ParseError
+from pywbem.cim_operations import DEFAULT_NAMESPACE, check_utf8_xml_chars
from comfychair import main, TestCase, NotRunError
-from pywbem.cim_operations import DEFAULT_NAMESPACE, check_utf8_xml_chars, \
- CharError
# A class that should be implemented and is used for testing
TEST_CLASS = 'CIM_ComputerSystem'
@@ -673,15 +672,15 @@
try:
check_utf8_xml_chars(utf8_xml, "Test XML")
- except CharError as exc:
+ except ParseError as exc:
if self.verbose:
- print "Verify manually: Input XML: %r, CharError: %s" %\
+ print "Verify manually: Input XML: %r, ParseError: %s" %\
(utf8_xml, exc)
self.assert_(expected_ok == False,
- "CharError unexpectedly raised: %s" % exc)
+ "ParseError unexpectedly raised: %s" % exc)
else:
self.assert_(expected_ok == True,
- "CharError unexpectedly not raised.")
+ "ParseError unexpectedly not raised.")
def runtest(self):
@@ -695,7 +694,7 @@
# invalid XML characters
if self.verbose:
- print "From here on, the only expected exception is CharError "\
+ print "From here on, the only expected exception is ParseError "\
"for invalid XML characters..."
self.runone('<V>a\bb</V>', False)
self.runone('<V>a\x08b</V>', False)
@@ -706,7 +705,7 @@
# correctly encoded but ill-formed UTF-8
if self.verbose:
- print "From here on, the only expected exception is CharError "\
+ print "From here on, the only expected exception is ParseError "\
"for ill-formed UTF-8 Byte sequences..."
# combo of U+D800,U+DD22:
self.runone('<V>a\xED\xA0\x80\xED\xB4\xA2b</V>', False)
@@ -716,7 +715,7 @@
# incorrectly encoded UTF-8
if self.verbose:
- print "From here on, the only expected exception is CharError "\
+ print "From here on, the only expected exception is ParseError "\
"for invalid UTF-8 Byte sequences..."
# incorrect 1-byte sequence:
self.runone('<V>a\x80b</V>', False)
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <ma...@us...> - 2015-01-21 16:48:44
|
Revision: 718
http://sourceforge.net/p/pywbem/code/718
Author: maiera
Date: 2015-01-21 16:48:36 +0000 (Wed, 21 Jan 2015)
Log Message:
-----------
Fixed bug 32, by adding a checking function check_utf8_xml_chars() to cim_operations.py and by invoking it on the reply from the WBEM server for intrinsic and extrinsic method calls, and by adding testcases for that new function in test_cim_operations.py.
Modified Paths:
--------------
pywbem/trunk/pywbem/cim_operations.py
pywbem/trunk/testsuite/test_cim_operations.py
Modified: pywbem/trunk/pywbem/cim_operations.py
===================================================================
--- pywbem/trunk/pywbem/cim_operations.py 2015-01-21 14:19:23 UTC (rev 717)
+++ pywbem/trunk/pywbem/cim_operations.py 2015-01-21 16:48:36 UTC (rev 718)
@@ -32,6 +32,7 @@
# This module is meant to be safe for 'import *'.
import string
+import re
from types import StringTypes
from xml.dom import minidom
from datetime import datetime, timedelta
@@ -40,13 +41,26 @@
from pywbem.cim_obj import CIMInstance, CIMInstanceName, CIMClass, \
CIMClassName, NocaseDict
-__all__ = ['DEFAULT_NAMESPACE', 'CIMError', 'WBEMConnection', 'is_subclass',
+__all__ = ['DEFAULT_NAMESPACE', 'CharError', 'check_utf8_xml_chars',
+ 'CIMError', 'WBEMConnection', 'is_subclass',
'PegasusUDSConnection', 'SFCBUDSConnection',
'OpenWBEMUDSConnection']
DEFAULT_NAMESPACE = 'root/cimv2'
+if len(u'\U00010122') == 2:
+ # This is a "narrow" Unicode build of Python (the normal case).
+ _ILLEGAL_XML_CHARS_RE = re.compile(
+ u'([\u0000-\u0008\u000B-\u000C\u000E-\u001F\uFFFE\uFFFF])')
+else:
+ # This is a "wide" Unicode build of Python.
+ _ILLEGAL_XML_CHARS_RE = re.compile(
+ u'([\u0000-\u0008\u000B-\u000C\u000E-\u001F\uD800-\uDFFF\uFFFE\uFFFF])')
+_ILL_FORMED_UTF8_RE = re.compile(
+ '(\xED[\xA0-\xBF][\x80-\xBF])') # U+D800...U+DFFF
+
+
def _check_classname(val):
"""
Validate a classname.
@@ -56,7 +70,188 @@
if not isinstance(val, StringTypes):
raise ValueError("string expected for classname, not %s" % `val`)
+class CharError(Exception):
+ """Raised when the `check_utf8_xml_chars()` function finds an invalid UTF-8
+ Byte sequence, or a valid Unicode character that cannot be represented in
+ XML.
+ The value is a string describing the error.
+ """
+
+ pass
+
+def check_utf8_xml_chars(utf8_xml, meaning):
+ """
+ Examine a UTF-8 encoded XML string and raise a `CharError` exception if
+ the response contains Bytes that are invalid UTF-8 sequences (incorrectly
+ encoded or ill-formed) or that are invalid XML characters.
+
+ This function works in both "wide" and "narrow" Unicode builds of Python
+ and supports the full range of Unicode characters from U+0000 to U+10FFFF.
+
+ This function is just a workaround for the bad error handling of Python's
+ `xml.dom.minidom` package. It replaces the not very informative
+ `ExpatError` "not well-formed (invalid token): line: x, column: y" with a
+ `CharError` providing more useful information.
+
+ :Parameters:
+
+ utf8_xml : string
+ The UTF-8 encoded XML string to be examined.
+
+ meaning : string
+ Short text with meaning of the XML string, for messages in exceptions.
+
+ :Exceptions:
+
+ `TypeError`, if invoked with incorrect Python object type for
+ `utf8_xml`.
+
+ `CharError`, if `utf8_xml` contains Bytes that are invalid UTF-8
+ sequences (incorrectly encoded or ill-formed) or invalid XML characters.
+
+ Notes on Unicode support in Python:
+
+ (1) For internally representing Unicode characters in the unicode type, a
+ "wide" Unicode build of Python uses UTF-32, while a "narrow" Unicode
+ build uses UTF-16. The difference is visible to Python programs for
+ Unicode characters assigned to code points above U+FFFF: The "narrow"
+ build uses 2 characters (a surrogate pair) for them, while the "wide"
+ build uses just 1 character. This affects all position- and
+ length-oriented functions, such as `len()` or string slicing.
+
+ (2) In a "wide" Unicode build of Python, the Unicode characters assigned to
+ code points U+10000 to U+10FFFF are represented directly (using code
+ points U+10000 to U+10FFFF) and the surrogate code points
+ U+D800...U+DFFF are never used; in a "narrow" Unicode build of Python,
+ the Unicode characters assigned to code points U+10000 to U+10FFFF are
+ represented using pairs of the surrogate code points U+D800...U+DFFF.
+
+ Notes on the Unicode code points U+D800...U+DFFF ("surrogate code points"):
+
+ (1) These code points have no corresponding Unicode characters assigned,
+ because they are reserved for surrogates in the UTF-16 encoding.
+
+ (2) The UTF-8 encoding can technically represent the surrogate code points.
+ ISO/IEC 10646 defines that a UTF-8 sequence containing the surrogate
+ code points is ill-formed, but it is technically possible that such a
+ sequence is in a UTF-8 encoded XML string.
+
+ (3) The Python escapes \\u and \\U used in literal strings can represent
+ the surrogate code points (as well as all other code points, regardless
+ of whether they are assigned to Unicode characters).
+
+ (4) The Python `str.encode()` and `str.decode()` functions successfully
+ translate the surrogate code points back and forth for encoding UTF-8.
+
+ For example, ``'\\xed\\xb0\\x80'.decode("utf-8") = u'\\udc00'``.
+
+ (5) Because Python supports the encoding and decoding of UTF-8 sequences
+ also for the surrogate code points, the "narrow" Unicode build of
+ Python can be (mis-)used to transport each surrogate unit separately
+ encoded in (ill-formed) UTF-8.
+
+ For example, code point U+10122 can be (illegally) created from a
+ sequence of code points U+D800,U+DD22 represented in UTF-8:
+
+ ``'\\xED\\xA0\\x80\\xED\\xB4\\xA2'.decode("utf-8") = u'\\U00010122'``
+
+ while the correct UTF-8 sequence for this code point is:
+
+ ``u'\\U00010122'.encode("utf-8") = '\\xf0\\x90\\x84\\xa2'``
+
+ Notes on XML characters:
+
+ (1) The legal XML characters are defined in W3C XML 1.0 (Fith Edition):
+
+ ::
+
+ Char ::= #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] |
+ [#x10000-#x10FFFF]
+
+ These are the code points of Unicode characters using a non-surrogate
+ representation.
+ """
+
+ context_before = 16 # number of chars to print before any bad chars
+ context_after = 16 # number of chars to print after any bad chars
+
+ if not isinstance(utf8_xml, str):
+ raise TypeError("utf8_xml argument does not have str type, but %s" % \
+ type(utf8_xml))
+
+ # Check for ill-formed UTF-8 sequences. This needs to be done
+ # before the str type gets decoded to unicode, because afterwards
+ # surrogates produced from ill-formed UTF-8 cannot be distinguished from
+ # legally produced surrogates (for code points above U+FFFF).
+ ic_list = list()
+ for m in _ILL_FORMED_UTF8_RE.finditer(utf8_xml):
+ ic_pos = m.start(1)
+ ic_seq = m.group(1)
+ ic_list.append((ic_pos,ic_seq))
+ if len(ic_list) > 0:
+ exc_txt = "Ill-formed UTF-8 Byte sequences found in %s:" % meaning
+ for (ic_pos,ic_seq) in ic_list:
+ exc_txt += "\n At offset %d:" % ic_pos
+ for c in ic_seq:
+ exc_txt += " 0x%02X" % ord(c)
+ cpos1 = max(ic_pos-context_before,0)
+ cpos2 = min(ic_pos+context_after,len(utf8_xml))
+ context = utf8_xml[cpos1:cpos2]
+ exc_txt += ", context(-%d,+%d): %s" % (context_before,
+ context_after,
+ repr(context))
+ raise CharError(exc_txt)
+
+ # Check for incorrectly encoded UTF-8 sequences.
+ # @ibm.13@ Simplified logic (removed loop).
+ try:
+ utf8_xml_u = utf8_xml.decode("utf-8")
+ except UnicodeDecodeError as exc:
+ # Only raised for incorrectly encoded UTF-8 sequences; technically
+ # correct sequences that are ill-formed (e.g. representing surrogates)
+ # do not cause this exception to be raised.
+ # If more than one incorrectly encoded sequence is present, only
+ # information about the first one is returned in the exception object.
+ # Also, the stated reason (in _msg) is not always correct.
+ _codec, _str, _p1, _p2, _msg = exc.args
+ exc_txt = "Invalid UTF-8 Byte sequences found in %s" % meaning
+ exc_txt += "\n At offset %d:" % _p1
+ for c in utf8_xml[_p1:_p2+1]:
+ exc_txt += " 0x%02X" % ord(c)
+ cpos1 = max(_p1-context_before,0)
+ cpos2 = min(_p2+context_after,len(utf8_xml))
+ context = utf8_xml[cpos1:cpos2]
+ exc_txt += ", context(-%d,+%d): %s" % (context_before,
+ context_after,
+ repr(context))
+ raise CharError(exc_txt)
+
+ # Now we know the Unicode characters are valid.
+ # Check for Unicode characters that cannot legally be represented as XML
+ # characters.
+ ic_list = list()
+ last_ic_pos = -2
+ for m in _ILLEGAL_XML_CHARS_RE.finditer(utf8_xml_u):
+ ic_pos = m.start(1)
+ ic_char = m.group(1)
+ if ic_pos > last_ic_pos + 1:
+ ic_list.append((ic_pos,ic_char))
+ last_ic_pos = ic_pos
+ if len(ic_list) > 0:
+ exc_txt = "Invalid XML characters found in %s:" % meaning
+ for (ic_pos,ic_char) in ic_list:
+ cpos1 = max(ic_pos-context_before,0)
+ cpos2 = min(ic_pos+context_after,len(utf8_xml_u))
+ context_u = utf8_xml_u[cpos1:cpos2]
+ exc_txt += "\n At offset %d: U+%04X, context(-%d,+%d): %s" % \
+ (ic_pos, ord(ic_char), context_before, context_after,
+ repr(context_u))
+ raise CharError(exc_txt)
+
+ return utf8_xml
+
+
class CIMError(Exception):
"""
Exception indicating that a CIM error has happened.
@@ -414,10 +609,12 @@
## TODO: Perhaps only compute this if it's required? Should not be
## all that expensive.
- # Set the raw response before parsing (which can fail)
+ # Set the raw response before parsing and checking (which can fail)
if self.debug:
self.last_raw_reply = resp_xml
+ check_utf8_xml_chars(resp_xml, "CIM-XML response")
+
reply_dom = minidom.parseString(resp_xml)
if self.debug:
@@ -593,9 +790,13 @@
# Convert cim_http exceptions to CIMError exceptions
raise CIMError(0, str(arg))
+ # Set the raw response before parsing and checking (which can fail)
if self.debug:
- # Set the raw response before parsing (which can fail)
self.last_raw_reply = resp_xml
+
+ check_utf8_xml_chars(resp_xml, "CIM-XML response")
+
+ if self.debug:
resp_dom = minidom.parseString(resp_xml)
self.last_reply = resp_dom.toprettyxml(indent=' ')
Modified: pywbem/trunk/testsuite/test_cim_operations.py
===================================================================
--- pywbem/trunk/testsuite/test_cim_operations.py 2015-01-21 14:19:23 UTC (rev 717)
+++ pywbem/trunk/testsuite/test_cim_operations.py 2015-01-21 16:48:36 UTC (rev 718)
@@ -19,7 +19,8 @@
Real32, Real64, CIMDateTime
from comfychair import main, TestCase, NotRunError
-from pywbem.cim_operations import DEFAULT_NAMESPACE
+from pywbem.cim_operations import DEFAULT_NAMESPACE, check_utf8_xml_chars, \
+ CharError
# A class that should be implemented and is used for testing
TEST_CLASS = 'CIM_ComputerSystem'
@@ -660,6 +661,78 @@
raise(NotRunError);
#################################################################
+# Internal functions
+#################################################################
+
+class Test_check_utf8_xml_chars(TestCase):
+
+ verbose = False # Set to True during development of tests for manually
+ # verifying the expected results.
+
+ def runone(self, utf8_xml, expected_ok):
+
+ try:
+ check_utf8_xml_chars(utf8_xml, "Test XML")
+ except CharError as exc:
+ if self.verbose:
+ print "Verify manually: Input XML: %r, CharError: %s" %\
+ (utf8_xml, exc)
+ self.assert_(expected_ok == False,
+ "CharError unexpectedly raised: %s" % exc)
+ else:
+ self.assert_(expected_ok == True,
+ "CharError unexpectedly not raised.")
+
+ def runtest(self):
+
+ # good cases
+ self.runone('<V>a</V>', True)
+ self.runone('<V>a\tb\nc\rd</V>', True)
+ self.runone('<V>a\x09b\x0Ac\x0Dd</V>', True)
+ self.runone('<V>a\xCD\x90b</V>', True) # U+350
+ self.runone('<V>a\xE2\x80\x93b</V>', True) # U+2013
+ self.runone('<V>a\xF0\x90\x84\xA2b</V>', True) # U+10122
+
+ # invalid XML characters
+ if self.verbose:
+ print "From here on, the only expected exception is CharError "\
+ "for invalid XML characters..."
+ self.runone('<V>a\bb</V>', False)
+ self.runone('<V>a\x08b</V>', False)
+ self.runone('<V>a\x00b</V>', False)
+ self.runone('<V>a\x01b</V>', False)
+ self.runone('<V>a\x1Ab</V>', False)
+ self.runone('<V>a\x1Ab\x1Fc</V>', False)
+
+ # correctly encoded but ill-formed UTF-8
+ if self.verbose:
+ print "From here on, the only expected exception is CharError "\
+ "for ill-formed UTF-8 Byte sequences..."
+ # combo of U+D800,U+DD22:
+ self.runone('<V>a\xED\xA0\x80\xED\xB4\xA2b</V>', False)
+ # combo of U+D800,U+DD22 and combo of U+D800,U+DD23:
+ self.runone('<V>a\xED\xA0\x80\xED\xB4\xA2b\xED\xA0\x80\xED\xB4\xA3</V>',
+ False)
+
+ # incorrectly encoded UTF-8
+ if self.verbose:
+ print "From here on, the only expected exception is CharError "\
+ "for invalid UTF-8 Byte sequences..."
+ # incorrect 1-byte sequence:
+ self.runone('<V>a\x80b</V>', False)
+ # 2-byte sequence with missing second byte:
+ self.runone('<V>a\xC0', False)
+ # 2-byte sequence with incorrect 2nd byte
+ self.runone('<V>a\xC0b</V>', False)
+ # 4-byte sequence with incorrect 3rd byte:
+ self.runone('<V>a\xF1\x80abc</V>', False)
+ # 4-byte sequence with incorrect 3rd byte that is an incorr. new start:
+ self.runone('<V>a\xF1\x80\xFFbc</V>', False)
+ # 4-byte sequence with incorrect 3rd byte that is an correct new start:
+ self.runone('<V>a\xF1\x80\xC2\x81c</V>', False)
+
+
+#################################################################
# Main function
#################################################################
@@ -712,12 +785,18 @@
]
+tests_internal = [
+ Test_check_utf8_xml_chars,
+]
+
if __name__ == '__main__':
if len(sys.argv) < 2:
- print 'Usage: %s [OPTS] URL [USERNAME%%PASSWORD [COMFYOPTS] '\
+ print 'Usage for manual external tests:\n %s [OPTS] URL [USERNAME%%PASSWORD [COMFYOPTS] '\
'[COMFYTESTS]]' % sys.argv[0]
- sys.exit(0)
+ print 'Invoke with -h or --help for full help text.'
+ print 'Running internal tests...'
+ main(tests_internal)
elif sys.argv[1] == '--help' or sys.argv[1] == '-h':
print ''
print 'Test program for CIM operations.'
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <ma...@us...> - 2015-01-21 14:19:26
|
Revision: 717
http://sourceforge.net/p/pywbem/code/717
Author: maiera
Date: 2015-01-21 14:19:23 +0000 (Wed, 21 Jan 2015)
Log Message:
-----------
Released preliminary version 0.8.0-dev.r716
Revision Links:
--------------
http://sourceforge.net/p/pywbem/code/716
Added Paths:
-----------
pywbem/dist/pywbem-0.8.0/pywbem-0.8.0-dev.r716.zip
Added: pywbem/dist/pywbem-0.8.0/pywbem-0.8.0-dev.r716.zip
===================================================================
(Binary files differ)
Index: pywbem/dist/pywbem-0.8.0/pywbem-0.8.0-dev.r716.zip
===================================================================
--- pywbem/dist/pywbem-0.8.0/pywbem-0.8.0-dev.r716.zip 2015-01-21 14:12:52 UTC (rev 716)
+++ pywbem/dist/pywbem-0.8.0/pywbem-0.8.0-dev.r716.zip 2015-01-21 14:19:23 UTC (rev 717)
Property changes on: pywbem/dist/pywbem-0.8.0/pywbem-0.8.0-dev.r716.zip
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <ma...@us...> - 2015-01-21 14:12:55
|
Revision: 716
http://sourceforge.net/p/pywbem/code/716
Author: maiera
Date: 2015-01-21 14:12:52 +0000 (Wed, 21 Jan 2015)
Log Message:
-----------
Added comments to cim_xml.py to explain why the EmbededObject attribute cannot be amended by an EMBEDDEDOBJECT attribute in support of OpenPegasus 2.6.
Modified Paths:
--------------
pywbem/trunk/pywbem/cim_xml.py
Modified: pywbem/trunk/pywbem/cim_xml.py
===================================================================
--- pywbem/trunk/pywbem/cim_xml.py 2015-01-21 14:08:52 UTC (rev 715)
+++ pywbem/trunk/pywbem/cim_xml.py 2015-01-21 14:12:52 UTC (rev 716)
@@ -853,7 +853,23 @@
self.setAttribute('PROPAGATED', str(propagated).lower())
self.setOptionalAttribute('xml:lang', xml_lang)
+
self.setOptionalAttribute('EmbeddedObject', embedded_object)
+ # Note on EmbeddedObject:
+ # The CIM-XML standard requires the mixed case form, 'EmbeddedObject'.
+ # Given that all other attributes are in upper case, this is an
+ # inconsistency in the standard that cannot be fixed for backwards
+ # compatibility reasons.
+ # OpenPegasus 2.6 supported only the upper case form 'EMBEDDEDOBJECT'.
+ # Later OpenPegasus versions fixed that by using 'EmbeddedObject' in
+ # any responses and by accepting both 'EMBEDDEDOBJECT' and
+ # 'EmbeddedObject' in any requests.
+ # Adding the 'EMBEDDEDOBJECT' attribute to any requests (that is, in
+ # this code here) in order to support the old OpenPegasus 2.6 does not
+ # work unfortunately, because SFCB supports either form but not both
+ # attributes in the same request.
+ # As a result, the best choice is to use only the standards-conforming
+ # mixed case form in any requests sent by PyWBEM.
self.appendChildren(qualifiers)
self.appendOptionalChild(value)
@@ -894,6 +910,7 @@
self.setAttribute('ARRAYSIZE', str(array_size))
self.setOptionalAttribute('CLASSORIGIN', class_origin)
self.setOptionalAttribute('EmbeddedObject', embedded_object)
+ # See the note on EmbeddedObject in PROPERTY().
if propagated is not None:
self.setAttribute('PROPAGATED', str(propagated).lower())
@@ -1284,6 +1301,7 @@
self.setName(name)
self.setOptionalAttribute('PARAMTYPE', paramtype)
self.setOptionalAttribute('EmbeddedObject', embedded_object)
+ # See the note on EmbeddedObject in PROPERTY().
self.appendOptionalChild(data)
class IPARAMVALUE(CIMElement):
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <ma...@us...> - 2015-01-21 14:08:55
|
Revision: 715
http://sourceforge.net/p/pywbem/code/715
Author: maiera
Date: 2015-01-21 14:08:52 +0000 (Wed, 21 Jan 2015)
Log Message:
-----------
Fixed bug 30: Added support for CDATA based escaping, which can be turned on using the global variable _CDATA_ESCAPING in the cim_xml module. Extended the testcases to test both XML-based and CDATA-based escaping, and to test nested escaping (for nested embedded instances). Moved Python version check from cim_xml to __init__.
Modified Paths:
--------------
pywbem/trunk/pywbem/NEWS
pywbem/trunk/pywbem/__init__.py
pywbem/trunk/pywbem/cim_xml.py
pywbem/trunk/testsuite/test_cim_xml.py
Modified: pywbem/trunk/pywbem/NEWS
===================================================================
--- pywbem/trunk/pywbem/NEWS 2015-01-21 13:58:14 UTC (rev 714)
+++ pywbem/trunk/pywbem/NEWS 2015-01-21 14:08:52 UTC (rev 715)
@@ -1,4 +1,4 @@
-pywbem-0.8.0-dev.r712
+pywbem-0.8.0-dev.r715
ENHANCEMENTS:
@@ -73,6 +73,12 @@
__all__: mof_compiler, twisted_client, tupleparse, cimxml_parse,
cim_http. (Andreas Maier)
+ * Added support for using CDATA section based escaping in any requests sent
+ to the WBEM server. The default is still XML entity reference based
+ escaping, the CDATA based escaping can be turned on by setting the switch
+ _CDATA_ESCAPING accordingly, which is a global variable in the cim_xml
+ module. (Andreas Maier)
+
BUG FIXES:
* Fix syntax error in CIM DTDVERSION error path. Allow KEYVALUE
Modified: pywbem/trunk/pywbem/__init__.py
===================================================================
--- pywbem/trunk/pywbem/__init__.py 2015-01-21 13:58:14 UTC (rev 714)
+++ pywbem/trunk/pywbem/__init__.py 2015-01-21 14:08:52 UTC (rev 715)
@@ -160,3 +160,8 @@
from pywbem.cim_operations import *
from pywbem.cim_obj import *
from pywbem.tupleparse import ParseError
+
+# TODO: Check if we can bump the minimum Python version to 2.6.
+import sys
+if sys.version_info < (2,3,0):
+ raise RuntimeError('PyWBEM requires Python 2.3.0 or higher')
Modified: pywbem/trunk/pywbem/cim_xml.py
===================================================================
--- pywbem/trunk/pywbem/cim_xml.py 2015-01-21 13:58:14 UTC (rev 714)
+++ pywbem/trunk/pywbem/cim_xml.py 2015-01-21 14:08:52 UTC (rev 715)
@@ -75,17 +75,112 @@
'RESPONSEDESTINATION', 'SIMPLEREQACK']
def _text(data):
- """Grr. The API for the minidom text node function has changed in
- Python 2.3. This function allows the code to run under older
- versions of the intepreter."""
+ """Return a minidom text node with the specified data string.
- if sys.version_info[0] == 2 and sys.version_info[1] >= 3:
- t = xml.dom.minidom.Text()
- t.data = data
- return t
+ When converting that node to an XML string using ``toxml()``, XML-escaping
+ will be applied if needed (for example, ``_text('&').toxml() = '&'``).
- return xml.dom.minidom.Text(data)
+ Note: The API for the minidom text node function has changed in
+ Python 2.3. The code for older Python versions has been removed from this
+ function in PyWBEM 0.8.0; the Python version check is now done in
+ __init__.py.
+ """
+ # The following initialization approach requires Python 2.3 or higher.
+ t = xml.dom.minidom.Text()
+ t.data = data
+
+ return t
+
+# Switch controlling whether the escaping of special XML characters in any
+# request messages sent to the WBEM server will be done using CDATA
+# sections (if True), or using XML entity references (e.g. &) (if
+# False).
+# Using XML-based escaping generates a simpler CIM-XML payload.
+# Standards-conforming WBEM servers need to support both ways.
+# You only need to set this to True if the WBEM server has no support for
+# XML-based escaping, but does have support for CDATA-based escaping.
+_CDATA_ESCAPING = False
+
+def _pcdata_nodes(pcdata):
+ """Return a list of minidom nodes with the properly escaped ``pcdata``
+ inside.
+
+ The following special XML characters are escaped:
+ * left angle bracket (<)
+ * Right angle bracket (>)
+ * Ampersand (&)
+
+ By default, XML-based escaping is used for these characters. XML-based
+ escaping will cause the corresponding XML entity references to be used
+ (for example, the ampersand character ``&`` will be represented as
+ ``&``, and the returned list contains one text node with the escaped
+ pcdata string.
+
+ Nesting of escaped pcdata is naturally supported with XML-based escaping.
+ For example, if the pcdata string is ``a&b``, the XML-escaped string
+ will be ``a&amp;b``.
+
+ If the ``cim_xml._CDATA_ESCAPING`` switch is set to True, CDATA-based
+ escaping is used instead. CDATA-based escaping will cause a CDATA section
+ to be used for the entire string, or consecutive CDATA sequences (see
+ discussion of nesting, below). The returned node list contains only CDATA
+ section nodes. Example: The pcdata string ``a<b>c`` will become
+ ``<![CDATA[a<b>]]>``, allowing the special XML characters to be used
+ unchanged inside of the CDATA section.
+
+ Nesting of escaped pcdata is supported with CDATA-based escaping, by using
+ the following approach: If the input pcdata string already contains CDATA
+ sections, they are split into separate strings, splitting the CDATA end
+ token string in the middle, and these part strings are CDATA-escaped
+ separately. See http://en.wikipedia.org/wiki/CDATA#Nesting for details.
+
+ Escaping of already escaped pcdata is needed in support of nested embedded
+ instances. That requires that each level of escaping can lateron be
+ unescaped, one at a time.
+ """
+
+ nodelist = []
+
+ if _CDATA_ESCAPING and type(pcdata) in (str,unicode) and \
+ (pcdata.find("<") >= 0 or \
+ pcdata.find(">") >= 0 or \
+ pcdata.find("&") >= 0):
+
+ # In order to support nesting of CDATA sections, we represent pcdata
+ # that already contains CDATA sections by multiple new CDATA sections
+ # whose boundaries split the end marker of the already existing CDATA
+ # sections.
+
+ pcdata_part_list = pcdata.split("]]>")
+ # ']]>' is the complete CDATA section end marker
+
+ i = 0
+ for pcdata_part in pcdata_part_list:
+ i += 1
+
+ left = "" if i == 1 else "]>"
+ # ']>' is right part of CDATA section end marker
+
+ right = "" if i == len(pcdata_part_list) else "]"
+ # "]" is left part of CDATA section end marker
+
+ # The following initialization approach requires Python 2.3 or
+ # higher.
+ node = xml.dom.minidom.CDATASection()
+ node.data = left + pcdata_part + right
+
+ nodelist.append(node)
+
+ else:
+
+ # The following automatically uses XML entity references for escaping.
+ node = _text(pcdata)
+
+ nodelist.append(node)
+
+ return nodelist
+
class CIMElement(Element):
"""A base class that has a few bonus helper methods."""
@@ -285,7 +380,7 @@
def __init__(self, pcdata):
Element.__init__(self, 'VALUE')
if pcdata is not None:
- self.appendChild(_text(pcdata))
+ self.appendChildren(_pcdata_nodes(pcdata))
class VALUE_ARRAY(CIMElement):
# pylint: disable=invalid-name
Modified: pywbem/trunk/testsuite/test_cim_xml.py
===================================================================
--- pywbem/trunk/testsuite/test_cim_xml.py 2015-01-21 13:58:14 UTC (rev 714)
+++ pywbem/trunk/testsuite/test_cim_xml.py 2015-01-21 14:08:52 UTC (rev 715)
@@ -67,18 +67,39 @@
class CIMXMLTest(comfychair.TestCase):
"""Run validate.py script against an xml document fragment."""
- xml = [] # Test data
+ def __init__(self):
+ super(CIMXMLTest, self).__init__()
+ self.xml = [] # List of test cases, each list item being an
+ # xml.dom.minidom node representing some element
+ # from the CIM-XML payload.
+
+ self.xml_str = [] # List of expected XML strings resulting from each
+ # test case.
+
def validate(self, xml, expectedResult=0):
+ """xml is a string with the CIM-XML."""
validate_xml(xml, dtd_directory='../..')
def runtest(self):
- # Test xml fragments pass validation
+ for i in range(0, len(self.xml)):
- for x in [x.toxml() for x in self.xml]:
- self.validate(x)
+ xml_node = self.xml[i]
+ act_xml_str = xml_node.toxml()
+ self.log("CIM-XML fragment to be tested: %r" % act_xml_str)
+
+ # Test that the XML fragments pass validation against CIM-XML DTD
+ self.validate(act_xml_str)
+
+ if i < len(self.xml_str):
+ # Test XML fragments for expected string representation
+ exp_xml_str = self.xml_str[i]
+ if exp_xml_str is not None:
+ self.assert_equal(act_xml_str, exp_xml_str)
+
+
class UnimplementedTest(CIMXMLTest):
def runtest(self):
raise comfychair.NotRunError('unimplemented')
@@ -185,10 +206,65 @@
def setup(self):
+ # The VALUE element depends on whether XML-based or CDATA-based
+ # escaping is used. Therefore, we modify the module-level switch that
+ # controls that and run each test twice (wth different expected XML
+ # strings).
+
+ cim_xml._CDATA_ESCAPING = True
+
self.xml.append(cim_xml.VALUE('dog'))
- self.xml.append(cim_xml.VALUE(None))
+ self.xml_str.append('<VALUE>dog</VALUE>')
+
+ # self.xml.append(cim_xml.VALUE(None))
+ # Note: This is illegal, Value.Null should be used instead.
+
self.xml.append(cim_xml.VALUE(''))
+ self.xml_str.append('<VALUE></VALUE>') # Assuming not folded to <VALUE/>
+ # Some control characters
+ self.xml.append(cim_xml.VALUE('a\nb\rc\td'))
+ self.xml_str.append('<VALUE>a\nb\rc\td</VALUE>') # Assuming XML 1.1
+
+ # Some XML special characters
+ self.xml.append(cim_xml.VALUE('a&b<c>d'))
+ self.xml_str.append('<VALUE><![CDATA[a&b<c>d]]></VALUE>')
+
+ # Some XML special characters, already XML-escaped
+ self.xml.append(cim_xml.VALUE('a&b<c>d'))
+ self.xml_str.append('<VALUE><![CDATA[a&b<c>d]]></VALUE>')
+
+ # Some XML special characters, already CDATA-escaped
+ self.xml.append(cim_xml.VALUE('<![CDATA[a&b<c>d]]>'))
+ self.xml_str.append('<VALUE><![CDATA[<![CDATA[a&b<c>d]]]><![CDATA[]>]]></VALUE>')
+
+ cim_xml._CDATA_ESCAPING = False # Back to its default
+
+ self.xml.append(cim_xml.VALUE('dog'))
+ self.xml_str.append('<VALUE>dog</VALUE>')
+
+ # self.xml.append(cim_xml.VALUE(None))
+ # Note: This is illegal, Value.Null is used instead.
+
+ self.xml.append(cim_xml.VALUE(''))
+ self.xml_str.append('<VALUE></VALUE>') # Assuming not folded to <VALUE/>
+
+ # Some control characters
+ self.xml.append(cim_xml.VALUE('a\nb\rc\td'))
+ self.xml_str.append('<VALUE>a\nb\rc\td</VALUE>') # Assuming XML 1.1
+
+ # Some XML special characters
+ self.xml.append(cim_xml.VALUE('a&b<c>d'))
+ self.xml_str.append('<VALUE>a&b<c>d</VALUE>')
+
+ # Some XML special characters, already XML-escaped
+ self.xml.append(cim_xml.VALUE('a&b<c>d'))
+ self.xml_str.append('<VALUE>a&amp;b&lt;c&gt;d</VALUE>')
+
+ # Some XML special characters, already CDATA-escaped
+ self.xml.append(cim_xml.VALUE('<![CDATA[a&b<c>d]]>'))
+ self.xml_str.append('<VALUE><![CDATA[a&b<c>d]]></VALUE>')
+
class ValueArray(CIMXMLTest):
"""
<!ELEMENT VALUE.ARRAY (VALUE*)>
@@ -348,7 +424,9 @@
"""
<!ELEMENT VALUE.NULL EMPTY>
"""
+ # TODO: Implement ValueNull test
+
#################################################################
# 3.2.4. Naming and Location Elements
#################################################################
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <ma...@us...> - 2015-01-21 13:58:23
|
Revision: 714
http://sourceforge.net/p/pywbem/code/714
Author: maiera
Date: 2015-01-21 13:58:14 +0000 (Wed, 21 Jan 2015)
Log Message:
-----------
Fixed passing of command line options to testcases.
Modified Paths:
--------------
pywbem/trunk/testsuite/runtests.sh
pywbem/trunk/testsuite/test_cim_operations.py
Modified: pywbem/trunk/testsuite/runtests.sh
===================================================================
--- pywbem/trunk/testsuite/runtests.sh 2015-01-19 11:09:22 UTC (rev 713)
+++ pywbem/trunk/testsuite/runtests.sh 2015-01-21 13:58:14 UTC (rev 714)
@@ -36,7 +36,7 @@
for test in test_*.py; do
for python in $PYTHON; do
echo ====================
- echo $python $test
+ echo $python $test "$@"
echo ====================
$python $test "$@"
if [ $? != 0 ]; then
Modified: pywbem/trunk/testsuite/test_cim_operations.py
===================================================================
--- pywbem/trunk/testsuite/test_cim_operations.py 2015-01-19 11:09:22 UTC (rev 713)
+++ pywbem/trunk/testsuite/test_cim_operations.py 2015-01-21 13:58:14 UTC (rev 714)
@@ -758,10 +758,14 @@
namespace = DEFAULT_NAMESPACE
while (True):
if sys.argv[1][0] != '-':
+ # Stop at first non-option
break
if sys.argv[1] == '-n':
namespace = sys.argv[2]
del sys.argv[1:3]
+ else:
+ print "Error: Unknown option: %s" % sys.argv[1]
+ sys.exit(1)
url = sys.argv[1]
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <ma...@us...> - 2015-01-19 11:09:26
|
Revision: 713
http://sourceforge.net/p/pywbem/code/713
Author: maiera
Date: 2015-01-19 11:09:22 +0000 (Mon, 19 Jan 2015)
Log Message:
-----------
Released preliminary version 0.8.0-dev.r712
Revision Links:
--------------
http://sourceforge.net/p/pywbem/code/712
Added Paths:
-----------
pywbem/dist/pywbem-0.8.0/pywbem-0.8.0-dev.r712.zip
Added: pywbem/dist/pywbem-0.8.0/pywbem-0.8.0-dev.r712.zip
===================================================================
(Binary files differ)
Index: pywbem/dist/pywbem-0.8.0/pywbem-0.8.0-dev.r712.zip
===================================================================
--- pywbem/dist/pywbem-0.8.0/pywbem-0.8.0-dev.r712.zip 2015-01-19 11:04:17 UTC (rev 712)
+++ pywbem/dist/pywbem-0.8.0/pywbem-0.8.0-dev.r712.zip 2015-01-19 11:09:22 UTC (rev 713)
Property changes on: pywbem/dist/pywbem-0.8.0/pywbem-0.8.0-dev.r712.zip
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <ma...@us...> - 2015-01-19 11:04:19
|
Revision: 712
http://sourceforge.net/p/pywbem/code/712
Author: maiera
Date: 2015-01-19 11:04:17 +0000 (Mon, 19 Jan 2015)
Log Message:
-----------
Fixed bug 29:
Fixed errors in generated MOF (e.g. in any tomof() methods):
- Missing backslash escaping within string literals for \n, \r, \t, \".
- Representation of REF types was incorrect.
- '=' in array-typed qualifier declarations was missing.
- Fixed size indicator was missing in array elements.
- Qualifiers of method parameters were missing.
Improvements in generated MOF:
- Changed order of qualifiers to be sorted by qualifier name.
- Added empty line before each property and method in the class for better readability.
- Method parameters are now placed on separate lines.
- Moved generation of method qualifiers from class into method. This changes the behavior of CIMMethod.tomof() to now generate the method qualifiers.
Modified Paths:
--------------
pywbem/trunk/pywbem/NEWS
pywbem/trunk/pywbem/cim_obj.py
pywbem/trunk/testsuite/test_cim_obj.py
Modified: pywbem/trunk/pywbem/NEWS
===================================================================
--- pywbem/trunk/pywbem/NEWS 2015-01-19 09:27:29 UTC (rev 711)
+++ pywbem/trunk/pywbem/NEWS 2015-01-19 11:04:17 UTC (rev 712)
@@ -1,4 +1,4 @@
-pywbem-0.8.0-dev.r710
+pywbem-0.8.0-dev.r712
ENHANCEMENTS:
@@ -217,6 +217,22 @@
Also, cleaned up the global namespace of wbemcli.py and made it
importable as a module. (Andreas Maier)
+ * Fixed errors in generated MOF (e.g. in any tomof() methods):
+ - Missing backslash escaping within string literals for \n, \r, \t, \".
+ - Representation of REF types was incorrect.
+ - '=' in array-typed qualifier declarations was missing.
+ - Fixed size indicator was missing in array elements.
+ - Qualifiers of method parameters were missing.
+ Improvements in generated MOF:
+ - Changed order of qualifiers to be sorted by qualifier name.
+ - Added empty line before each property and method in the class for
+ better readability.
+ - Method parameters are now placed on separate lines.
+ - Moved generation of method qualifiers from class into method. This
+ changes the behavior of CIMMethod.tomof() to now generate the method
+ qualifiers.
+ (Andreas Maier)
+
TESTING:
* Added support for running the unit test cases without having to be in the
Modified: pywbem/trunk/pywbem/cim_obj.py
===================================================================
--- pywbem/trunk/pywbem/cim_obj.py 2015-01-19 09:27:29 UTC (rev 711)
+++ pywbem/trunk/pywbem/cim_obj.py 2015-01-19 11:04:17 UTC (rev 712)
@@ -35,6 +35,7 @@
# This module is meant to be safe for 'import *'.
import string
+import re
from types import StringTypes
from datetime import datetime, timedelta
@@ -443,6 +444,83 @@
return cmp(lower_name1, lower_name2)
+def _makequalifiers(qualifiers, indent):
+ """Return a MOF fragment for a NocaseDict of qualifiers."""
+
+ if len(qualifiers) == 0:
+ return ''
+
+ return '[%s]' % ',\n '.ljust(indent+2).\
+ join([q.tomof(indent) for q in sorted(qualifiers.values())])
+
+def mofstr(strvalue, indent=7, maxline=80):
+ """Converts the input string value to a MOF literal string value, including
+ the surrounding double quotes.
+
+ In doing so, all characters that have MOF escape characters (except for
+ single quotes) are escaped by adding a leading backslash (\), if not yet
+ present. This conditional behavior is needed for WBEM servers that return
+ the MOF escape sequences in their CIM-XML representation of any strings,
+ instead of converting them to the binary characters as required by the CIM
+ standards.
+
+ Single quotes do not need to be escaped because the returned literal
+ string uses double quotes.
+
+ After escaping, the string is broken into multiple lines, for better
+ readability. The maximum line size is specified via the ``maxline``
+ argument. The indentation for any spilled over lines (i.e. not the first
+ line) is specified via the ``indent`` argument.
+ """
+
+ # escape \n, \r, \t, \f, \b
+ escaped_str = strvalue.replace("\n","\\n").replace("\r","\\r").\
+ replace("\t","\\t").replace("\f","\\f").replace("\b","\\b")
+
+ # escape double quote (") if not already escaped.
+ # TODO: Add support for two consecutive double quotes ("").
+ escaped_str = re.sub(r'([^\\])"', r'\1\\"', escaped_str)
+
+ # escape special case of a single double quote (")
+ escaped_str = re.sub(r'^"$', r'\"', escaped_str)
+
+ # escape backslash (\) not followed by any of: nrtfb"'
+ escaped_str = re.sub(r'\\([^nrtfb"\'])', r'\\\1', escaped_str)
+
+ # escape special case of a single backslash (\)
+ escaped_str = re.sub(r'^\\$', r'\\\\', escaped_str)
+
+ # Break into multiple strings for better readability
+ blankfind = maxline - indent - 2
+ indent_str = ' '.ljust(indent, ' ')
+ ret_str_list = list()
+ if escaped_str == '':
+ ret_str_list.append('""')
+ else:
+ while escaped_str != '':
+ if len(escaped_str) <= blankfind:
+ ret_str_list.append('"' + escaped_str + '"')
+ escaped_str = ''
+ else:
+ splitpos = escaped_str.rfind(' ',0,blankfind)
+ if splitpos < 0:
+ splitpos = blankfind-1
+ ret_str_list.append('"' + escaped_str[0:splitpos+1] + '"')
+ escaped_str = escaped_str[splitpos+1:]
+
+ ret_str = ('\n'+indent_str).join(ret_str_list)
+ return ret_str
+
+def moftype(cimtype, refclass):
+ """Converts a CIM type name to MOF syntax."""
+
+ if cimtype == 'reference':
+ _moftype = refclass + " REF"
+ else:
+ _moftype = cimtype
+
+ return _moftype
+
class CIMClassName(object):
"""
A CIM class path.
@@ -1534,7 +1612,7 @@
val += _prop2mof(_type, x)
val += '}'
elif _type == 'string':
- val = '"' + value + '"'
+ val = mofstr(value)
else:
val = str(value)
return val
@@ -1607,15 +1685,6 @@
def tomof(self):
- def _makequalifiers(qualifiers, indent):
- """Return a mof fragment for a NocaseDict of qualifiers."""
-
- if len(qualifiers) == 0:
- return ''
-
- return '[%s]' % ',\n '.ljust(indent+2).join(
- [q.tomof() for q in qualifiers.values()])
-
# Class definition
s = ' %s\n' % _makequalifiers(self.qualifiers, 4)
@@ -1632,13 +1701,19 @@
# Properties
for p in self.properties.values():
+ if p.is_array and p.array_size is not None:
+ array_str = "[%s]" % p.array_size
+ else:
+ array_str = ''
+ s += '\n'
s += ' %s\n' % (_makequalifiers(p.qualifiers, 7))
- s += ' %s %s;\n' % (p.type, p.name)
+ s += ' %s %s%s;\n' % (moftype(p.type, p.reference_class),
+ p.name, array_str)
# Methods
for m in self.methods.values():
- s += ' %s\n' % (_makequalifiers(m.qualifiers, 7))
+ s += '\n'
s += ' %s\n' % m.tomof()
s += '};\n'
@@ -1712,12 +1787,17 @@
s = ''
+ s += ' %s\n' % (_makequalifiers(self.qualifiers, 7))
+
if self.return_type is not None:
- s += '%s ' % self.return_type
+ s += '%s ' % moftype(self.return_type, None)
+ # CIM-XML does not support methods returning reference types
+ # (the CIM architecture does).
- s += '%s(%s);' % \
- (self.name,
- string.join([p.tomof() for p in self.parameters.values()], ', '))
+ s += '%s(\n' % (self.name)
+ s += string.join(
+ [' '+p.tomof() for p in self.parameters.values()], ',\n')
+ s += ');\n'
return s
@@ -1827,7 +1907,15 @@
qualifiers=[q.tocimxml() for q in self.qualifiers.values()])
def tomof(self):
- return '%s %s' % (self.type, self.name)
+ if self.is_array and self.array_size is not None:
+ array_str = "[%s]" % self.array_size
+ else:
+ array_str = ''
+ s = '\n'
+ s += ' %s\n' % (_makequalifiers(self.qualifiers, 10))
+ s += ' %s %s%s' % (moftype(self.type, self.reference_class),
+ self.name, array_str)
+ return s
class CIMQualifier(object):
"""
@@ -1944,11 +2032,11 @@
toinstance=self.toinstance,
translatable=self.translatable)
- def tomof(self):
+ def tomof(self, indent=7):
def valstr(v):
if isinstance(v, basestring):
- return '"%s"' % v
+ return mofstr(v, indent)
return str(v)
if type(self.value) == list:
@@ -2048,7 +2136,7 @@
mof += ']'
if self.value is not None:
if isinstance(self.value, list):
- mof += '{'
+ mof += ' = {'
mof += ', '.join([cim_types.atomic_to_cim_xml(
tocimobj(self.type, x)) for x in self.value])
mof += '}'
Modified: pywbem/trunk/testsuite/test_cim_obj.py
===================================================================
--- pywbem/trunk/testsuite/test_cim_obj.py 2015-01-19 09:27:29 UTC (rev 711)
+++ pywbem/trunk/testsuite/test_cim_obj.py 2015-01-19 11:04:17 UTC (rev 712)
@@ -2764,6 +2764,72 @@
#self.assert_equal(path.host, '.')
#self.assert_equal(path.classname, 'NetworkCard')
+#################################################################
+# MofStr - test cases for mofstr()
+#################################################################
+
+class MofStr(TestCase):
+
+ def runtest_single(self, in_value, exp_value):
+ '''
+ Test function for single invocation of mofstr()
+ '''
+
+ ret_value = cim_obj.mofstr(in_value)
+
+ self.assert_equal(ret_value, exp_value)
+
+ def runtest(self):
+ '''
+ Run all tests for mofstr().
+ '''
+
+ self.runtest_single('', '""')
+ self.runtest_single('\\', '"\\\\"')
+ self.runtest_single('"', '"\\""')
+ self.runtest_single('a"b', '"a\\"b"')
+ # TODO: Enable the following test, once "" is supported.
+ #self.runtest_single('a""b', '"a\\"\\"b"')
+ self.runtest_single("'", '"\'"')
+ self.runtest_single("a'b", '"a\'b"')
+ self.runtest_single("a''b", '"a\'\'b"')
+ self.runtest_single("\\'", '"\\\'"')
+ self.runtest_single('\\"', '"\\""')
+ self.runtest_single('\r\n\t\b\f', '"\\r\\n\\t\\b\\f"')
+ self.runtest_single('\\r\\n\\t\\b\\f', '"\\r\\n\\t\\b\\f"')
+ self.runtest_single('\\_\\+\\v\\h\\j', '"\\_\\+\\v\\h\\j"')
+ self.runtest_single('a', '"a"')
+ self.runtest_single('a b', '"a b"')
+ self.runtest_single(' b', '" b"')
+ self.runtest_single('a ', '"a "')
+ self.runtest_single(' ', '" "')
+
+ # |0 |71
+ self.runtest_single('the big brown fox jumps over a big brown fox jumps over a big brown f jumps over a big brown fox',\
+ '"the big brown fox jumps over a big brown fox jumps over a big brown f "\n '+\
+ '"jumps over a big brown fox"')
+ self.runtest_single('the big brown fox jumps over a big brown fox jumps over a big brown fo jumps over a big brown fox',\
+ '"the big brown fox jumps over a big brown fox jumps over a big brown fo "\n '+\
+ '"jumps over a big brown fox"')
+ self.runtest_single('the big brown fox jumps over a big brown fox jumps over a big brown fox jumps over a big brown fox',\
+ '"the big brown fox jumps over a big brown fox jumps over a big brown "\n '+\
+ '"fox jumps over a big brown fox"')
+ self.runtest_single('the big brown fox jumps over a big brown fox jumps over a big brown foxx jumps over a big brown fox',\
+ '"the big brown fox jumps over a big brown fox jumps over a big brown "\n '+\
+ '"foxx jumps over a big brown fox"')
+ self.runtest_single('the big brown fox jumps over a big brown fox jumps over a big brown foxxx jumps over a big brown fox',\
+ '"the big brown fox jumps over a big brown fox jumps over a big brown "\n '+\
+ '"foxxx jumps over a big brown fox"')
+ self.runtest_single('the_big_brown_fox_jumps_over_a_big_brown_fox_jumps_over_a_big_brown_fox_jumps_over a big brown fox',\
+ '"the_big_brown_fox_jumps_over_a_big_brown_fox_jumps_over_a_big_brown_fox"\n '+\
+ '"_jumps_over a big brown fox"')
+ self.runtest_single('the big brown fox jumps over a big brown fox jumps over a big brown fox_jumps_over_a_big_brown_fox',\
+ '"the big brown fox jumps over a big brown fox jumps over a big brown "\n '+\
+ '"fox_jumps_over_a_big_brown_fox"')
+
+ return 0
+
+
###############################################################################
# Main function
###############################################################################
@@ -2879,9 +2945,9 @@
CIMQualifierDeclarationString,
CIMQualifierDeclarationToXML,
- # tocimobj
-
+ # Others
ToCIMObj,
+ MofStr,
]
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <ma...@us...> - 2015-01-19 09:27:32
|
Revision: 711
http://sourceforge.net/p/pywbem/code/711
Author: maiera
Date: 2015-01-19 09:27:29 +0000 (Mon, 19 Jan 2015)
Log Message:
-----------
Released preliminary version 0.8.0-dev.r710
Revision Links:
--------------
http://sourceforge.net/p/pywbem/code/710
Modified Paths:
--------------
pywbem/trunk/pywbem/NEWS
Added Paths:
-----------
pywbem/dist/pywbem-0.8.0/pywbem-0.8.0-dev.r710.zip
Added: pywbem/dist/pywbem-0.8.0/pywbem-0.8.0-dev.r710.zip
===================================================================
(Binary files differ)
Index: pywbem/dist/pywbem-0.8.0/pywbem-0.8.0-dev.r710.zip
===================================================================
--- pywbem/dist/pywbem-0.8.0/pywbem-0.8.0-dev.r710.zip 2015-01-19 09:23:12 UTC (rev 710)
+++ pywbem/dist/pywbem-0.8.0/pywbem-0.8.0-dev.r710.zip 2015-01-19 09:27:29 UTC (rev 711)
Property changes on: pywbem/dist/pywbem-0.8.0/pywbem-0.8.0-dev.r710.zip
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Modified: pywbem/trunk/pywbem/NEWS
===================================================================
--- pywbem/trunk/pywbem/NEWS 2015-01-19 09:23:12 UTC (rev 710)
+++ pywbem/trunk/pywbem/NEWS 2015-01-19 09:27:29 UTC (rev 711)
@@ -1,4 +1,4 @@
-pywbem-0.8.0-dev.r708
+pywbem-0.8.0-dev.r710
ENHANCEMENTS:
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <ma...@us...> - 2015-01-19 09:23:15
|
Revision: 710
http://sourceforge.net/p/pywbem/code/710
Author: maiera
Date: 2015-01-19 09:23:12 +0000 (Mon, 19 Jan 2015)
Log Message:
-----------
Added classifiers information to setup.py to make it suitable for PyPi.
Modified Paths:
--------------
pywbem/trunk/setup.py
Modified: pywbem/trunk/setup.py
===================================================================
--- pywbem/trunk/setup.py 2015-01-19 09:20:09 UTC (rev 709)
+++ pywbem/trunk/setup.py 2015-01-19 09:23:12 UTC (rev 710)
@@ -59,6 +59,19 @@
'pywbem/wbemcli.py',
'pywbem/mof_compiler.py',
],
+ 'classifiers' : [
+ 'Development Status :: 4 - Beta',
+ 'Intended Audience :: Developers',
+ 'Intended Audience :: System Administrators',
+ 'License :: OSI Approved :: GNU Lesser General Public License v2 or later (LGPLv2+)',
+ 'Operating System :: POSIX :: Linux',
+ 'Operating System :: Microsoft :: Windows',
+ 'Programming Language :: Python',
+ 'Programming Language :: Python :: 2.6',
+ 'Programming Language :: Python :: 2.7',
+ 'Topic :: Software Development',
+ 'Topic :: System :: Systems Administration',
+ ],
}
setup(**args)
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <ma...@us...> - 2015-01-19 09:20:17
|
Revision: 709
http://sourceforge.net/p/pywbem/code/709
Author: maiera
Date: 2015-01-19 09:20:09 +0000 (Mon, 19 Jan 2015)
Log Message:
-----------
wbemcli.py: Added support for Windows; Cleaned up global namespace; Added pp alias for pprint back in; Made it importable as a module.
Modified Paths:
--------------
pywbem/trunk/pywbem/NEWS
pywbem/trunk/pywbem/wbemcli.py
Modified: pywbem/trunk/pywbem/NEWS
===================================================================
--- pywbem/trunk/pywbem/NEWS 2015-01-19 08:14:25 UTC (rev 708)
+++ pywbem/trunk/pywbem/NEWS 2015-01-19 09:20:09 UTC (rev 709)
@@ -212,6 +212,11 @@
* Added CIM-XML declaration support for alternative PyWBEM client based
on twisted. (Andreas Maier)
+ * Added support for Windows to wbemcli.py, by making dependency on HOME
+ environment variable optional, and adding HOMEPATH environment variable.
+ Also, cleaned up the global namespace of wbemcli.py and made it
+ importable as a module. (Andreas Maier)
+
TESTING:
* Added support for running the unit test cases without having to be in the
Modified: pywbem/trunk/pywbem/wbemcli.py
===================================================================
--- pywbem/trunk/pywbem/wbemcli.py 2015-01-19 08:14:25 UTC (rev 708)
+++ pywbem/trunk/pywbem/wbemcli.py 2015-01-19 09:20:09 UTC (rev 709)
@@ -19,101 +19,63 @@
# Author: Tim Potter <tp...@hp...>
#
-#
-# A small utility to wrap up a PyWBEM session in a Python interactive
-# console.
-#
-# Usage:
-#
-# wbemcli.py HOSTNAME [-u USERNAME -p PASSWORD] [-n namespace] [--no-ssl] \
-# [--port PORT]
-#
-# CIM operations can be executed by using the PyWBEM connection object
-# called 'cli' in the global scope. There are two sets of aliases
-# available for usage in the interpreter. For example the following
-# three commands are equivalent:
-#
-# >>> cli.EnumerateInstanceNames('SMX_ComputerSystem')
-# >>> EnumerateInstanceNames('SMX_ComputerSystem')
-# >>> ein('SMX_ComputerSystem')
-#
-# Pretty-printing of results is also available using the 'pp'
-# function. For example:
-#
-# >>> cs = ei('SMX_ComputerSystem')[0]
-# >>> pp(cs.items())
-# [(u'RequestedState', 12L),
-# (u'Dedicated', [1L]),
-# (u'StatusDescriptions', [u'System is Functional']),
-# (u'IdentifyingNumber', u'6F880AA1-F4F5-11D5-8C45-C0116FBAE02A'),
-# ...
-#
+"""A small utility to wrap up a PyWBEM session in a Python interactive
+console.
+Usage:
+ wbemcli.py HOSTNAME [-u USERNAME -p PASSWORD] [-n namespace] [--no-ssl] \
+ [--port PORT]
+
+The utility creates a ``pywbem.WBEMConnection`` object for the specified
+WBEM server location. Subsequent operatoins then use that connection.
+
+There are two sets of aliases available for usage in the interpreter. For
+example, the following two commands are equivalent:
+
+ >>> EnumerateInstanceNames('SMX_ComputerSystem')
+ >>> ein('SMX_ComputerSystem')
+
+Pretty-printing of results is also available using the 'pp'
+function. For example:
+
+ >>> cs = ei('SMX_ComputerSystem')[0]
+ >>> pp(cs.items())
+ [(u'RequestedState', 12L),
+ (u'Dedicated', [1L]),
+ (u'StatusDescriptions', [u'System is Functional']),
+ (u'IdentifyingNumber', u'6F880AA1-F4F5-11D5-8C45-C0116FBAE02A'),
+ ...
+"""
+
import os
import sys
import getpass
import errno
-from code import InteractiveConsole
-from optparse import OptionParser
+import code
+import optparse
# Conditional support of readline module
-have_readline = False
+_HAVE_READLINE = False
try:
import readline
- have_readline = True
+ _HAVE_READLINE = True
except ImportError, arg:
pass
import pywbem
-#
-# Parse command line args
-#
+# Additional symbols for use in the interactive session
+from pprint import pprint as pp
-optparser = OptionParser(
- usage='%prog HOSTNAME [-u USER -p PASS] [-n NAMESPACE] [--no-ssl]')
+__all__ = []
-# Username and password
+_CONN = None
-optparser.add_option('-u', '--user', dest='user',
- action='store', type='string',
- help='user to connect as')
+def remote_connection(argv, opts):
+ """Initiate a remote connection, via PyWBEM."""
-optparser.add_option('-p', '--password', dest='password',
- action='store', type='string',
- help='password to connect user as')
+ global _CONN
-# Change the default namespace used
-
-optparser.add_option('-n', '--namespace', dest='namespace',
- action='store', type='string', default='root/cimv2',
- help='default namespace to use')
-
-# Don't use SSL for remote connections
-
-optparser.add_option('--no-ssl', dest='no_ssl', action='store_true',
- help='don\'t use SSL')
-
-# Specify non-standard port
-
-optparser.add_option('--port', dest='port', action='store', type='int',
- help='port to connect as', default=None)
-
-# Check usage
-
-(opts, argv) = optparser.parse_args()
-
-if len(argv) != 1:
- optparser.print_usage()
- sys.exit(1)
-
-#
-# Set up a client connection
-#
-
-def remote_connection():
- """Initiate a remote connection, via PyWBEM."""
-
if argv[0][0] == '/':
url = argv[0]
else:
@@ -135,14 +97,12 @@
if opts.user is not None or opts.password is not None:
creds = (opts.user, opts.password)
- cli = pywbem.WBEMConnection(url, creds, default_namespace=opts.namespace)
+ _CONN = pywbem.WBEMConnection(url, creds, default_namespace=opts.namespace)
- cli.debug = True
+ _CONN.debug = True
- return cli
+ return _CONN
-cli = remote_connection()
-
#
# Create some convenient global functions to reduce typing
#
@@ -151,15 +111,19 @@
"""Enumerate the names of the instances of a CIM Class (including the
names of any subclasses) in the target namespace."""
- return cli.EnumerateInstanceNames(classname, namespace=namespace)
+ global _CONN
+ return _CONN.EnumerateInstanceNames(classname, namespace=namespace)
+
def EnumerateInstances(classname, namespace=None, LocalOnly=True,
DeepInheritance=True, IncludeQualifiers=False,
IncludeClassOrigin=False):
"""Enumerate instances of a CIM Class (includeing the instances of
any subclasses in the target namespace."""
- return cli.EnumerateInstances(classname,
+ global _CONN
+
+ return _CONN.EnumerateInstances(classname,
namespace=namespace,
DeepInheritance=DeepInheritance,
IncludeQualifiers=IncludeQualifiers,
@@ -171,7 +135,9 @@
"""Return a single CIM instance corresponding to the instance name
given."""
- return cli.GetInstance(instancename,
+ global _CONN
+
+ return _CONN.GetInstance(instancename,
LocalOnly=LocalOnly,
IncludeQualifiers=IncludeQualifiers,
IncludeClassOrigin=IncludeClassOrigin)
@@ -179,58 +145,77 @@
def DeleteInstance(instancename):
"""Delete a single CIM instance."""
- return cli.DeleteInstance(instancename)
+ global _CONN
+ return _CONN.DeleteInstance(instancename)
+
def ModifyInstance(*args, **kwargs):
- return cli.ModifyInstance(*args, **kwargs)
+ global _CONN
+ return _CONN.ModifyInstance(*args, **kwargs)
def CreateInstance(*args, **kwargs):
- return cli.CreateInstance(*args, **kwargs)
+ global _CONN
+ return _CONN.CreateInstance(*args, **kwargs)
def InvokeMethod(*args, **kwargs):
- return cli.InvokeMethod(*args, **kwargs)
+ global _CONN
+ return _CONN.InvokeMethod(*args, **kwargs)
def AssociatorNames(*args, **kwargs):
- return cli.AssociatorNames(*args, **kwargs)
+ global _CONN
+ return _CONN.AssociatorNames(*args, **kwargs)
def Associators(*args, **kwargs):
- return cli.Associators(*args, **kwargs)
+ global _CONN
+ return _CONN.Associators(*args, **kwargs)
def ReferenceNames(*args, **kwargs):
- return cli.ReferenceNames(*args, **kwargs)
+ global _CONN
+ return _CONN.ReferenceNames(*args, **kwargs)
def References(*args, **kwargs):
- return cli.References(*args, **kwargs)
+ global _CONN
+ return _CONN.References(*args, **kwargs)
def EnumerateClassNames(*args, **kwargs):
- return cli.EnumerateClassNames(*args, **kwargs)
+ global _CONN
+ return _CONN.EnumerateClassNames(*args, **kwargs)
def EnumerateClasses(*args, **kwargs):
- return cli.EnumerateClasses(*args, **kwargs)
+ global _CONN
+ return _CONN.EnumerateClasses(*args, **kwargs)
def GetClass(*args, **kwargs):
- return cli.GetClass(*args, **kwargs)
+ global _CONN
+ return _CONN.GetClass(*args, **kwargs)
def DeleteClass(*args, **kwargs):
- return cli.DeleteClass(*args, **kwargs)
+ global _CONN
+ return _CONN.DeleteClass(*args, **kwargs)
def ModifyClass(*args, **kwargs):
- return cli.ModifyClass(*args, **kwargs)
+ global _CONN
+ return _CONN.ModifyClass(*args, **kwargs)
def CreateClass(*args, **kwargs):
- return cli.CreateClass(*args, **kwargs)
+ global _CONN
+ return _CONN.CreateClass(*args, **kwargs)
def EnumerateQualifiers(*args, **kwargs):
- return cli.EnumerateQualifiers(*args, **kwargs)
+ global _CONN
+ return _CONN.EnumerateQualifiers(*args, **kwargs)
def GetQualifier(*args, **kwargs):
- return cli.GetQualifier(*args, **kwargs)
+ global _CONN
+ return _CONN.GetQualifier(*args, **kwargs)
def SetQualifier(*args, **kwargs):
- return cli.SetQualifier(*args, **kwargs)
+ global _CONN
+ return _CONN.SetQualifier(*args, **kwargs)
def DeleteQualifier(*args, **kwargs):
- return cli.DeleteQualifier(*args, **kwargs)
+ global _CONN
+ return _CONN.DeleteQualifier(*args, **kwargs)
# Aliases for global functions above
@@ -260,39 +245,92 @@
sq = SetQualifier
dq = DeleteQualifier
-#
-# Enter interactive console
-#
def get_banner():
+ """Return a banner message for the interactive console."""
+ global _CONN
+
result = ''
# Note how we are connected
+ result += 'Connected to %s' % _CONN.url
+ if _CONN.creds is not None:
+ result += ' as %s' % _CONN.creds[0]
- result += 'Connected to %s' % cli.url
- if cli.creds is not None:
- result += ' as %s' % cli.creds[0]
+ # Give hint about exiting. Most people exit with 'quit()' which will
+ # not return from the interact() method, and thus will not write
+ # the history.
+ result += '\nPress Ctrl-D to exit'
return result
-# Read previous command line history
-histfile = '%s/.wbemcli_history' % os.environ['HOME']
+def main():
+ """Main routine, when called as a script."""
-try:
- if have_readline:
- readline.read_history_file(histfile)
-except IOError, arg:
- if arg[0] != errno.ENOENT:
- raise
+ global _CONN
-# Interact
+ # Parse command line args
+ optparser = optparse.OptionParser(
+ usage='%prog HOSTNAME [-u USER -p PASS] [-n NAMESPACE] [--no-ssl]')
-i = InteractiveConsole(globals())
-i.interact(get_banner())
+ # Username and password
+ optparser.add_option('-u', '--user', dest='user',
+ action='store', type='string',
+ help='user to connect as')
+ optparser.add_option('-p', '--password', dest='password',
+ action='store', type='string',
+ help='password to connect user as')
-# Save command line history
+ # Change the default namespace used
+ optparser.add_option('-n', '--namespace', dest='namespace',
+ action='store', type='string', default='root/cimv2',
+ help='default namespace to use')
-if have_readline:
- readline.write_history_file(histfile)
+ # Don't use SSL for remote connections
+ optparser.add_option('--no-ssl', dest='no_ssl', action='store_true',
+ help='don\'t use SSL')
+
+ # Specify non-standard port
+ optparser.add_option('--port', dest='port', action='store', type='int',
+ help='port to connect as', default=None)
+
+ # Check usage
+ (opts, argv) = optparser.parse_args()
+
+ if len(argv) != 1:
+ optparser.print_usage()
+ sys.exit(1)
+
+ # Set up a client connection
+ _CONN = remote_connection(argv, opts)
+
+ # Determine file path of history file
+ home_dir = '.'
+ if 'HOME' in os.environ:
+ home_dir = os.environ['HOME'] # Linux
+ elif 'HOMEPATH' in os.environ:
+ home_dir = os.environ['HOMEPATH'] # Windows
+ histfile = '%s/.wbemcli_history' % home_dir
+
+ # Read previous command line history
+ if _HAVE_READLINE:
+ try:
+ readline.read_history_file(histfile)
+ except IOError, arg:
+ if arg[0] != errno.ENOENT:
+ raise
+
+ # Interact
+ i = code.InteractiveConsole(globals())
+ i.interact(get_banner())
+
+ # Save command line history
+ if _HAVE_READLINE:
+ readline.write_history_file(histfile)
+
+ return 0
+
+if __name__ == '__main__':
+ exit(main())
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <ma...@us...> - 2015-01-19 08:14:28
|
Revision: 708
http://sourceforge.net/p/pywbem/code/708
Author: maiera
Date: 2015-01-19 08:14:25 +0000 (Mon, 19 Jan 2015)
Log Message:
-----------
Cleaned up public symbols and wildcard symbols.
Modified Paths:
--------------
pywbem/trunk/pywbem/NEWS
pywbem/trunk/pywbem/cim_http.py
pywbem/trunk/pywbem/cim_obj.py
pywbem/trunk/pywbem/cim_operations.py
pywbem/trunk/pywbem/cim_types.py
pywbem/trunk/pywbem/cim_xml.py
pywbem/trunk/pywbem/cimxml_parse.py
pywbem/trunk/pywbem/mof_compiler.py
pywbem/trunk/pywbem/tupleparse.py
pywbem/trunk/pywbem/tupletree.py
pywbem/trunk/pywbem/twisted_client.py
Modified: pywbem/trunk/pywbem/NEWS
===================================================================
--- pywbem/trunk/pywbem/NEWS 2015-01-16 22:57:15 UTC (rev 707)
+++ pywbem/trunk/pywbem/NEWS 2015-01-19 08:14:25 UTC (rev 708)
@@ -1,4 +1,4 @@
-pywbem-0.8.0-dev.r707
+pywbem-0.8.0-dev.r708
ENHANCEMENTS:
@@ -60,6 +60,19 @@
the standard. The new argument is optional, making this a backwards
compatible change of InvokeMethod(). (Andreas Maier)
+ * Cleaned up the public symbols of each module by making symbols private
+ that are used only internally. Specifically, the following symbols have
+ been made private: In cimxml_parse: _get_required_attribute,
+ _get_attribute, _get_end_event, _is_start, _is_end. In cim_xml: _text
+ (was: Text). (Andreas Maier)
+
+ * Cleaned up symbols imported by wildcard import by defining __all__ in
+ each module with only the public symbols defined in that module (removing
+ any symbols imported into the module), except for the following modules
+ which define less than the complete set of public symbols in their
+ __all__: mof_compiler, twisted_client, tupleparse, cimxml_parse,
+ cim_http. (Andreas Maier)
+
BUG FIXES:
* Fix syntax error in CIM DTDVERSION error path. Allow KEYVALUE
Modified: pywbem/trunk/pywbem/cim_http.py
===================================================================
--- pywbem/trunk/pywbem/cim_http.py 2015-01-16 22:57:15 UTC (rev 707)
+++ pywbem/trunk/pywbem/cim_http.py 2015-01-19 08:14:25 UTC (rev 708)
@@ -47,6 +47,8 @@
from pywbem import cim_obj
+__all__ = ['Error', 'AuthError', 'wbem_request', 'get_object_header']
+
class Error(Exception):
"""This exception is raised when a transport error occurs."""
pass
Modified: pywbem/trunk/pywbem/cim_obj.py
===================================================================
--- pywbem/trunk/pywbem/cim_obj.py 2015-01-16 22:57:15 UTC (rev 707)
+++ pywbem/trunk/pywbem/cim_obj.py 2015-01-19 08:14:25 UTC (rev 708)
@@ -40,6 +40,11 @@
from pywbem import cim_xml, cim_types
+__all__ = ['NocaseDict', 'cmpname', 'CIMClassName', 'CIMProperty',
+ 'CIMInstanceName', 'CIMInstance', 'CIMClass', 'CIMMethod',
+ 'CIMParameter', 'CIMQualifier', 'CIMQualifierDeclaration',
+ 'tocimxml', 'tocimobj', 'byname']
+
class NocaseDict(object):
"""
Yet another implementation of a case-insensitive dictionary.
Modified: pywbem/trunk/pywbem/cim_operations.py
===================================================================
--- pywbem/trunk/pywbem/cim_operations.py 2015-01-16 22:57:15 UTC (rev 707)
+++ pywbem/trunk/pywbem/cim_operations.py 2015-01-19 08:14:25 UTC (rev 708)
@@ -40,6 +40,10 @@
from pywbem.cim_obj import CIMInstance, CIMInstanceName, CIMClass, \
CIMClassName, NocaseDict
+__all__ = ['DEFAULT_NAMESPACE', 'CIMError', 'WBEMConnection', 'is_subclass',
+ 'PegasusUDSConnection', 'SFCBUDSConnection',
+ 'OpenWBEMUDSConnection']
+
DEFAULT_NAMESPACE = 'root/cimv2'
Modified: pywbem/trunk/pywbem/cim_types.py
===================================================================
--- pywbem/trunk/pywbem/cim_types.py 2015-01-16 22:57:15 UTC (rev 707)
+++ pywbem/trunk/pywbem/cim_types.py 2015-01-19 08:14:25 UTC (rev 708)
@@ -62,6 +62,11 @@
from datetime import tzinfo, datetime, timedelta
import re
+__all__ = ['MinutesFromUTC', 'CIMType', 'CIMDateTime', 'CIMInt', 'Uint8',
+ 'Sint8', 'Uint16', 'Sint16', 'Uint32', 'Sint32', 'Uint64', 'Sint64',
+ 'CIMFloat', 'Real32', 'Real64', 'cimtype', 'type_from_name',
+ 'atomic_to_cim_xml']
+
class MinutesFromUTC(tzinfo):
"""
Modified: pywbem/trunk/pywbem/cim_xml.py
===================================================================
--- pywbem/trunk/pywbem/cim_xml.py 2015-01-16 22:57:15 UTC (rev 707)
+++ pywbem/trunk/pywbem/cim_xml.py 2015-01-19 08:14:25 UTC (rev 708)
@@ -53,8 +53,28 @@
import xml.dom.minidom
from xml.dom.minidom import Element
-def Text(data):
- # pylint: disable=invalid-name
+__all__ = ['CIMElement', 'CIM', 'DECLARATION', 'DECLGROUP',
+ 'DECLGROUP_WITHNAME', 'DECLGROUP_WITHPATH', 'QUALIFIER_DECLARATION',
+ 'SCOPE', 'VALUE', 'VALUE_ARRAY', 'VALUE_REFERENCE',
+ 'VALUE_REFARRAY', 'VALUE_OBJECT', 'VALUE_NAMEDINSTANCE',
+ 'VALUE_NAMEDOBJECT', 'VALUE_OBJECTWITHLOCALPATH',
+ 'VALUE_OBJECTWITHPATH', 'VALUE_NULL', 'NAMESPACEPATH',
+ 'LOCALNAMESPACEPATH', 'HOST', 'NAMESPACE', 'CLASSPATH',
+ 'LOCALCLASSPATH', 'CLASSNAME', 'INSTANCEPATH', 'LOCALINSTANCEPATH',
+ 'INSTANCENAME', 'OBJECTPATH', 'KEYBINDING', 'KEYVALUE', 'CLASS',
+ 'INSTANCE', 'QUALIFIER', 'PROPERTY', 'PROPERTY_ARRAY',
+ 'PROPERTY_REFERENCE', 'METHOD', 'PARAMETER', 'PARAMETER_REFERENCE',
+ 'PARAMETER_ARRAY', 'PARAMETER_REFARRAY',
+ 'TABLECELL_DECLARATION', 'TABLECELL_REFERENCE',
+ 'TABLEROW_DECLARATION', 'TABLE','TABLEROW',
+ 'MESSAGE', 'MULTIREQ', 'MULTIEXPREQ', 'SIMPLEREQ', 'SIMPLEEXPREQ',
+ 'IMETHODCALL', 'METHODCALL', 'EXPMETHODCALL', 'PARAMVALUE',
+ 'IPARAMVALUE', 'EXPPARAMVALUE', 'MULTIRSP', 'MULTIEXPRSP',
+ 'SIMPLERSP', 'SIMPLEEXPRSP', 'METHODRESPONSE', 'EXPMETHODRESPONSE',
+ 'IMETHODRESPONSE', 'ERROR', 'RETURNVALUE', 'IRETURNVALUE',
+ 'RESPONSEDESTINATION', 'SIMPLEREQACK']
+
+def _text(data):
"""Grr. The API for the minidom text node function has changed in
Python 2.3. This function allows the code to run under older
versions of the intepreter."""
@@ -265,7 +285,7 @@
def __init__(self, pcdata):
Element.__init__(self, 'VALUE')
if pcdata is not None:
- self.appendChild(Text(pcdata))
+ self.appendChild(_text(pcdata))
class VALUE_ARRAY(CIMElement):
# pylint: disable=invalid-name
@@ -439,7 +459,7 @@
def __init__(self, pcdata):
Element.__init__(self, 'HOST')
- self.appendChild(Text(pcdata))
+ self.appendChild(_text(pcdata))
class NAMESPACE(CIMElement):
# pylint: disable=invalid-name
@@ -614,7 +634,7 @@
self.setOptionalAttribute('TYPE', cim_type)
if data != None:
- self.appendChild(Text(data))
+ self.appendChild(_text(data))
# Object definition elements
Modified: pywbem/trunk/pywbem/cimxml_parse.py
===================================================================
--- pywbem/trunk/pywbem/cimxml_parse.py 2015-01-16 22:57:15 UTC (rev 707)
+++ pywbem/trunk/pywbem/cimxml_parse.py 2015-01-19 08:14:25 UTC (rev 708)
@@ -25,6 +25,8 @@
from pywbem.cim_obj import CIMInstance, CIMInstanceName, CIMQualifier, \
CIMProperty
+__all__ = ['ParseError', 'make_parser', 'parse_any']
+
class ParseError(Exception):
"""This exception is raised when there is a validation error detected
by the parser."""
@@ -34,7 +36,7 @@
# Helper functions
#
-def get_required_attribute(node, attr):
+def _get_required_attribute(node, attr):
"""Return an attribute by name. Throw an exception if not present."""
if not node.hasAttribute(attr):
@@ -43,7 +45,7 @@
return node.getAttribute(attr)
-def get_attribute(node, attr):
+def _get_attribute(node, attr):
"""Return an attribute by name, or None if not present."""
if node.hasAttribute(attr):
@@ -51,7 +53,7 @@
return None
-def get_end_event(parser, tagName):
+def _get_end_event(parser, tagName):
"""Check that the next event is the end of a particular tag."""
(event, node) = parser.next()
@@ -60,11 +62,11 @@
raise ParseError(
'Expecting %s end tag, got %s %s' % (tagName, event, node.tagName))
-def is_start(event, node, tagName):
+def _is_start(event, node, tagName):
"""Return true if (event, node) is a start event for tagname."""
return event == pulldom.START_ELEMENT and node.tagName == tagName
-def is_end(event, node, tagName):
+def _is_end(event, node, tagName):
"""Return true if (event, node) is an end event for tagname."""
return event == pulldom.END_ELEMENT and node.tagName == tagName
@@ -126,7 +128,7 @@
(next_event, next_node) = parser.next()
- if not is_end(next_event, next_node, 'VALUE'):
+ if not _is_end(next_event, next_node, 'VALUE'):
raise ParseError('Expecting end VALUE')
return value
@@ -139,7 +141,7 @@
(next_event, next_node) = parser.next()
- if is_start(next_event, next_node, 'VALUE'):
+ if _is_start(next_event, next_node, 'VALUE'):
value_array.append(parse_value(parser, next_event, next_node))
@@ -147,10 +149,10 @@
(next_event, next_node) = parser.next()
- if is_end(next_event, next_node, 'VALUE.ARRAY'):
+ if _is_end(next_event, next_node, 'VALUE.ARRAY'):
break
- if is_start(next_event, next_node, 'VALUE'):
+ if _is_start(next_event, next_node, 'VALUE'):
value_array.append(parse_value(parser, next_event, next_node))
else:
raise ParseError('Expecting VALUE element')
@@ -164,29 +166,29 @@
(next_event, next_node) = parser.next()
- if is_start(next_event, next_node, 'CLASSPATH'):
+ if _is_start(next_event, next_node, 'CLASSPATH'):
result = parse_classpath(parser, next_event, next_node)
- elif is_start(next_event, next_node, 'LOCALCLASSPATH'):
+ elif _is_start(next_event, next_node, 'LOCALCLASSPATH'):
result = parse_localclasspath(parser, next_event, next_node)
- elif is_start(next_event, next_node, 'CLASSNAME'):
+ elif _is_start(next_event, next_node, 'CLASSNAME'):
result = parse_classname(parser, next_event, next_node)
- elif is_start(next_event, next_node, 'INSTANCEPATH'):
+ elif _is_start(next_event, next_node, 'INSTANCEPATH'):
result = parse_instancepath(parser, next_event, next_node)
- elif is_start(next_event, next_node, 'LOCALINSTANCEPATH'):
+ elif _is_start(next_event, next_node, 'LOCALINSTANCEPATH'):
result = parse_localinstancepath(parser, next_event, next_node)
- elif is_start(next_event, next_node, 'INSTANCENAME'):
+ elif _is_start(next_event, next_node, 'INSTANCENAME'):
result = parse_instancename(parser, next_event, next_node)
else:
raise ParseError('Expecting (CLASSPATH | LOCALCLASSPATH | CLASSNAME '
'| INSTANCEPATH | LOCALINSTANCEPATH | INSTANCENAME)')
- get_end_event(parser, 'VALUE.REFERENCE')
+ _get_end_event(parser, 'VALUE.REFERENCE')
return result
@@ -210,21 +212,21 @@
(next_event, next_node) = parser.next()
- if not is_start(next_event, next_node, 'HOST'):
+ if not _is_start(next_event, next_node, 'HOST'):
raise ParseError('Expecting HOST')
host = parse_host(parser, next_event, next_node)
(next_event, next_node) = parser.next()
- if not is_start(next_event, next_node, 'LOCALNAMESPACEPATH'):
+ if not _is_start(next_event, next_node, 'LOCALNAMESPACEPATH'):
raise ParseError('Expecting LOCALNAMESPACEPATH')
namespacepath = parse_localnamespacepath(parser, next_event, next_node)
(next_event, next_node) = parser.next()
- if not is_end(next_event, next_node, 'NAMESPACEPATH'):
+ if not _is_end(next_event, next_node, 'NAMESPACEPATH'):
raise ParseError('Expecting end NAMESPACEPATH')
return (host, namespacepath)
@@ -237,7 +239,7 @@
namespaces = []
- if not is_start(next_event, next_node, 'NAMESPACE'):
+ if not _is_start(next_event, next_node, 'NAMESPACE'):
print next_event, next_node
raise ParseError('Expecting NAMESPACE')
@@ -247,10 +249,10 @@
(next_event, next_node) = parser.next()
- if is_end(next_event, next_node, 'LOCALNAMESPACEPATH'):
+ if _is_end(next_event, next_node, 'LOCALNAMESPACEPATH'):
break
- if is_start(next_event, next_node, 'NAMESPACE'):
+ if _is_start(next_event, next_node, 'NAMESPACE'):
namespaces.append(parse_namespace(parser, next_event, next_node))
else:
raise ParseError('Expecting NAMESPACE')
@@ -271,7 +273,7 @@
(next_event, next_node) = parser.next()
- if not is_end(next_event, next_node, 'HOST'):
+ if not _is_end(next_event, next_node, 'HOST'):
raise ParseError('Expecting end HOST')
return host
@@ -283,11 +285,11 @@
def parse_namespace(parser, event, node):
- name = get_required_attribute(node, 'NAME')
+ name = _get_required_attribute(node, 'NAME')
(next_event, next_node) = parser.next()
- if not is_end(next_event, next_node, 'NAMESPACE'):
+ if not _is_end(next_event, next_node, 'NAMESPACE'):
raise ParseError('Expecting end NAMESPACE')
return name
@@ -307,14 +309,14 @@
(next_event, next_node) = parser.next()
- if not is_start(next_event, next_node, 'NAMESPACEPATH'):
+ if not _is_start(next_event, next_node, 'NAMESPACEPATH'):
raise ParseError('Expecting NAMESPACEPATH')
host, namespacepath = parse_namespacepath(parser, next_event, next_node)
(next_event, next_node) = parser.next()
- if not is_start(next_event, next_node, 'INSTANCENAME'):
+ if not _is_start(next_event, next_node, 'INSTANCENAME'):
print next_event, next_node
raise ParseError('Expecting INSTANCENAME')
@@ -331,14 +333,14 @@
(next_event, next_node) = parser.next()
- if not is_start(next_event, next_node, 'LOCALNAMESPACEPATH'):
+ if not _is_start(next_event, next_node, 'LOCALNAMESPACEPATH'):
raise ParseError('Expecting LOCALNAMESPACEPATH')
namespacepath = parse_localnamespacepath(parser, next_event, next_node)
(next_event, next_node) = parser.next()
- if not is_start(next_event, next_node, 'INSTANCENAME'):
+ if not _is_start(next_event, next_node, 'INSTANCENAME'):
raise ParseError('Expecting INSTANCENAME')
instancename = parse_instancename(parser, next_event, next_node)
@@ -354,12 +356,12 @@
def parse_instancename(parser, event, node):
- classname = get_required_attribute(node, 'CLASSNAME')
+ classname = _get_required_attribute(node, 'CLASSNAME')
keybindings = []
(next_event, next_node) = parser.next()
- if is_start(next_event, next_node, 'KEYBINDING'):
+ if _is_start(next_event, next_node, 'KEYBINDING'):
keybindings.append(parse_keybinding(parser, next_event, next_node))
@@ -367,22 +369,22 @@
(next_event, next_node) = parser.next()
- if is_end(next_event, next_node, 'INSTANCENAME'):
+ if _is_end(next_event, next_node, 'INSTANCENAME'):
break
- if is_start(next_event, next_node, 'KEYBINDING'):
+ if _is_start(next_event, next_node, 'KEYBINDING'):
keybindings.append(
parse_keybinding(parser, next_event, next_node))
else:
raise ParseError('Expecting KEYBINDING element')
- if is_end(next_event, next_node, 'INSTANCENAME'):
+ if _is_end(next_event, next_node, 'INSTANCENAME'):
pass
- elif is_start(next_event, next_node, 'KEYVALUE'):
+ elif _is_start(next_event, next_node, 'KEYVALUE'):
keybindings.append(('', parse_keyvalue(parser, next_event, next_node)))
- elif is_start(next_event, next_node, 'VALUE.REFERENCE'):
+ elif _is_start(next_event, next_node, 'VALUE.REFERENCE'):
keybindings.append(
parse_value_reference(parser, next_event, next_node))
@@ -401,22 +403,22 @@
def parse_keybinding(parser, event, node):
- name = get_required_attribute(node, 'NAME')
+ name = _get_required_attribute(node, 'NAME')
(next_event, next_node) = parser.next()
- if is_start(next_event, next_node, 'KEYVALUE'):
+ if _is_start(next_event, next_node, 'KEYVALUE'):
keyvalue = parse_keyvalue(parser, next_event, next_node)
result = (name, keyvalue)
- elif is_start(next_event, next_node, 'VALUE.REFERENCE'):
+ elif _is_start(next_event, next_node, 'VALUE.REFERENCE'):
value_reference = parse_value_reference(parser, next_event, next_node)
result = (name, value_reference)
else:
raise ParseError('Expecting KEYVALUE or VALUE.REFERENCE element')
- get_end_event(parser, 'KEYBINDING')
+ _get_end_event(parser, 'KEYBINDING')
return result
@@ -428,8 +430,8 @@
def parse_keyvalue(parser, event, node):
- valuetype = get_required_attribute(node, 'VALUETYPE')
- type = get_attribute(node, 'TYPE')
+ valuetype = _get_required_attribute(node, 'VALUETYPE')
+ type = _get_attribute(node, 'TYPE')
(next_event, next_node) = parser.next()
@@ -476,7 +478,7 @@
else:
raise ParseError('Invalid VALUETYPE')
- get_end_event(parser, 'KEYVALUE')
+ _get_end_event(parser, 'KEYVALUE')
return value
@@ -500,14 +502,14 @@
def parse_instance(parser, event, node):
- classname = get_required_attribute(node, 'CLASSNAME')
+ classname = _get_required_attribute(node, 'CLASSNAME')
properties = []
qualifiers = []
(next_event, next_node) = parser.next()
- if is_start(next_event, next_node, 'QUALIFIER'):
+ if _is_start(next_event, next_node, 'QUALIFIER'):
qualifiers.append(parse_qualifier(parser, next_event, next_node))
@@ -515,13 +517,13 @@
(next_event, next_node) = parser.next()
- if is_start(next_event, next_node, 'PROPERTY') or \
- is_start(next_event, next_node, 'PROPERTY.ARRAY') or \
- is_start(next_event, next_node, 'PROPERTY.REFERENCE') or \
- is_end(next_event, next_node, 'INSTANCE'):
+ if _is_start(next_event, next_node, 'PROPERTY') or \
+ _is_start(next_event, next_node, 'PROPERTY.ARRAY') or \
+ _is_start(next_event, next_node, 'PROPERTY.REFERENCE') or \
+ _is_end(next_event, next_node, 'INSTANCE'):
break
- if is_start(next_event, next_node, 'QUALIFIER'):
+ if _is_start(next_event, next_node, 'QUALIFIER'):
qualifiers.append(
parse_qualifier(parser, next_event, next_node))
else:
@@ -529,17 +531,17 @@
while 1:
- if is_end(next_event, next_node, 'INSTANCE'):
+ if _is_end(next_event, next_node, 'INSTANCE'):
break
- if is_start(next_event, next_node, 'PROPERTY'):
+ if _is_start(next_event, next_node, 'PROPERTY'):
properties.append(parse_property(parser, next_event, next_node))
- elif is_start(next_event, next_node, 'PROPERTY.ARRAY'):
+ elif _is_start(next_event, next_node, 'PROPERTY.ARRAY'):
properties.append(
parse_property_array(parser, next_event, next_node))
- elif is_start(next_event, next_node, 'PROPERTY.REFERENCE'):
+ elif _is_start(next_event, next_node, 'PROPERTY.REFERENCE'):
properties.append(
parse_property_reference(parser, next_event, next_node))
else:
@@ -548,7 +550,7 @@
(next_event, next_node) = parser.next()
- if not is_end(next_event, next_node, 'INSTANCE'):
+ if not _is_end(next_event, next_node, 'INSTANCE'):
raise ParseError('Expecting end INSTANCE')
return CIMInstance(
@@ -567,25 +569,25 @@
def parse_qualifier(parser, event, node):
- name = get_required_attribute(node, 'NAME')
- type = get_required_attribute(node, 'TYPE')
- propagated = get_attribute(node, 'PROPAGATED')
+ name = _get_required_attribute(node, 'NAME')
+ type = _get_required_attribute(node, 'TYPE')
+ propagated = _get_attribute(node, 'PROPAGATED')
(next_event, next_node) = parser.next()
- if is_end(next_event, next_node, 'QUALIFIER'):
+ if _is_end(next_event, next_node, 'QUALIFIER'):
return CIMQualifier(name, None, type=type)
- if is_start(next_event, next_node, 'VALUE'):
+ if _is_start(next_event, next_node, 'VALUE'):
value = parse_value(parser, next_event, next_node)
- elif is_start(next_event, next_node, 'VALUE.ARRAY'):
+ elif _is_start(next_event, next_node, 'VALUE.ARRAY'):
value = parse_value_array(parser, next_event, next_node)
else:
raise ParseError('Expecting (VALUE | VALUE.ARRAY)')
result = CIMQualifier(name, cim_obj.tocimobj(type, value))
- get_end_event(parser, 'QUALIFIER')
+ _get_end_event(parser, 'QUALIFIER')
return result
@@ -600,18 +602,18 @@
def parse_property(parser, event, node):
- name = get_required_attribute(node, 'NAME')
- type = get_required_attribute(node, 'TYPE')
+ name = _get_required_attribute(node, 'NAME')
+ type = _get_required_attribute(node, 'TYPE')
- class_origin = get_attribute(node, 'CLASSORIGIN')
- propagated = get_attribute(node, 'PROPAGATED')
+ class_origin = _get_attribute(node, 'CLASSORIGIN')
+ propagated = _get_attribute(node, 'PROPAGATED')
qualifiers = []
value = None
(next_event, next_node) = parser.next()
- if is_start(next_event, next_node, 'QUALIFIER'):
+ if _is_start(next_event, next_node, 'QUALIFIER'):
qualifiers.append(parse_qualifier(parser, next_event, next_node))
@@ -619,21 +621,21 @@
(next_event, next_node) = parser.next()
- if is_start(next_event, next_node, 'VALUE'):
+ if _is_start(next_event, next_node, 'VALUE'):
break
- if is_start(next_event, next_node, 'QUALIFIER'):
+ if _is_start(next_event, next_node, 'QUALIFIER'):
qualifiers.append(
parse_qualifier(parser, next_event, next_node))
else:
raise ParseError('Expecting QUALIFIER')
- if is_start(next_event, next_node, 'VALUE'):
+ if _is_start(next_event, next_node, 'VALUE'):
value = parse_value(parser, next_event, next_node)
(next_event, next_node) = parser.next()
- if not is_end(next_event, next_node, 'PROPERTY'):
+ if not _is_end(next_event, next_node, 'PROPERTY'):
raise ParseError('Expecting end PROPERTY')
return CIMProperty(
@@ -656,19 +658,19 @@
def parse_property_array(parser, event, node):
- name = get_required_attribute(node, 'NAME')
- type = get_required_attribute(node, 'TYPE')
+ name = _get_required_attribute(node, 'NAME')
+ type = _get_required_attribute(node, 'TYPE')
- array_size = get_attribute(node, 'ARRAYSIZE')
- class_origin = get_attribute(node, 'CLASSORIGIN')
- propagated = get_attribute(node, 'PROPAGATED')
+ array_size = _get_attribute(node, 'ARRAYSIZE')
+ class_origin = _get_attribute(node, 'CLASSORIGIN')
+ propagated = _get_attribute(node, 'PROPAGATED')
qualifiers = []
value = None
(next_event, next_node) = parser.next()
- if is_start(next_event, next_node, 'QUALIFIER'):
+ if _is_start(next_event, next_node, 'QUALIFIER'):
qualifiers.append(parse_qualifier(parser, next_event, next_node))
@@ -676,21 +678,21 @@
(next_event, next_node) = parser.next()
- if is_start(next_event, next_node, 'VALUE.ARRAY'):
+ if _is_start(next_event, next_node, 'VALUE.ARRAY'):
break
- if is_start(next_event, next_node, 'QUALIFIER'):
+ if _is_start(next_event, next_node, 'QUALIFIER'):
qualifiers.append(
parse_qualifier(parser, next_event, next_node))
else:
raise ParseError('Expecting QUALIFIER')
- if is_start(next_event, next_node, 'VALUE.ARRAY'):
+ if _is_start(next_event, next_node, 'VALUE.ARRAY'):
value = parse_value_array(parser, next_event, next_node)
(next_event, next_node) = parser.next()
- if not is_end(next_event, next_node, 'PROPERTY.ARRAY'):
+ if not _is_end(next_event, next_node, 'PROPERTY.ARRAY'):
raise ParseError('Expecting end PROPERTY.ARRAY')
return CIMProperty(
@@ -712,17 +714,17 @@
def parse_property_reference(parser, event, node):
- name = get_required_attribute(node, 'NAME')
+ name = _get_required_attribute(node, 'NAME')
- class_origin = get_attribute(node, 'CLASSORIGIN')
- propagated = get_attribute(node, 'PROPAGATED')
+ class_origin = _get_attribute(node, 'CLASSORIGIN')
+ propagated = _get_attribute(node, 'PROPAGATED')
qualifiers = []
value = None
(next_event, next_node) = parser.next()
- if is_start(next_event, next_node, 'QUALIFIER'):
+ if _is_start(next_event, next_node, 'QUALIFIER'):
qualifiers.append(parse_qualifier(parser, next_event, next_node))
@@ -730,22 +732,22 @@
(next_event, next_node) = parser.next()
- if is_start(next_event, next_node, 'VALUE.REFERENCE'):
+ if _is_start(next_event, next_node, 'VALUE.REFERENCE'):
break
- if is_start(next_event, next_node, 'QUALIFIER'):
+ if _is_start(next_event, next_node, 'QUALIFIER'):
qualifiers.append(
parse_qualifier(parser, next_event, next_node))
else:
raise ParseError('Expecting QUALIFIER')
- if is_start(next_event, next_node, 'VALUE.REFERENCE'):
+ if _is_start(next_event, next_node, 'VALUE.REFERENCE'):
value = parse_value_reference(parser, next_event, next_node)
(next_event, next_node) = parser.next()
- if not is_end(next_event, next_node, 'PROPERTY.REFERENCE'):
+ if not _is_end(next_event, next_node, 'PROPERTY.REFERENCE'):
raise ParseError('Expecting end PROPERTY.REFERENCE')
return CIMProperty(
Modified: pywbem/trunk/pywbem/mof_compiler.py
===================================================================
--- pywbem/trunk/pywbem/mof_compiler.py 2015-01-16 22:57:15 UTC (rev 707)
+++ pywbem/trunk/pywbem/mof_compiler.py 2015-01-19 08:14:25 UTC (rev 708)
@@ -30,6 +30,8 @@
from pywbem.cim_operations import CIMError, WBEMConnection
from pywbem.cim_constants import *
+__all__ = ['MOFParseError', 'MOFWBEMConnection', 'MOFCompiler']
+
_optimize = 1
_tabmodule = 'mofparsetab'
_lextab = 'moflextab'
Modified: pywbem/trunk/pywbem/tupleparse.py
===================================================================
--- pywbem/trunk/pywbem/tupleparse.py 2015-01-16 22:57:15 UTC (rev 707)
+++ pywbem/trunk/pywbem/tupleparse.py 2015-01-19 08:14:25 UTC (rev 708)
@@ -84,6 +84,8 @@
CIMClassName, CIMProperty, CIMMethod, \
CIMParameter, CIMQualifier, CIMQualifierDeclaration
+__all__ = ['ParseError', 'parse_cim', 'parse_any']
+
class ParseError(Exception):
"""This exception is raised when there is a validation error detected
by the parser."""
Modified: pywbem/trunk/pywbem/tupletree.py
===================================================================
--- pywbem/trunk/pywbem/tupletree.py 2015-01-16 22:57:15 UTC (rev 707)
+++ pywbem/trunk/pywbem/tupletree.py 2015-01-19 08:14:25 UTC (rev 708)
@@ -50,6 +50,8 @@
from types import StringTypes
import xml.dom.minidom
+__all__ = ['dom_to_tupletree', 'xml_to_tupletree']
+
def dom_to_tupletree(node):
"""Convert a DOM object to a pyRXP-style tuple tree.
Modified: pywbem/trunk/pywbem/twisted_client.py
===================================================================
--- pywbem/trunk/pywbem/twisted_client.py 2015-01-16 22:57:15 UTC (rev 707)
+++ pywbem/trunk/pywbem/twisted_client.py 2015-01-19 08:14:25 UTC (rev 708)
@@ -45,6 +45,12 @@
from pywbem.cim_operations import CIMError
from pywbem.cim_types import CIMDateTime
+__all__ = ['WBEMClient', 'WBEMClientFactory', 'EnumerateInstances',
+ 'EnumerateInstanceNames', 'GetInstance', 'DeleteInstance',
+ 'CreateInstance', 'ModifyInstance', 'EnumerateClassNames',
+ 'EnumerateClasses', 'GetClass', 'Associators', 'AssociatorNames',
+ 'References', 'ReferenceNames', 'InvokeMethod', 'ExecQuery']
+
class WBEMClient(http.HTTPClient):
"""A HTTPClient subclass that handles WBEM requests."""
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <ma...@us...> - 2015-01-16 22:57:24
|
Revision: 707
http://sourceforge.net/p/pywbem/code/707
Author: maiera
Date: 2015-01-16 22:57:15 +0000 (Fri, 16 Jan 2015)
Log Message:
-----------
Fixed bug 22: Improved parsing of URLs to be correct for IPv6.
Added testcases for URL parsing.
Modified Paths:
--------------
pywbem/trunk/pywbem/NEWS
pywbem/trunk/pywbem/cim_http.py
Added Paths:
-----------
pywbem/trunk/testsuite/test_cim_http.py
Modified: pywbem/trunk/pywbem/NEWS
===================================================================
--- pywbem/trunk/pywbem/NEWS 2015-01-16 22:55:25 UTC (rev 706)
+++ pywbem/trunk/pywbem/NEWS 2015-01-16 22:57:15 UTC (rev 707)
@@ -1,4 +1,4 @@
-pywbem-0.8.0-dev.r704
+pywbem-0.8.0-dev.r707
ENHANCEMENTS:
@@ -105,10 +105,8 @@
Note: The CIM-XML supported by this fix does not conform to DSP0201 so
far. Further fixes are pending. (Jan Safranek)
- * Fixed parsing errors for connection URLs with IPv6 addresses.
- Note: The parsing support does not address all issues with IPv6 addresses,
- and it does not support zone indexes (aka scope IDs). Further fixes are
- pending. (Peter Hatina)
+ * Fixed parsing errors for connection URLs with IPv6 addresses, including
+ zone indexes (aka scope IDs). (Peter Hatina, Andreas Maier)
* Fixed the hard coded socket addressing family used for HTTPS that was
incorrect in some IPv6 cases, by determining it dynamically.
Modified: pywbem/trunk/pywbem/cim_http.py
===================================================================
--- pywbem/trunk/pywbem/cim_http.py 2015-01-16 22:55:25 UTC (rev 706)
+++ pywbem/trunk/pywbem/cim_http.py 2015-01-16 22:57:15 UTC (rev 707)
@@ -56,36 +56,82 @@
pass
def parse_url(url):
- """Return a tuple of (host, port, ssl) from the URL parameter.
- The returned port defaults to 5988 if not specified. SSL supports
- defaults to False if not specified."""
+ """Return a tuple of ``(host, port, ssl)`` from the URL specified in the
+ ``url`` parameter.
- host = url # Defaults
- port = 5988
- ssl = False
+ The returned ``ssl`` item is a boolean indicating the use of SSL, and is
+ recognized from the URL scheme (http vs. https). If none of these schemes
+ is specified in the URL, the returned value defaults to False
+ (non-SSL/http).
- if re.match("https", url): # Set SSL if specified
- ssl = True
- port = 5989
+ The returned ``port`` item is the port number, as an integer. If there is
+ no port number specified in the URL, the returned value defaults to 5988
+ for non-SSL/http, and to 5989 for SSL/https.
- m = re.search("^https?://", url) # Eat protocol name
+ The returned ``host`` item is the host portion of the URL, as a string.
+ The host portion may be specified in the URL as a short or long host name,
+ dotted IPv4 address, or bracketed IPv6 address with or without zone index
+ (aka scope ID). An IPv6 address is converted from the RFC6874 URI syntax
+ to the RFC4007 text representation syntax before being returned, by
+ removing the brackets and converting the zone index (if present) from
+ "-eth0" to "%eth0".
+
+ Examples for valid URLs can be found in the test program
+ `testsuite/test_cim_http.py`.
+ """
+
+ default_port_http = 5988 # default port for http
+ default_port_https = 5989 # default port for https
+ default_ssl = False # default SSL use (for no or unknown scheme)
+
+ # Look for scheme.
+ m = re.match(r"^(https?)://(.*)$", url, re.I)
if m:
- host = url[len(m.group(0)):]
+ _scheme = m.group(1).lower()
+ hostport = m.group(2)
+ if _scheme == 'https':
+ ssl = True
+ else: # will be 'http'
+ ssl = False
+ else:
+ # The URL specified no scheme (or a scheme other than the expected
+ # schemes, but we don't check)
+ ssl = default_ssl
+ hostport = url
- # IPv6 with/without port
- m = re.match("^\[?([0-9A-Fa-f:]*)\]?(:([0-9]*))?$", host)
+ # Remove trailing path segments, if any.
+ # Having URL components other than just slashes (e.g. '#' or '?') is not
+ # allowed (but we don't check).
+ m = hostport.find("/")
+ if m >= 0:
+ hostport = hostport[0:m]
+
+ # Look for port.
+ # This regexp also works for (colon-separated) IPv6 addresses, because they
+ # must be bracketed in a URL.
+ m = re.search(r":([0-9]+)$", hostport)
if m:
+ host = hostport[0:m.start(0)]
+ port = int(m.group(1))
+ else:
+ host = hostport
+ port = default_port_https if ssl else default_port_http
+
+ # Reformat IPv6 addresses from RFC6874 URI syntax to RFC4007 text
+ # representation syntax:
+ # - Remove the brackets.
+ # - Convert the zone index (aka scope ID) from "-eth0" to "%eth0".
+ # Note on the regexp below: The first group needs the '?' after '.+' to
+ # become non-greedy; in greedy mode, the optional second group would never
+ # be matched.
+ m = re.match(r"^\[(.+?)(?:-(.+))?\]$", host)
+ if m:
+ # It is an IPv6 address
host = m.group(1)
- port_tmp = m.group(3)
- if port_tmp:
- port = int(port_tmp)
- return host, port, ssl
+ if m.group(2) != None:
+ # The zone index is present
+ host += "%" + m.group(2)
- s = string.split(host, ":") # Set port number
- if len(s) != 1:
- host = s[0]
- port = int(s[1])
-
return host, port, ssl
def get_default_ca_certs():
Added: pywbem/trunk/testsuite/test_cim_http.py
===================================================================
--- pywbem/trunk/testsuite/test_cim_http.py (rev 0)
+++ pywbem/trunk/testsuite/test_cim_http.py 2015-01-16 22:57:15 UTC (rev 707)
@@ -0,0 +1,206 @@
+#
+# Exercise routines in cim_http.
+#
+
+import comfychair
+
+from pywbem import cim_http
+
+
+class Parse_url(comfychair.TestCase):
+ """
+ Test the parse_url() function.
+ """
+
+ def setup(self):
+ return
+
+ def runtest_single(self, url, exp_host, exp_port, exp_ssl):
+ '''
+ Test function for single invocation of parse_url()
+ '''
+
+ host, port, ssl = cim_http.parse_url(url)
+
+ self.assert_equal(host, exp_host,
+ "Unexpected host: %r, expected: %r" % (host, exp_host))
+ self.assert_equal(port, exp_port,
+ "Unexpected port: %r, expected: %r" % (port, exp_port))
+ self.assert_equal(ssl, exp_ssl,
+ "Unexpected ssl: %r, expected: %r" % (ssl, exp_ssl))
+
+
+ def runtest(self):
+ '''
+ Run all tests for parse_url().
+ '''
+
+ # Keep these defaults in sync with those in cim_http.parse_url()
+ default_port_http = 5988
+ default_port_https = 5989
+ default_ssl = False
+
+ self.runtest_single("http://my.host.com",
+ "my.host.com",
+ default_port_http,
+ False)
+
+ self.runtest_single("https://my.host.com/",
+ "my.host.com",
+ default_port_https,
+ True)
+
+ self.runtest_single("my.host.com",
+ "my.host.com",
+ default_port_http,
+ default_ssl)
+
+ self.runtest_single("http.com",
+ "http.com",
+ default_port_http,
+ default_ssl)
+
+ self.runtest_single("http.com/",
+ "http.com",
+ default_port_http,
+ default_ssl)
+
+ self.runtest_single("http.com/path.segment.com",
+ "http.com",
+ default_port_http,
+ default_ssl)
+
+ self.runtest_single("http.com//path.segment.com",
+ "http.com",
+ default_port_http,
+ default_ssl)
+
+ self.runtest_single("http://my.host.com:1234",
+ "my.host.com",
+ 1234,
+ False)
+
+ self.runtest_single("http://my.host.com:1234/",
+ "my.host.com",
+ 1234,
+ False)
+
+ self.runtest_single("http://my.host.com:1234/path/segment",
+ "my.host.com",
+ 1234,
+ False)
+
+ self.runtest_single("http://9.10.11.12:1234",
+ "9.10.11.12",
+ 1234,
+ False)
+
+ self.runtest_single("my.host.com:1234",
+ "my.host.com",
+ 1234,
+ default_ssl)
+
+ self.runtest_single("my.host.com:1234/",
+ "my.host.com",
+ 1234,
+ default_ssl)
+
+ self.runtest_single("9.10.11.12/",
+ "9.10.11.12",
+ default_port_http,
+ default_ssl)
+
+ self.runtest_single("HTTP://my.host.com",
+ "my.host.com",
+ default_port_http,
+ False)
+
+ self.runtest_single("HTTPS://my.host.com",
+ "my.host.com",
+ default_port_https,
+ True)
+
+ self.runtest_single("http://[2001:db8::7348]",
+ "2001:db8::7348",
+ default_port_http,
+ False)
+
+ self.runtest_single("http://[2001:db8::7348-1]",
+ "2001:db8::7348%1",
+ default_port_http,
+ False)
+
+ self.runtest_single("http://[2001:db8::7348-eth1]",
+ "2001:db8::7348%eth1",
+ default_port_http,
+ False)
+
+ # Toleration of (incorrect) IPv6 URI format supported by PyWBEM:
+ # Must specify port; zone index must be specified with % if used
+
+ self.runtest_single("http://2001:db8::7348:1234",
+ "2001:db8::7348",
+ 1234,
+ False)
+
+ self.runtest_single("http://2001:db8::7348%eth0:1234",
+ "2001:db8::7348%eth0",
+ 1234,
+ False)
+
+ self.runtest_single("http://2001:db8::7348%1:1234",
+ "2001:db8::7348%1",
+ 1234,
+ False)
+
+ self.runtest_single("https://[2001:db8::7348]/",
+ "2001:db8::7348",
+ default_port_https,
+ True)
+
+ self.runtest_single("http://[2001:db8::7348]:1234",
+ "2001:db8::7348",
+ 1234,
+ False)
+
+ self.runtest_single("https://[::ffff.9.10.11.12]:1234/",
+ "::ffff.9.10.11.12",
+ 1234,
+ True)
+
+ self.runtest_single("https://[::ffff.9.10.11.12-0]:1234/",
+ "::ffff.9.10.11.12%0",
+ 1234,
+ True)
+
+ self.runtest_single("https://[::ffff.9.10.11.12-eth0]:1234/",
+ "::ffff.9.10.11.12%eth0",
+ 1234,
+ True)
+
+ self.runtest_single("[2001:db8::7348]",
+ "2001:db8::7348",
+ default_port_http,
+ default_ssl)
+
+ self.runtest_single("[2001:db8::7348]/",
+ "2001:db8::7348",
+ default_port_http,
+ default_ssl)
+
+ self.runtest_single("[2001:db8::7348]/-eth0",
+ "2001:db8::7348",
+ default_port_http,
+ default_ssl)
+
+
+#################################################################
+# Main function
+#################################################################
+
+tests = [
+ Parse_url, # parse_url()
+]
+
+if __name__ == '__main__':
+ comfychair.main(tests)
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <ma...@us...> - 2015-01-16 22:55:28
|
Revision: 706
http://sourceforge.net/p/pywbem/code/706
Author: maiera
Date: 2015-01-16 22:55:25 +0000 (Fri, 16 Jan 2015)
Log Message:
-----------
Made showstatus target phony, to avoid useless rebuilds.
Modified Paths:
--------------
pywbem/trunk/makefile
Modified: pywbem/trunk/makefile
===================================================================
--- pywbem/trunk/makefile 2015-01-16 19:12:13 UTC (rev 705)
+++ pywbem/trunk/makefile 2015-01-16 22:55:25 UTC (rev 706)
@@ -80,12 +80,12 @@
# No built-in rules needed:
.SUFFIXES:
-.PHONY: build buildwin test install clean help
+.PHONY: build buildwin test install clean help showstatus
-build: _showrepo $(dist_file)
+build: showstatus $(dist_file)
@echo '$@ done; created: $(dist_file)'
-buildwin: _showrepo $(win64_dist_file)
+buildwin: showstatus $(win64_dist_file)
@echo '$@ done; created: $(win64_dist_file)'
check: pylint_report.html
@@ -110,7 +110,7 @@
all: build check test install clean
@echo '$@ done.'
-_showrepo:
+showstatus:
@echo 'SVN status:'
@svn status -u
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <ma...@us...> - 2015-01-16 19:48:01
|
Revision: 701
http://sourceforge.net/p/pywbem/code/701
Author: maiera
Date: 2015-01-16 18:39:25 +0000 (Fri, 16 Jan 2015)
Log Message:
-----------
Removed the limitation in the CIMProperty constructor where a Null value of the property in combination with embedded_object=instance was raising an error.
Modified Paths:
--------------
pywbem/trunk/pywbem/cim_obj.py
Modified: pywbem/trunk/pywbem/cim_obj.py
===================================================================
--- pywbem/trunk/pywbem/cim_obj.py 2015-01-16 12:42:18 UTC (rev 700)
+++ pywbem/trunk/pywbem/cim_obj.py 2015-01-16 18:39:25 UTC (rev 701)
@@ -668,11 +668,11 @@
values are defined for this argument:
`'instance'`: The property is declared with the
`EmbeddedInstance` qualifier, indicating that the property
- value is an embedded instance of a known class name.
+ value is an embedded instance of a known class name (or Null).
`'object'`: The property is declared with the
`EmbeddedObject` qualifier, indicating that the property
value is an embedded object (instance or class) of which the
- class name is not known.
+ class name is not known (or Null).
`None` means that the argument is unspecified, causing the
corresponding instance variable to be inferred. An exception is
raised if it cannot be inferred.
@@ -759,16 +759,13 @@
elif value is None or len(value) == 0 or value[0] is None:
# Cannot infer from value, look at embedded_object and type
if embedded_object == 'instance':
- raise ValueError(
- 'Limitation: Array property %r that is Null, ' \
- 'empty, or has Null as its first element cannot ' \
- 'have embedded instances (class cannot be ' \
- 'specified)' % name)
+ msg = 'Array property %r contains embedded instances' % name
+ type = _intended_value('string',
+ None, type, 'type', msg)
elif embedded_object == 'object':
+ msg = 'Array property %r contains embedded objects' % name
type = _intended_value('string',
- None, type, 'type',
- 'Array property %r contains embedded objects' % \
- name)
+ None, type, 'type', msg)
elif type is not None:
# Leave type as specified, but check it for validity
dummy_type_obj = cim_types.type_from_name(type)
@@ -825,9 +822,11 @@
if value is None:
# Try to infer from embedded_object, reference_class, and type
if embedded_object == 'instance':
- raise ValueError('Limitation: Simple property %r that ' \
- 'is Null cannot have embedded instances '\
- '(class cannot be specified)' % name)
+ msg = 'Property %r contains embedded instance' % name
+ type = _intended_value('string',
+ None, type, 'type', msg)
+ reference_class = _intended_value(None,
+ None, reference_class, 'reference_class', msg)
elif embedded_object == 'object':
msg = 'Property %r contains embedded object' % name
type = _intended_value('string',
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <ma...@us...> - 2015-01-16 19:12:16
|
Revision: 705
http://sourceforge.net/p/pywbem/code/705
Author: maiera
Date: 2015-01-16 19:12:13 +0000 (Fri, 16 Jan 2015)
Log Message:
-----------
Released preliminary version 0.8.0-dev.r704
Revision Links:
--------------
http://sourceforge.net/p/pywbem/code/704
Added Paths:
-----------
pywbem/dist/pywbem-0.8.0/pywbem-0.8.0-dev.r704.zip
Added: pywbem/dist/pywbem-0.8.0/pywbem-0.8.0-dev.r704.zip
===================================================================
(Binary files differ)
Index: pywbem/dist/pywbem-0.8.0/pywbem-0.8.0-dev.r704.zip
===================================================================
--- pywbem/dist/pywbem-0.8.0/pywbem-0.8.0-dev.r704.zip 2015-01-16 19:08:40 UTC (rev 704)
+++ pywbem/dist/pywbem-0.8.0/pywbem-0.8.0-dev.r704.zip 2015-01-16 19:12:13 UTC (rev 705)
Property changes on: pywbem/dist/pywbem-0.8.0/pywbem-0.8.0-dev.r704.zip
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <ma...@us...> - 2015-01-16 19:08:47
|
Revision: 704
http://sourceforge.net/p/pywbem/code/704
Author: maiera
Date: 2015-01-16 19:08:40 +0000 (Fri, 16 Jan 2015)
Log Message:
-----------
Updated change history.
Modified Paths:
--------------
pywbem/trunk/pywbem/NEWS
Modified: pywbem/trunk/pywbem/NEWS
===================================================================
--- pywbem/trunk/pywbem/NEWS 2015-01-16 18:43:27 UTC (rev 703)
+++ pywbem/trunk/pywbem/NEWS 2015-01-16 19:08:40 UTC (rev 704)
@@ -1,4 +1,4 @@
-pywbem-0.8.0-dev.r698 (last updated: 2015-01-16, includes commits up to r698)
+pywbem-0.8.0-dev.r704
ENHANCEMENTS:
@@ -53,6 +53,13 @@
* Improved help text of test_cim_operations.py test program.
(Andreas Maier)
+ * Added an optional Params argument to InvokeMethod(), that is an ordered
+ list of CIM input parameters, that preserves its order in the CIM-XML
+ request message. This is to accomodate deficient WBEM servers that do
+ not tolerate arbitrary order of method input parameters as required by
+ the standard. The new argument is optional, making this a backwards
+ compatible change of InvokeMethod(). (Andreas Maier)
+
BUG FIXES:
* Fix syntax error in CIM DTDVERSION error path. Allow KEYVALUE
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <ma...@us...> - 2015-01-16 18:43:38
|
Revision: 703
http://sourceforge.net/p/pywbem/code/703
Author: maiera
Date: 2015-01-16 18:43:27 +0000 (Fri, 16 Jan 2015)
Log Message:
-----------
Improved and fixed operation testcases, and used class names that work in a broader set of implementations.
Added support for -n namespace command line option.
Modified Paths:
--------------
pywbem/trunk/testsuite/test_cim_operations.py
Modified: pywbem/trunk/testsuite/test_cim_operations.py
===================================================================
--- pywbem/trunk/testsuite/test_cim_operations.py 2015-01-16 18:41:52 UTC (rev 702)
+++ pywbem/trunk/testsuite/test_cim_operations.py 2015-01-16 18:43:27 UTC (rev 703)
@@ -19,7 +19,11 @@
Real32, Real64, CIMDateTime
from comfychair import main, TestCase, NotRunError
+from pywbem.cim_operations import DEFAULT_NAMESPACE
+# A class that should be implemented and is used for testing
+TEST_CLASS = 'CIM_ComputerSystem'
+
# Test classes
class ClientTest(TestCase):
@@ -34,7 +38,8 @@
self.system_url = url
self.conn = WBEMConnection(
self.system_url,
- (username, password))
+ (username, password),
+ namespace)
self.conn.debug = True
def cimcall(self, fn, *args, **kw):
@@ -46,11 +51,12 @@
self.log('Operation %s failed with %s: %s\n' % \
(fn.__name__, exc.__class__.__name__, str(exc)))
last_request = self.conn.last_request or self.conn.last_raw_request
- self.log('Failed Request:\n\n%s\n' % last_request)
+ self.log('Request:\n\n%s\n' % last_request)
last_reply = self.conn.last_reply or self.conn.last_raw_reply
- self.log('Failed Reply:\n\n%s\n' % last_reply)
+ self.log('Reply:\n\n%s\n' % last_reply)
raise
+ self.log('Operation %s succeeded\n' % fn.__name__)
last_request = self.conn.last_request or self.conn.last_raw_request
self.log('Request:\n\n%s\n' % last_request)
last_reply = self.conn.last_reply or self.conn.last_raw_reply
@@ -68,22 +74,27 @@
# Single arg call
- names = self.cimcall(
- self.conn.EnumerateInstanceNames,
- 'PyWBEM_Person')
+ names = self.cimcall(self.conn.EnumerateInstanceNames,
+ TEST_CLASS)
- self.assert_(len(names) == 3)
+ self.assert_(len(names) >= 1)
[self.assert_(isinstance(n, CIMInstanceName)) for n in names]
[self.assert_(len(n.namespace) > 0) for n in names]
- # Call with optional namespace path
+ # Call with explicit CIM namespace that exists
+ self.cimcall(self.conn.EnumerateInstanceNames,
+ TEST_CLASS,
+ namespace=self.conn.default_namespace)
+
+ # Call with explicit CIM namespace that does not exist
+
try:
self.cimcall(self.conn.EnumerateInstanceNames,
- 'PyWBEM_Person',
- namespace='root/pywbem')
+ TEST_CLASS,
+ namespace='root/blah')
except CIMError, arg:
if arg[0] != CIM_ERR_INVALID_NAMESPACE:
@@ -95,23 +106,28 @@
# Simplest invocation
- instances = self.cimcall(
- self.conn.EnumerateInstances,
- 'PyWBEM_Person')
+ instances = self.cimcall(self.conn.EnumerateInstances,
+ TEST_CLASS)
- self.assert_(len(instances) == 3)
+ self.assert_(len(instances) >= 1)
[self.assert_(isinstance(i, CIMInstance)) for i in instances]
[self.assert_(isinstance(i.path, CIMInstanceName)) for i in instances]
[self.assert_(len(i.path.namespace) > 0) for i in instances]
- # Call with optional namespace path
+ # Call with explicit CIM namespace that exists
+ self.cimcall(self.conn.EnumerateInstances,
+ TEST_CLASS,
+ namespace=self.conn.default_namespace)
+
+ # Call with explicit CIM namespace that does not exist
+
try:
self.cimcall(self.conn.EnumerateInstances,
- 'PyWBEM_Person',
- namespace='root/pywbem')
+ TEST_CLASS,
+ namespace='root/blah')
except CIMError, arg:
if arg[0] != CIM_ERR_INVALID_NAMESPACE:
@@ -123,25 +139,28 @@
def runtest(self):
try:
- instances = self.cimcall(
- self.conn.ExecQuery,
- 'wql',
- 'Select * from PyWBEM_Person')
- self.assert_(len(instances) == 3)
+ # Simplest invocation
+ instances = self.cimcall(self.conn.ExecQuery,
+ 'wql',
+ 'Select * from %s' % TEST_CLASS)
+
+ self.assert_(len(instances) >= 1)
+
[self.assert_(isinstance(i, CIMInstance)) for i in instances]
[self.assert_(isinstance(i.path, CIMInstanceName)) \
for i in instances]
[self.assert_(len(i.path.namespace) > 0) for i in instances]
- # Call with optional namespace path
+ # Call with explicit CIM namespace that does not exist
+
try:
self.cimcall(self.conn.ExecQuery,
'wql',
- 'Select * from PyWBEM_Person',
- namespace='root/pywbem')
+ 'Select * from %s' % TEST_CLASS,
+ namespace='root/blah')
except CIMError, arg:
if arg[0] != CIM_ERR_INVALID_NAMESPACE:
@@ -149,7 +168,9 @@
except CIMError, arg:
if arg[0] == CIM_ERR_NOT_SUPPORTED:
- raise NotRunError, "CIMOM doesn't support ExecQuery"
+ raise NotRunError, "The WBEM server doesn't support ExecQuery"
+ if arg[0] == CIM_ERR_QUERY_LANGUAGE_NOT_SUPPORTED:
+ raise NotRunError, "The WBEM server doesn't support WQL for ExecQuery"
else:
raise
@@ -158,13 +179,14 @@
def runtest(self):
- name = self.cimcall(
- self.conn.EnumerateInstanceNames,
- 'PyWBEM_Person')[0]
+ inst_names = self.cimcall(self.conn.EnumerateInstanceNames, TEST_CLASS)
+ self.assert_(len(inst_names) >= 1)
+ name = inst_names[0] # Pick the first returned instance
# Simplest invocation
- obj = self.cimcall(self.conn.GetInstance, name)
+ obj = self.cimcall(self.conn.GetInstance,
+ name)
self.assert_(isinstance(obj, CIMInstance))
self.assert_(isinstance(obj.path, CIMInstanceName))
@@ -176,9 +198,8 @@
try:
- self.cimcall(
- self.conn.GetInstance,
- invalid_name)
+ self.cimcall(self.conn.GetInstance,
+ invalid_name)
except CIMError, arg:
if arg[0] != CIM_ERR_INVALID_NAMESPACE:
@@ -208,33 +229,26 @@
# Simple create and delete
- result = self.cimcall(self.conn.CreateInstance, instance)
+ try:
+ result = self.cimcall(self.conn.CreateInstance, instance)
+ except CIMError, arg:
+ if arg == CIM_ERR_INVALID_CLASS:
+ # does not support creation
+ pass
+ else:
+ self.assert_(isinstance(result, CIMInstanceName))
+ self.assert_(len(result.namespace) > 0)
- self.assert_(isinstance(result, CIMInstanceName))
- self.assert_(len(result.namespace) > 0)
+ result = self.cimcall(self.conn.DeleteInstance, instance.path)
- result = self.cimcall(self.conn.DeleteInstance, instance.path)
+ self.assert_(result == None)
- self.assert_(result == None)
-
try:
self.cimcall(self.conn.GetInstance(instance.path))
except CIMError, arg:
if arg == CIM_ERR_NOT_FOUND:
pass
- # Arg plus namespace
-
- try:
-
- self.cimcall(
- self.conn.CreateInstance,
- instance)
-
- except CIMError, arg:
- if arg[0] != CIM_ERR_INVALID_NAMESPACE:
- raise
-
class ModifyInstance(ClientTest):
def runtest(self):
@@ -259,22 +273,28 @@
# Create instance
- self.cimcall(self.conn.CreateInstance, instance)
+ try:
+ self.cimcall(self.conn.CreateInstance, instance)
+ except CIMError, arg:
+ if arg == CIM_ERR_INVALID_CLASS:
+ # does not support creation
+ pass
+ else:
- # Modify instance
+ # Modify instance
+
+ instance['Title'] = 'Sir'
+
+ instance.path.namespace = 'root/cimv2'
+ result = self.cimcall(self.conn.ModifyInstance, instance)
+
+ self.assert_(result is None)
+
+ # Clean up
+
+ self.cimcall(self.conn.DeleteInstance, instance.path)
- instance['Title'] = 'Sir'
- instance.path.namespace = 'root/cimv2'
- result = self.cimcall(self.conn.ModifyInstance, instance)
-
- self.assert_(result is None)
-
- # Clean up
-
- self.cimcall(self.conn.DeleteInstance, instance.path)
-
-
#################################################################
# Method provider interface tests
#################################################################
@@ -290,7 +310,7 @@
self.cimcall(
self.conn.InvokeMethod,
'FooMethod',
- 'CIM_Process')
+ TEST_CLASS)
except CIMError, arg:
if arg[0] != CIM_ERR_METHOD_NOT_AVAILABLE:
@@ -298,7 +318,9 @@
# Invoke on an InstanceName
- name = self.cimcall(self.conn.EnumerateInstanceNames, 'CIM_Process')[0]
+ inst_names = self.cimcall(self.conn.EnumerateInstanceNames, TEST_CLASS)
+ self.assert_(len(inst_names) >= 1)
+ name = inst_names[0] # Pick the first returned instance
try:
@@ -307,7 +329,7 @@
name)
except CIMError, arg:
- if arg[0] != CIM_ERR_METHOD_NOT_AVAILABLE:
+ if arg[0] not in (CIM_ERR_METHOD_NOT_AVAILABLE, CIM_ERR_METHOD_NOT_FOUND):
raise
# Test remote instance name
@@ -323,7 +345,7 @@
name)
except CIMError, arg:
- if arg[0] != CIM_ERR_METHOD_NOT_AVAILABLE:
+ if arg[0] not in (CIM_ERR_METHOD_NOT_AVAILABLE, CIM_ERR_METHOD_NOT_FOUND):
raise
# Call with all possible parameter types
@@ -331,7 +353,7 @@
try:
self.cimcall(self.conn.InvokeMethod,
'FooMethod',
- 'CIM_Process',
+ TEST_CLASS,
String='Spotty',
Uint8=Uint8(1),
Sint8=Sint8(2),
@@ -357,7 +379,7 @@
self.cimcall(self.conn.InvokeMethod,
'FooMethod',
- 'CIM_Process',
+ TEST_CLASS,
StringArray='Spotty',
Uint8Array=[Uint8(1)],
Sint8Array=[Sint8(2)],
@@ -378,6 +400,19 @@
if arg[0] != CIM_ERR_METHOD_NOT_AVAILABLE:
raise
+ # Call with new Params arg
+
+ try:
+ self.cimcall(self.conn.InvokeMethod,
+ 'FooMethod',
+ TEST_CLASS,
+ [('Spam',Uint16(1)),('Ham',Uint16(2))], # Params
+ Drink=Uint16(3), # begin of **params
+ Beer=Uint16(4))
+ except CIMError, arg:
+ if arg[0] != CIM_ERR_METHOD_NOT_AVAILABLE:
+ raise
+
# TODO: Call with empty arrays
# TODO: Call with weird VALUE.REFERENCE child types:
@@ -394,23 +429,24 @@
# Call on named instance
- collection = self.cimcall(
- self.conn.EnumerateInstanceNames, 'PyWBEM_PersonCollection')[0]
+ inst_names = self.cimcall(self.conn.EnumerateInstanceNames, TEST_CLASS)
+ self.assert_(len(inst_names) >= 1)
+ inst_name = inst_names[0] # Pick the first returned instance
- instances = self.cimcall(self.conn.Associators, collection)
+ instances = self.cimcall(self.conn.Associators, inst_name)
[self.assert_(isinstance(i, CIMInstance)) for i in instances]
[self.assert_(isinstance(i.path, CIMInstanceName)) for i in instances]
- [self.assert_(i.classname == 'PyWBEM_Person') for i in instances]
+ # TODO: For now, disabled test for class name of associated instances.
+ # [self.assert_(i.classname == 'TBD') for i in instances]
[self.assert_(i.path.namespace is not None) for i in instances]
[self.assert_(i.path.host is not None) for i in instances]
# Call on class name
- classes = self.cimcall(
- self.conn.Associators, 'PyWBEM_PersonCollection')
+ classes = self.cimcall(self.conn.Associators, TEST_CLASS)
# TODO: check return values
@@ -418,24 +454,25 @@
def runtest(self):
- # Call on instance name
+ # Call on named instance
- collection = self.cimcall(
- self.conn.EnumerateInstanceNames, 'PyWBEM_PersonCollection')[0]
+ inst_names = self.cimcall(self.conn.EnumerateInstanceNames, TEST_CLASS)
+ self.assert_(len(inst_names) >= 1)
+ inst_name = inst_names[0] # Pick the first returned instance
- names = self.cimcall(self.conn.AssociatorNames, collection)
+ names = self.cimcall(self.conn.AssociatorNames, inst_name)
[self.assert_(isinstance(n, CIMInstanceName)) for n in names]
- [self.assert_(n.classname == 'PyWBEM_Person') for n in names]
+ # TODO: For now, disabled test for class name of associated instances.
+ # [self.assert_(n.classname == 'TBD') for n in names]
[self.assert_(n.namespace is not None) for n in names]
[self.assert_(n.host is not None) for n in names]
# Call on class name
- classes = self.cimcall(
- self.conn.AssociatorNames, 'PyWBEM_PersonCollection')
+ classes = self.cimcall(self.conn.AssociatorNames, TEST_CLASS)
# TODO: check return values
@@ -445,24 +482,25 @@
# Call on named instance
- collection = self.cimcall(
- self.conn.EnumerateInstanceNames, 'PyWBEM_PersonCollection')[0]
+ inst_names = self.cimcall(self.conn.EnumerateInstanceNames, TEST_CLASS)
+ self.assert_(len(inst_names) >= 1)
+ inst_name = inst_names[0] # Pick the first returned instance
- instances = self.cimcall(self.conn.References, collection)
+ instances = self.cimcall(self.conn.References, inst_name)
[self.assert_(isinstance(i, CIMInstance)) for i in instances]
[self.assert_(isinstance(i.path, CIMInstanceName)) for i in instances]
- [self.assert_(i.classname == 'PyWBEM_MemberOfPersonCollection')
- for i in instances]
+ # TODO: For now, disabled test for class name of referencing instances.
+ #[self.assert_(i.classname == 'TBD')
+ # for i in instances]
[self.assert_(i.path.namespace is not None) for i in instances]
[self.assert_(i.path.host is not None) for i in instances]
# Call on class name
- classes = self.cimcall(
- self.conn.References, 'PyWBEM_PersonCollection')
+ classes = self.cimcall(self.conn.References, TEST_CLASS)
# TODO: check return values
@@ -472,23 +510,24 @@
# Call on instance name
- collection = self.cimcall(
- self.conn.EnumerateInstanceNames, 'PyWBEM_PersonCollection')[0]
+ inst_names = self.cimcall(self.conn.EnumerateInstanceNames, TEST_CLASS)
+ self.assert_(len(inst_names) >= 1)
+ inst_name = inst_names[0] # Pick the first returned instance
- names = self.cimcall(self.conn.ReferenceNames, collection)
+ names = self.cimcall(self.conn.ReferenceNames, inst_name)
[self.assert_(isinstance(n, CIMInstanceName)) for n in names]
- [self.assert_(n.classname == 'PyWBEM_MemberOfPersonCollection')
- for n in names]
+ # TODO: For now, disabled test for class name of referencing instances.
+ #[self.assert_(n.classname == 'TBD')
+ # for n in names]
[self.assert_(n.namespace is not None) for n in names]
[self.assert_(n.host is not None) for n in names]
# Call on class name
- classes = self.cimcall(
- self.conn.ReferenceNames, 'PyWBEM_PersonCollection')
+ classes = self.cimcall(self.conn.ReferenceNames, TEST_CLASS)
# TODO: check return values
@@ -702,6 +741,8 @@
print ''
print 'General options:'
print ' --help, -h Display this help text.'
+ print ' -n NAMESPACE Use this CIM namespace instead of '\
+ 'default: %s' % DEFAULT_NAMESPACE
print ''
print 'Comfychair help:'
print ''
@@ -714,6 +755,14 @@
'EnumerateInstances GetInstance ' % sys.argv[0]
sys.exit(0)
+ namespace = DEFAULT_NAMESPACE
+ while (True):
+ if sys.argv[1][0] != '-':
+ break
+ if sys.argv[1] == '-n':
+ namespace = sys.argv[2]
+ del sys.argv[1:3]
+
url = sys.argv[1]
if len(sys.argv) >= 3:
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <ma...@us...> - 2015-01-16 18:41:55
|
Revision: 702
http://sourceforge.net/p/pywbem/code/702
Author: maiera
Date: 2015-01-16 18:41:52 +0000 (Fri, 16 Jan 2015)
Log Message:
-----------
Fix for bug 4: Added an optional Params parameter to InvokeMethod(), that is an ordered list of CIM input parameters.
Modified Paths:
--------------
pywbem/trunk/pywbem/cim_operations.py
Modified: pywbem/trunk/pywbem/cim_operations.py
===================================================================
--- pywbem/trunk/pywbem/cim_operations.py 2015-01-16 18:39:25 UTC (rev 701)
+++ pywbem/trunk/pywbem/cim_operations.py 2015-01-16 18:41:52 UTC (rev 702)
@@ -462,7 +462,7 @@
return tt
- def methodcall(self, methodname, localobject, **params):
+ def methodcall(self, methodname, localobject, Params=None, **params):
"""
Perform an extrinsic method call (= CIM method invocation).
@@ -470,8 +470,8 @@
method of this class. In general, clients should use 'InvokeMethod'
instead of this function.
- The parameters are automatically converted to the right CIM-XML
- elements.
+ The Python method parameters are automatically converted to the right
+ CIM-XML elements. See `InvokeMethod` for details.
:Returns:
@@ -544,10 +544,17 @@
return 'instance'
return None
+ if Params is None:
+ Params = []
plist = [cim_xml.PARAMVALUE(x[0],
paramvalue(x[1]),
paramtype(x[1]),
embedded_object=is_embedded(x[1]))
+ for x in Params]
+ plist += [cim_xml.PARAMVALUE(x[0],
+ paramvalue(x[1]),
+ paramtype(x[1]),
+ embedded_object=is_embedded(x[1]))
for x in params.items()]
# Build XML request
@@ -1804,7 +1811,7 @@
# Method provider API
#
- def InvokeMethod(self, MethodName, ObjectName, **params):
+ def InvokeMethod(self, MethodName, ObjectName, Params=None, **params):
# pylint: disable=invalid-name
"""
Invoke a method on a target instance or on a target class.
@@ -1818,6 +1825,10 @@
If the operation succeeds, this method returns.
Otherwise, this method raises an exception.
+ Input parameters for the CIM method can be specified in a
+ order-preserving way using the ``Params`` parameter, and in a
+ order-agnostic way using the ``**params`` keyword parameters.
+
:Parameters:
MethodName : string
@@ -1838,14 +1849,30 @@
specify a namespace, the default namespace of the connection is
used.
- {paramname}
- An input parameter for the CIM method. This Python method parameter
- must be provided for each CIM method input parameter (there is no
- concept of optional method parameters in CIM). The name of this
- Python method parameter must be the name of the CIM method
- parameter. The value of this Python method parameter must be a CIM
- typed value as described in `cim_types`.
+ Params
+ A list of input parameters for the CIM method.
+ Each list item represents a single input parameter for the CIM
+ method and must be a ``tuple(name,value)``, where ``name`` is the
+ parameter name in any lexical case, and ``value`` is the parameter
+ value as a CIM typed value as described in `cim_types`.
+
+ **params
+ Keyword parameters for the input parameters for the CIM method.
+
+ Each keyword parameter represents a single input parameter for the
+ CIM method, where the key is the parameter name in any lexical
+ case, and the value is the parameter value as a CIM typed value as
+ described in `cim_types`.
+
+ The overall list of input parameters represented in the CIM-XML
+ request message that is sent to the WBEM server is formed from
+ the list of parameters specified in ``Params`` preserving its
+ order, followed by the set of parameters specified in ``**params``
+ in any order. There is no checking for duplicate parameter names
+ in the PyWBEM client.
+
+
:Returns:
A tuple of ``(returnvalue, outparams)``, where:
@@ -1878,7 +1905,7 @@
# Make the method call
- result = self.methodcall(MethodName, obj, **params)
+ result = self.methodcall(MethodName, obj, Params, **params)
# Convert optional RETURNVALUE into a Python object
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <ma...@us...> - 2015-01-16 13:58:21
|
Revision: 698
http://sourceforge.net/p/pywbem/code/698
Author: maiera
Date: 2015-01-16 12:35:18 +0000 (Fri, 16 Jan 2015)
Log Message:
-----------
Fixed bug 21: Added code in support of CIM-XML declarations, for alternative PyWBEM client based on twisted.
Modified Paths:
--------------
pywbem/trunk/pywbem/NEWS
pywbem/trunk/pywbem/tupleparse.py
Modified: pywbem/trunk/pywbem/NEWS
===================================================================
--- pywbem/trunk/pywbem/NEWS 2015-01-16 10:48:49 UTC (rev 697)
+++ pywbem/trunk/pywbem/NEWS 2015-01-16 12:35:18 UTC (rev 698)
@@ -1,4 +1,4 @@
-pywbem-0.8.0-dev.r696 (last updated: 2015-01-16, includes commits up to r696)
+pywbem-0.8.0-dev.r698 (last updated: 2015-01-16, includes commits up to r698)
ENHANCEMENTS:
@@ -190,6 +190,9 @@
* Fixed bug where HTTP body was attempted ot be read when CIMError header
is set, causing a hang. (Andreas Maier)
+
+ * Added CIM-XML declaration support for alternative PyWBEM client based
+ on twisted. (Andreas Maier)
TESTING:
Modified: pywbem/trunk/pywbem/tupleparse.py
===================================================================
--- pywbem/trunk/pywbem/tupleparse.py 2015-01-16 10:48:49 UTC (rev 697)
+++ pywbem/trunk/pywbem/tupleparse.py 2015-01-16 12:35:18 UTC (rev 698)
@@ -301,7 +301,43 @@
return name(tt), attrs(tt), child
+
#
+# Declaration elements
+#
+
+def parse_declaration(tt):
+ """
+ <!ELEMENT DECLARATION ( DECLGROUP | DECLGROUP.WITHNAME |
+ DECLGROUP.WITHPATH )+>
+
+ Note: We only support the DECLGROUP child, at this point.
+ """
+
+ check_node(tt, 'DECLARATION')
+
+ child = one_child(tt, ['DECLGROUP'])
+
+ return name(tt), attrs(tt), child
+
+
+def parse_declgroup(tt):
+ """
+ <!ELEMENT DECLGROUP ( (LOCALNAMESPACEPATH|NAMESPACEPATH)?,
+ QUALIFIER.DECLARATION*, VALUE.OBJECT* )>
+
+ Note: We only support the QUALIFIER.DECLARATION and VALUE.OBJECT
+ children, and with a multiplicity of 1, at this point.
+ """
+
+ check_node(tt, 'DECLGROUP')
+
+ child = one_child(tt, ['QUALIFIER.DECLARATION', 'VALUE.OBJECT'])
+
+ return name(tt), attrs(tt), child
+
+
+#
# Object value elements
#
@@ -359,7 +395,7 @@
check_node(tt, 'VALUE.OBJECT')
- child = one_child(tt, ['CLASS', 'INSTANCE', 'QUALIFIER.DECLARATION'])
+ child = one_child(tt, ['CLASS', 'INSTANCE'])
return (name(tt), attrs(tt), child)
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <ma...@us...> - 2015-01-16 12:42:25
|
Revision: 700
http://sourceforge.net/p/pywbem/code/700
Author: maiera
Date: 2015-01-16 12:42:18 +0000 (Fri, 16 Jan 2015)
Log Message:
-----------
Released preliminary version 0.8.0-dev.r699.
Revision Links:
--------------
http://sourceforge.net/p/pywbem/code/699
Added Paths:
-----------
pywbem/dist/pywbem-0.8.0/pywbem-0.8.0-dev.r699.zip
Removed Paths:
-------------
pywbem/dist/pywbem-0.8.0/pywbem-0.8.0-dev.r695.zip
Deleted: pywbem/dist/pywbem-0.8.0/pywbem-0.8.0-dev.r695.zip
===================================================================
(Binary files differ)
Added: pywbem/dist/pywbem-0.8.0/pywbem-0.8.0-dev.r699.zip
===================================================================
(Binary files differ)
Index: pywbem/dist/pywbem-0.8.0/pywbem-0.8.0-dev.r699.zip
===================================================================
--- pywbem/dist/pywbem-0.8.0/pywbem-0.8.0-dev.r699.zip 2015-01-16 12:36:06 UTC (rev 699)
+++ pywbem/dist/pywbem-0.8.0/pywbem-0.8.0-dev.r699.zip 2015-01-16 12:42:18 UTC (rev 700)
Property changes on: pywbem/dist/pywbem-0.8.0/pywbem-0.8.0-dev.r699.zip
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <ma...@us...> - 2015-01-16 12:36:08
|
Revision: 699
http://sourceforge.net/p/pywbem/code/699
Author: maiera
Date: 2015-01-16 12:36:06 +0000 (Fri, 16 Jan 2015)
Log Message:
-----------
Added displaying of SVN status in makefile-based build.
Modified Paths:
--------------
pywbem/trunk/makefile
Modified: pywbem/trunk/makefile
===================================================================
--- pywbem/trunk/makefile 2015-01-16 12:35:18 UTC (rev 698)
+++ pywbem/trunk/makefile 2015-01-16 12:36:06 UTC (rev 699)
@@ -82,10 +82,10 @@
.PHONY: build buildwin test install clean help
-build: $(dist_file)
+build: _showrepo $(dist_file)
@echo '$@ done; created: $(dist_file)'
-buildwin: $(win64_dist_file)
+buildwin: _showrepo $(win64_dist_file)
@echo '$@ done; created: $(win64_dist_file)'
check: pylint_report.html
@@ -110,6 +110,10 @@
all: build check test install clean
@echo '$@ done.'
+_showrepo:
+ @echo 'SVN status:'
+ @svn status -u
+
help:
@echo 'makefile for $(package_name) $(package_version)'
@echo 'Valid targets are:'
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <ma...@us...> - 2015-01-16 12:00:22
|
Revision: 697
http://sourceforge.net/p/pywbem/code/697
Author: maiera
Date: 2015-01-16 10:48:49 +0000 (Fri, 16 Jan 2015)
Log Message:
-----------
Fixed bug 6: Attempt to read HTTP body when CIMError header is set.
Modified Paths:
--------------
pywbem/trunk/pywbem/NEWS
pywbem/trunk/pywbem/cim_http.py
Modified: pywbem/trunk/pywbem/NEWS
===================================================================
--- pywbem/trunk/pywbem/NEWS 2015-01-16 09:30:41 UTC (rev 696)
+++ pywbem/trunk/pywbem/NEWS 2015-01-16 10:48:49 UTC (rev 697)
@@ -1,4 +1,4 @@
-pywbem-0.8.0-dev.r694 (last updated: 2015-01-16, includes commits up to r694)
+pywbem-0.8.0-dev.r696 (last updated: 2015-01-16, includes commits up to r696)
ENHANCEMENTS:
@@ -188,6 +188,9 @@
on Python 2.6.
(Andreas Maier)
+ * Fixed bug where HTTP body was attempted ot be read when CIMError header
+ is set, causing a hang. (Andreas Maier)
+
TESTING:
* Added support for running the unit test cases without having to be in the
Modified: pywbem/trunk/pywbem/cim_http.py
===================================================================
--- pywbem/trunk/pywbem/cim_http.py 2015-01-16 09:30:41 UTC (rev 696)
+++ pywbem/trunk/pywbem/cim_http.py 2015-01-16 10:48:49 UTC (rev 697)
@@ -361,7 +361,6 @@
raise
response = h.getresponse()
- body = response.read()
if response.status != 200:
if response.status == 401:
@@ -429,6 +428,8 @@
urllib.unquote(response.getheader('PGErrorDetail'))))
raise Error('HTTP error: %s' % response.reason)
+ body = response.read()
+
except httplib.BadStatusLine, arg:
raise Error("The web server returned a bad status line: '%s'" % arg)
except socket.error, arg:
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <ma...@us...> - 2015-01-16 10:54:54
|
Revision: 695
http://sourceforge.net/p/pywbem/code/695
Author: maiera
Date: 2015-01-16 09:28:30 +0000 (Fri, 16 Jan 2015)
Log Message:
-----------
Added commit level to file name of generated distribution archive.
Modified Paths:
--------------
pywbem/trunk/makefile
Added Paths:
-----------
pywbem/dist/pywbem-0.8.0/README-0.8.0-dev.rst
pywbem/dist/pywbem-0.8.0/pywbem-0.8.0-dev.r694.zip
Removed Paths:
-------------
pywbem/dist/pywbem-0.8.0/pywbem-0.8.0-dev.zip
Added: pywbem/dist/pywbem-0.8.0/README-0.8.0-dev.rst
===================================================================
--- pywbem/dist/pywbem-0.8.0/README-0.8.0-dev.rst (rev 0)
+++ pywbem/dist/pywbem-0.8.0/README-0.8.0-dev.rst 2015-01-16 09:28:30 UTC (rev 695)
@@ -0,0 +1,9 @@
+PyWBEM v0.8.0-dev
+-----------------
+
+**Attention:** This version of PyWBEM is still in development (as indicated by
+the "-dev" suffix in the version string).
+
+The NEWS file in the download archive describes the changes up to now.
+
+Please report any issues using the PyWBEM bug tracker on SourceForge.
Added: pywbem/dist/pywbem-0.8.0/pywbem-0.8.0-dev.r694.zip
===================================================================
(Binary files differ)
Index: pywbem/dist/pywbem-0.8.0/pywbem-0.8.0-dev.r694.zip
===================================================================
--- pywbem/dist/pywbem-0.8.0/pywbem-0.8.0-dev.r694.zip 2015-01-16 09:25:20 UTC (rev 694)
+++ pywbem/dist/pywbem-0.8.0/pywbem-0.8.0-dev.r694.zip 2015-01-16 09:28:30 UTC (rev 695)
Property changes on: pywbem/dist/pywbem-0.8.0/pywbem-0.8.0-dev.r694.zip
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Deleted: pywbem/dist/pywbem-0.8.0/pywbem-0.8.0-dev.zip
===================================================================
(Binary files differ)
Modified: pywbem/trunk/makefile
===================================================================
--- pywbem/trunk/makefile 2015-01-16 09:25:20 UTC (rev 694)
+++ pywbem/trunk/makefile 2015-01-16 09:28:30 UTC (rev 695)
@@ -24,14 +24,20 @@
package_version := $(shell python -B setup.py --version)
package_final_version := $(shell sh -c "echo $(package_version) | sed s/-.*//")
+# Latest commit level of this Python package
+last_commit := $(strip $(shell sh -c "svn log .. -l 1 -q |grep -E ^r[0-9]+ |cut -d ' ' -f 1"))
+
# Directory for the generated distribution files
dist_dir := ../dist/$(package_name)-$(package_final_version)
# Generated distribution files (used as dependent).
-# Must be what setup.py creates in its build
-dist_file := $(dist_dir)/$(package_name)-$(package_version).zip
-win64_dist_file := $(dist_dir)/$(package_name)-$(package_version).win-amd64.exe
+# dist_build_file must be what setup.py creates in its build.
+# It will then be renamed to dist_file.
+dist_build_file := $(dist_dir)/$(package_name)-$(package_version).zip
+dist_file := $(dist_dir)/$(package_name)-$(package_version).$(last_commit).zip
+win64_dist_file := $(dist_dir)/$(package_name)-$(package_version).$(last_commit).win-amd64.exe
+
# Directory for generated API documentation
doc_out_dir := $(package_name)/docs
@@ -129,6 +135,7 @@
$(dist_file): setup.py MANIFEST.in $(dist_dependent_files)
rm -f MANIFEST
python setup.py build sdist -d $(dist_dir)
+ mv $(dist_build_file) $(dist_file)
$(win64_dist_file): setup.py MANIFEST.in $(dist_dependent_files)
rm -f MANIFEST
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <ma...@us...> - 2015-01-16 09:53:01
|
Revision: 694
http://sourceforge.net/p/pywbem/code/694
Author: maiera
Date: 2015-01-16 09:25:20 +0000 (Fri, 16 Jan 2015)
Log Message:
-----------
Updated change history.
Modified Paths:
--------------
pywbem/trunk/pywbem/NEWS
Modified: pywbem/trunk/pywbem/NEWS
===================================================================
--- pywbem/trunk/pywbem/NEWS 2015-01-16 08:45:37 UTC (rev 693)
+++ pywbem/trunk/pywbem/NEWS 2015-01-16 09:25:20 UTC (rev 694)
@@ -1,4 +1,4 @@
-pywbem-0.8.0~dev (last updated: 2014-11-06, includes commits up to r687)
+pywbem-0.8.0-dev.r694 (last updated: 2015-01-16, includes commits up to r694)
ENHANCEMENTS:
@@ -50,6 +50,9 @@
statement that they behave like dictionaries w.r.t. properties and key
bindings. (Andreas Maier)
+ * Improved help text of test_cim_operations.py test program.
+ (Andreas Maier)
+
BUG FIXES:
* Fix syntax error in CIM DTDVERSION error path. Allow KEYVALUE
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|