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. |