diff --git a/.gitignore b/.gitignore index 45c8368f..a59c25e5 100644 --- a/.gitignore +++ b/.gitignore @@ -46,3 +46,4 @@ output/*/index.html docs/_build .DS_Store +.idea diff --git a/HISTORY.rst b/HISTORY.rst index 43d4bd4d..a751a313 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -1,6 +1,10 @@ ======= History ======= +0.9.4 (2018-08-24) +-------------------- +* Support for Python3 + 0.9.3.1 (2018-05-27) -------------------- * Support for more APIs diff --git a/imcsdk/__init__.py b/imcsdk/__init__.py index f6cfa184..ad361eeb 100644 --- a/imcsdk/__init__.py +++ b/imcsdk/__init__.py @@ -57,4 +57,4 @@ def set_log_level(level=logging.DEBUG): __author__ = 'Cisco Systems' __email__ = 'ucs-python@cisco.com' -__version__ = '0.9.3.1' +__version__ = '0.9.4' diff --git a/imcsdk/apis/admin/ipmi.py b/imcsdk/apis/admin/ipmi.py index 5b9ade7d..dba5f6d3 100644 --- a/imcsdk/apis/admin/ipmi.py +++ b/imcsdk/apis/admin/ipmi.py @@ -54,7 +54,7 @@ def ipmi_enable(handle, priv=CommIpmiLanConsts.PRIV_ADMIN, Example: if ipmi_enable(handle): - print "IPMI Enabled" + print("IPMI Enabled") """ # Verify key is a hex number diff --git a/imcsdk/apis/server/vmedia.py b/imcsdk/apis/server/vmedia.py index 6b0ac9de..cb3a10cd 100644 --- a/imcsdk/apis/server/vmedia.py +++ b/imcsdk/apis/server/vmedia.py @@ -19,16 +19,14 @@ import time import re import logging -try: - from urllib.parse import urlsplit -except ImportError: - from urlparse import urlsplit from imcsdk.mometa.comm.CommVMedia import CommVMedia from imcsdk.mometa.comm.CommVMediaMap import CommVMediaMap from imcsdk.imcexception import ImcOperationError from imcsdk.apis.admin.ipmi import _get_comm_mo_dn +from six.moves import urllib + log = logging.getLogger('imc') CIFS_URI_PATTERN = re.compile('^//\d+\.\d+\.\d+\.\d+\/') @@ -293,9 +291,9 @@ def vmedia_mount_iso_uri(handle, uri, volume_name=None, user_id=None, mount_options = "noauto" # Set the Map based on the protocol - if urlsplit(uri).scheme == 'http': + if urllib.parse.urlsplit(uri).scheme == 'http': mount_protocol = "www" - elif urlsplit(uri).scheme == 'https': + elif urllib.parse.urlsplit(uri).scheme == 'https': mount_protocol = "www" elif CIFS_URI_PATTERN.match(uri): mount_protocol = "cifs" @@ -304,7 +302,7 @@ def vmedia_mount_iso_uri(handle, uri, volume_name=None, user_id=None, else: # Raise ValueError and bail raise ValueError("Unsupported protocol: " + - urlsplit(uri).scheme) + urllib.parse.urlsplit(uri).scheme) # Use remote filename if no volume_name givien if not volume_name: diff --git a/imcsdk/apis/v2/admin/ipmi.py b/imcsdk/apis/v2/admin/ipmi.py index 84981975..e51551c0 100644 --- a/imcsdk/apis/v2/admin/ipmi.py +++ b/imcsdk/apis/v2/admin/ipmi.py @@ -53,7 +53,7 @@ def ipmi_enable(handle, priv=None, key=None, server_id=1): Example: if ipmi_enable(handle): - print "IPMI Enabled" + print("IPMI Enabled") """ # Verify key is a hex number diff --git a/imcsdk/apis/v2/server/vmedia.py b/imcsdk/apis/v2/server/vmedia.py index 9416a3bd..3e9df71a 100644 --- a/imcsdk/apis/v2/server/vmedia.py +++ b/imcsdk/apis/v2/server/vmedia.py @@ -17,7 +17,6 @@ """ import os import time -import urlparse import re import logging @@ -26,6 +25,9 @@ from imcsdk.imcexception import ImcOperationError from imcsdk.apis.admin.ipmi import _get_comm_mo_dn +from six.moves import urllib + + log = logging.getLogger('imc') CIFS_URI_PATTERN = re.compile('^//\d+\.\d+\.\d+\.\d+\/') @@ -302,9 +304,9 @@ def vmedia_mount_iso_uri(handle, uri, user_id=None, password=None, mount_options = "noauto" # Set the Map based on the protocol - if urlparse.urlsplit(uri).scheme == 'http': + if urllib.parse.urlsplit(uri).scheme == 'http': mount_protocol = "www" - elif urlparse.urlsplit(uri).scheme == 'https': + elif urllib.parse.urlsplit(uri).scheme == 'https': mount_protocol = "www" elif CIFS_URI_PATTERN.match(uri): mount_protocol = "cifs" @@ -313,7 +315,7 @@ def vmedia_mount_iso_uri(handle, uri, user_id=None, password=None, else: # Raise ValueError and bail raise ValueError("Unsupported protocol: " + - urlparse.urlsplit(uri).scheme) + urllib.parse.urlsplit(uri).scheme) # Convert no user/pass to blank strings if not user_id: diff --git a/imcsdk/imcbasetype.py b/imcsdk/imcbasetype.py index 2f064b2a..71220350 100644 --- a/imcsdk/imcbasetype.py +++ b/imcsdk/imcbasetype.py @@ -20,12 +20,15 @@ from .imccore import BaseObject +import six + + class Method(BaseObject): """This is Method class.""" def __init__(self, **kwargs): BaseObject.__init__(self, "Method", "method") if kwargs: - for n, v in kwargs.iteritems(): + for n, v in six.iteritems(kwargs): self.attr_set(n, v) @@ -34,7 +37,7 @@ class ConfigConfig(BaseObject): def __init__(self, **kwargs): BaseObject.__init__(self, "ConfigConfig", "configConfig") if kwargs: - for n, v in kwargs.iteritems(): + for n, v in six.iteritems(kwargs): self.attr_set(n, v) @@ -43,7 +46,7 @@ class ConfigMap(BaseObject): def __init__(self, **kwargs): BaseObject.__init__(self, "ConfigMap", "configMap") if kwargs: - for n, v in kwargs.iteritems(): + for n, v in six.iteritems(kwargs): self.attr_set(n, v) @@ -52,7 +55,7 @@ class ConfigSet(BaseObject): def __init__(self, **kwargs): BaseObject.__init__(self, "ConfigSet", "configSet") if kwargs: - for n, v in kwargs.iteritems(): + for n, v in six.iteritems(kwargs): self.attr_set(n, v) @@ -65,7 +68,7 @@ def __init__(self, **kwargs): self.error_descr = None self.name = None if kwargs: - for n, v in kwargs.iteritems(): + for n, v in six.iteritems(kwargs): self.attr_set(n, v) @@ -74,7 +77,7 @@ class FailedMos(BaseObject): def __init__(self, **kwargs): BaseObject.__init__(self, "FailedMos", "failedMos") if kwargs: - for n, v in kwargs.iteritems(): + for n, v in six.iteritems(kwargs): self.attr_set(n, v) @@ -83,7 +86,7 @@ class FilterFilter(BaseObject): def __init__(self, **kwargs): BaseObject.__init__(self, "FilterFilter", "filter") if kwargs: - for n, v in kwargs.iteritems(): + for n, v in six.iteritems(kwargs): self.attr_set(n, v) @@ -93,6 +96,6 @@ def __init__(self, **kwargs): BaseObject.__init__(self, "Pair", "pair") self.key = None if kwargs: - for n, v in kwargs.iteritems(): + for n, v in six.iteritems(kwargs): self.attr_set(n, v) diff --git a/imcsdk/imccoreutils.py b/imcsdk/imccoreutils.py index d1315e9a..b93298fc 100644 --- a/imcsdk/imccoreutils.py +++ b/imcsdk/imccoreutils.py @@ -201,7 +201,6 @@ def find_class_id_in_mo_meta_ignore_case(class_id): return None if class_id in MO_CLASS_ID: return class_id - # print class_id l_class_id = class_id.lower() for key in MO_CLASS_ID: if key.lower() == l_class_id: @@ -272,10 +271,10 @@ def write_object(mo_or_list): for mo in mo_or_list: if (isinstance(mo, imcmo.ManagedObject) or isinstance(mo, imcmo.GenericMo)): - print (mo) + print(mo) elif (isinstance(mo_or_list, imcmo.ManagedObject) or isinstance(mo_or_list, imcmo.GenericMo)): - print (mo_or_list) + print(mo_or_list) def extract_molist_from_method_response(method_response, @@ -387,8 +386,6 @@ def write_mo_tree(mo, level=0, depth=None, show_level=[], else: tree_dict[key_all_mo][mo.class_id].append(mo) - # print tree_dict - if print_tree: if not show_level: print("%s %s (%s)" % (level_indent, mo.dn, mo.class_id)) diff --git a/imcsdk/imcdriver.py b/imcsdk/imcdriver.py index 37414a73..b8b11b40 100644 --- a/imcsdk/imcdriver.py +++ b/imcsdk/imcdriver.py @@ -17,23 +17,19 @@ import sys import socket import ssl +import logging -try: - import urllib2 - import httplib - from urllib2 import HTTPError -except: - import urllib.request as urllib2 - import http.client as httplib - from urllib.error import HTTPError - +from six.moves import urllib as urllib2 +from six.moves import http_client as httplib +from six.moves.urllib import request as Request +from six.moves.urllib.error import HTTPError +from six.moves.urllib.request import HTTPRedirectHandler, HTTPSHandler -import logging log = logging.getLogger('imc') -class SmartRedirectHandler(urllib2.HTTPRedirectHandler): +class SmartRedirectHandler(HTTPRedirectHandler): """This class is to handle redirection error.""" def http_error_301(self, req, fp, code, msg, headers): @@ -47,11 +43,11 @@ def http_error_302(self, req, fp, code, msg, headers): return resp_status -class TLS1Handler(urllib2.HTTPSHandler): +class TLS1Handler(HTTPSHandler): """Like HTTPSHandler but more specific""" def __init__(self): - urllib2.HTTPSHandler.__init__(self) + HTTPSHandler.__init__(self) def https_open(self, req): return self.do_open(TLS1Connection, req) @@ -85,11 +81,11 @@ def connect(self): ssl_version=ssl.PROTOCOL_TLSv1) -class TLSHandler(urllib2.HTTPSHandler): +class TLSHandler(HTTPSHandler): """Like HTTPSHandler but more specific""" def __init__(self): - urllib2.HTTPSHandler.__init__(self) + HTTPSHandler.__init__(self) def https_open(self, req): return self.do_open(TLSConnection, req) @@ -225,7 +221,7 @@ def __create_request(self, uri, data=None): web request object """ - request_ = urllib2.Request(url=uri, data=data) + request_ = Request.Request(url=uri, data=data) headers = self.__headers for header in headers: request_.add_header(header, headers[header]) @@ -259,7 +255,7 @@ def post(self, uri, data=None, dump_xml=False, read=True, timeout=None): if dump_xml: log.debug('%s ====> %s' % (uri, data)) - opener = urllib2.build_opener(*self.__handlers) + opener = Request.build_opener(*self.__handlers) try: response = opener.open(request, timeout=timeout) except Exception as e: @@ -273,7 +269,7 @@ def post(self, uri, data=None, dump_xml=False, read=True, timeout=None): # Fallback to TLSv1 for this server self.update_handlers(tls_proto="tlsv1") - opener = urllib2.build_opener(*self.__handlers) + opener = Request.build_opener(*self.__handlers) response = opener.open(request, timeout=timeout) if type(response) is list: @@ -286,7 +282,7 @@ def post(self, uri, data=None, dump_xml=False, read=True, timeout=None): if dump_xml: log.debug('%s <==== %s' % (uri, data)) - opener = urllib2.build_opener(*self.__handlers) + opener = Request.build_opener(*self.__handlers) response = opener.open(request, timeout=timeout) # response = urllib2.urlopen(request) if read: diff --git a/imcsdk/imceventhandler.py b/imcsdk/imceventhandler.py index 3e90059a..ecf4d0e8 100644 --- a/imcsdk/imceventhandler.py +++ b/imcsdk/imceventhandler.py @@ -18,16 +18,13 @@ from __future__ import print_function -try: - from Queue import Queue -except: - from queue import Queue - -from threading import Condition, Lock, Thread import datetime import logging import time +from threading import Condition, Lock, Thread +from six.moves import queue + from . import imcmo from . import imccoreutils from . import imcxmlcodec as xc @@ -64,7 +61,7 @@ def __init__(self, params, fmce, capacity, callback): self.params = params self.overflow = False self.error_code = 0 # TODO:error_code to call notify as per PowerTool - self.event_q = Queue() # infinite size Queue + self.event_q = queue.Queue() # infinite size Queue def dequeue(self, miliseconds_timeout): """Internal method to dequeue the events.""" diff --git a/imcsdk/imcfilter.py b/imcsdk/imcfilter.py index 850a7cf4..1429376a 100644 --- a/imcsdk/imcfilter.py +++ b/imcsdk/imcfilter.py @@ -89,7 +89,7 @@ def and_operator(toks): """ # print str, loc, toks - # print toks[0][0::2] + # print(toks[0][0::2]) and_filter = AndFilter() for op_filter in toks[0][0::2]: and_filter.child_add(op_filter) @@ -102,7 +102,7 @@ def or_operator(toks): """ # print str, loc, toks - # print toks[0][0::2] + # print(toks[0][0::2]) or_filter = OrFilter() for op_filter in toks[0][0::2]: or_filter.child_add(op_filter) diff --git a/imcsdk/imcgenutils.py b/imcsdk/imcgenutils.py index 75d12be3..cc4a4d7d 100644 --- a/imcsdk/imcgenutils.py +++ b/imcsdk/imcgenutils.py @@ -24,12 +24,14 @@ import platform import re import subprocess - import logging +import six + +from six.moves import range +from .imcexception import ImcWarning, ImcValidationException log = logging.getLogger('imc') -from .imcexception import ImcWarning, ImcValidationException AFFIRMATIVE_LIST = ['true', 'True', 'TRUE', True, 'yes', 'Yes', 'YES'] @@ -67,7 +69,6 @@ def to_python_propname(word): """ Converts any word to lowercase word separated by underscore """ - return re.sub('_+', '_', re.sub('^_', '', re.sub('[/\-: +]', '_', @@ -174,10 +175,6 @@ def download_file(driver, file_url, file_dir, file_name, progress=Progress()): download_file(driver=ImcDriver(), file_url="http://fileurl", file_dir='/home/user/backup', file_name='my_config_backup.xml') """ - - import os - from sys import stdout - destination_file = os.path.join(file_dir, file_name) response = driver.post(uri=file_url, read=False) @@ -412,18 +409,13 @@ def expand_key(key, clen): """ Internal method supporting encryption and decryption functionality. """ - try: - xrange - except: - xrange = range - import hashlib from array import array blocks = (clen + 19) / 20 x_key = [] seed = key - for i_cnt in xrange(blocks): + for i_cnt in range(blocks): seed = hashlib.md5(key + seed).digest() x_key.append(seed) j_str = ''.join(x_key) @@ -444,11 +436,6 @@ def encrypt_password(password, key): import hmac import base64 - try: - xrange - except: - xrange = range - h_hash = get_sha_hash uhash = h_hash(','.join(str(x) for x in [repr(time()), repr(os.getpid()), @@ -459,7 +446,7 @@ def encrypt_password(password, key): password_stream = array('L', password + '0000'[pwd_len & 3:]) x_key = expand_key(k_enc, pwd_len + 4) - for i_cnt in xrange(len(password_stream)): + for i_cnt in range(len(password_stream)): password_stream[i_cnt] = password_stream[i_cnt] ^ x_key[i_cnt] cipher_t = uhash + password_stream.tostring()[:pwd_len] @@ -479,11 +466,6 @@ def decrypt_password(cipher, key): import base64 from array import array - try: - xrange - except: - xrange = range - h_hash = get_sha_hash cipher += "\n" @@ -501,7 +483,7 @@ def decrypt_password(cipher, key): password_stream = array('L', password_stream) x_key = expand_key(k_enc, cipher_len + 4) - for i in xrange(len(password_stream)): + for i in range(len(password_stream)): password_stream[i] = password_stream[i] ^ x_key[i] decrypted_password = password_stream.tostring()[:cipher_len] @@ -512,8 +494,4 @@ def iteritems(d): """ Factor-out Py2-to-3 differences in dictionary item iterator methods """ - - try: - return d.iteritems() - except AttributeError: - return d.items() + return six.iteritems(d) diff --git a/imcsdk/imcmethod.py b/imcsdk/imcmethod.py index 0719e979..12412d5f 100644 --- a/imcsdk/imcmethod.py +++ b/imcsdk/imcmethod.py @@ -156,7 +156,6 @@ def from_xml(self, elem, handle=None): if child_obj: self.set_attr(child_name, child_obj) - # print child_method_obj.__dict__ child_obj.from_xml(child_elem, handle) def __str__(self): diff --git a/imcsdk/imcmo.py b/imcsdk/imcmo.py index 154a8aeb..75148db3 100644 --- a/imcsdk/imcmo.py +++ b/imcsdk/imcmo.py @@ -23,6 +23,7 @@ from . import imcgenutils from . import imccoreutils from . import imccoremeta +import six try: import xml.etree.cElementTree as ET @@ -53,7 +54,7 @@ class ManagedObject(ImcBase): This class structures/represents all the managed objects. """ - DUMMY_DIRTY = "0x1L" + DUMMY_DIRTY = "0x1" __internal_prop = frozenset( ["_dirty_mask", "_class_id", "_child", "_handle", '']) @@ -74,7 +75,7 @@ def __init__( self.__parent_mo = parent_mo_or_dn self.__parent_dn = self.__parent_mo.dn elif isinstance(parent_mo_or_dn, str) or \ - isinstance(parent_mo_or_dn, unicode): + isinstance(parent_mo_or_dn, six.text_type): self.__parent_dn = str(parent_mo_or_dn) else: raise ValueError('parent mo or dn must be specified') diff --git a/imcsdk/imcxmlcodec.py b/imcsdk/imcxmlcodec.py index 2ed65fd8..ad10edb7 100644 --- a/imcsdk/imcxmlcodec.py +++ b/imcsdk/imcxmlcodec.py @@ -58,7 +58,8 @@ def extract_root_elem(xml_str): ''' root_element = extract_root_elem(xml_str) """ - + if type(xml_str) is not str: + xml_str = xml_str.decode('utf-8') xml_str = xml_str.strip("\x00") root_elem = ET.fromstring(xml_str) return root_elem @@ -82,7 +83,8 @@ def from_xml_str(xml_str, handle=None): '''\n root_element = extract_root_elem(xml_str)\n """ - + if type(xml_str) is not str: + xml_str = xml_str.decode('utf-8') xml_str = xml_str.strip("\x00") root_elem = ET.fromstring(xml_str) if root_elem.tag == "error": diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 00000000..8a8af629 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +pyparsing +six diff --git a/setup.cfg b/setup.cfg index c74fc857..74a2eae9 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,15 +1,11 @@ [bumpversion] -current_version = 0.9.3.1 -commit = True -tag = True +current_version = 0.9.4 +commit = False +tag = False [bumpversion:file:setup.py] -search = version='{current_version}' -replace = version='{new_version}' [bumpversion:file:imcsdk/__init__.py] -search = __version__ = '{current_version}' -replace = __version__ = '{new_version}' [wheel] universal = 1 @@ -19,3 +15,4 @@ exclude = docs [metadata] description-file = README.rst + diff --git a/setup.py b/setup.py index dbc52442..0ac5b99a 100644 --- a/setup.py +++ b/setup.py @@ -7,6 +7,11 @@ except ImportError: from distutils.core import setup +with open('requirements.txt') as rf: + requirements = rf.readlines() + +with open('test-requirements.txt') as rf: + test_requirements = rf.readlines() with open('README.rst') as readme_file: readme = readme_file.read() @@ -14,17 +19,9 @@ with open('HISTORY.rst') as history_file: history = history_file.read() -requirements = [ - # TODO: put package requirements here -] - -test_requirements = [ - # TODO: put package test requirements here -] - setup( name='imcsdk', - version='0.9.3.1', + version='0.9.4', description="python SDK for Cisco UCS IMC", long_description=readme + '\n\n' + history, author="Cisco Systems", @@ -36,7 +33,7 @@ package_dir={'imcsdk': 'imcsdk'}, include_package_data=True, - install_requires=['pyparsing'], + install_requires=requirements, license="http://www.apache.org/licenses/LICENSE-2.0", zip_safe=False, keywords='imcsdk', @@ -53,7 +50,7 @@ 'Programming Language :: Python :: 3.4', 'Programming Language :: Python :: 3.5', ], - tests_require=['nose'], + tests_require=test_requirements, test_suite='nose.collector', extras_require={ 'ssl': ['pyOpenSSL'], diff --git a/test-requirements.txt b/test-requirements.txt new file mode 100644 index 00000000..f3c7e8e6 --- /dev/null +++ b/test-requirements.txt @@ -0,0 +1 @@ +nose diff --git a/tests/connection/info.py b/tests/connection/info.py index 77f1f05d..8fe8f9d6 100644 --- a/tests/connection/info.py +++ b/tests/connection/info.py @@ -12,19 +12,16 @@ # limitations under the License. import os +from six.moves import configparser CONNECTION_CFG_FILEPATH = os.path.join(os.path.dirname(__file__), '..', 'connection', 'connection.cfg') -def custom_setup(host="imc"): - try: - import ConfigParser - except: - import configparser as ConfigParser +def custom_setup(host="imc"): from imcsdk.imchandle import ImcHandle - config = ConfigParser.RawConfigParser() + config = configparser.RawConfigParser() config.read(CONNECTION_CFG_FILEPATH) hostname = config.get(host, "hostname") diff --git a/tests/session/test_imcsession.py b/tests/session/test_imcsession.py index 73cb6903..9ae1842d 100644 --- a/tests/session/test_imcsession.py +++ b/tests/session/test_imcsession.py @@ -79,7 +79,7 @@ def test_imc_no_timeout(): @raises(Exception) def test_imc_timeout(): - import urllib2 + from six.moves import urllib global handle server_dn = get_server_dn(handle) @@ -88,22 +88,18 @@ def test_imc_timeout(): mo.usr_lbl = usr_lbl try: handle.set_mo(mo, timeout=1) - except urllib2.URLError as e: + except urllib.error.URLError: print("Hit expected error") raise Exception def test_imc_context_manager_no_timeout(): - try: - import ConfigParser - except: - import configparser as ConfigParser - + from six.moves import configparser from imcsdk.imchandle import ImcHandle from ..connection import info host = 'imc' - config = ConfigParser.RawConfigParser() + config = configparser.RawConfigParser() config.read(info.CONNECTION_CFG_FILEPATH) hostname = config.get(host, "hostname") username = config.get(host, "username")