From 8269f6b89b82d522b6d06430df4f7b27189e15a9 Mon Sep 17 00:00:00 2001 From: Mike Raineri Date: Fri, 12 Feb 2021 14:11:48 -0500 Subject: [PATCH 1/3] Removed Python2 support --- README.rst | 52 ++++++------ examples/context_manager.py | 5 +- examples/discover.py | 5 +- examples/quickstart.py | 7 +- examples/quickstart_rmc.py | 7 +- requirements.txt | 2 +- setup.py | 11 ++- src/redfish/__init__.py | 7 +- src/redfish/discovery/__init__.py | 2 +- src/redfish/discovery/discovery.py | 9 ++- src/redfish/rest/__init__.py | 5 +- src/redfish/rest/v1.py | 124 ++++++++++++++++------------- src/redfish/ris/__init__.py | 5 +- src/redfish/ris/config.py | 12 +-- src/redfish/ris/ris.py | 11 ++- src/redfish/ris/rmc.py | 95 ++++++++++++---------- src/redfish/ris/rmc_helper.py | 64 +++++++-------- src/redfish/ris/sharedtypes.py | 7 +- tests/__init__.py | 4 + tests/discovery/__init__.py | 4 + tests/discovery/test_discovery.py | 7 +- tests/rest/__init__.py | 4 + tests/rest/test_v1.py | 5 ++ tests/ris/__init__.py | 4 + tests/ris/test_config.py | 46 ++--------- tests/ris/test_ris.py | 5 ++ tests/ris/test_rmc_helper.py | 4 +- tox.ini | 10 +-- 28 files changed, 279 insertions(+), 244 deletions(-) diff --git a/README.rst b/README.rst index d421cbd..3262db5 100644 --- a/README.rst +++ b/README.rst @@ -4,15 +4,15 @@ python-redfish-library .. image:: https://travis-ci.org/DMTF/python-redfish-library.svg?branch=master :target: https://travis-ci.org/DMTF/python-redfish-library .. image:: https://img.shields.io/pypi/v/redfish.svg?maxAge=2592000 - :target: https://pypi.python.org/pypi/redfish + :target: https://pypi.python.org/pypi/redfish .. image:: https://img.shields.io/github/release/DMTF/python-redfish-library.svg?maxAge=2592000 - :target: https://github.com/DMTF/python-redfish-library/releases + :target: https://github.com/DMTF/python-redfish-library/releases .. image:: https://img.shields.io/badge/License-BSD%203--Clause-blue.svg - :target: https://raw.githubusercontent.com/DMTF/python-redfish-library/master/LICENSE + :target: https://raw.githubusercontent.com/DMTF/python-redfish-library/master/LICENSE .. image:: https://img.shields.io/pypi/pyversions/redfish.svg?maxAge=2592000 - :target: https://pypi.python.org/pypi/redfish + :target: https://pypi.python.org/pypi/redfish .. image:: https://api.codacy.com/project/badge/Grade/1283adc3972d42b4a3ddb9b96660bc07 - :target: https://www.codacy.com/app/rexysmydog/python-redfish-library?utm_source=github.com&utm_medium=referral&utm_content=DMTF/python-redfish-library&utm_campaign=Badge_Grade + :target: https://www.codacy.com/app/rexysmydog/python-redfish-library?utm_source=github.com&utm_medium=referral&utm_content=DMTF/python-redfish-library&utm_campaign=Badge_Grade .. contents:: :depth: 1 @@ -21,6 +21,8 @@ python-redfish-library Description ----------- +As of version 3.0.0, Python2 is no longer supported. If Python2 is required, ``redfish<3.0.0`` can be specified in a requirements file. + REST (Representational State Transfer) is a web based software architectural style consisting of a set of constraints that focuses on a system's resources. The Redfish library performs the basic HTTPS operations GET, POST, PUT, PATCH and DELETE on resources using the HATEOAS (Hypermedia as the Engine of Application State) Redfish architecture. API clients allow you to manage and interact with the system through a fixed URL and several URIs. Go to the `wiki <../../wiki>`_ for more details. @@ -29,7 +31,7 @@ Installing .. code-block:: console - pip install redfish + pip install redfish Building from zip file source @@ -37,9 +39,9 @@ Building from zip file source .. code-block:: console - python setup.py sdist --formats=zip (this will produce a .zip file) - cd dist - pip install redfish-x.x.x.zip + python setup.py sdist --formats=zip (this will produce a .zip file) + cd dist + pip install redfish-x.x.x.zip Requirements @@ -63,7 +65,7 @@ For Redfish compliant application: .. code-block:: python - import redfish + import redfish Create a Redfish Object @@ -75,7 +77,7 @@ To crete a Redfish Object, call the redfish_client method: .. code-block:: python - REDFISH_OBJ = redfish.redfish_client(base_url=login_host, username=login_account, \ + REDFISH_OBJ = redfish.redfish_client(base_url=login_host, username=login_account, \ password=login_password, default_prefix='/redfish/v1') @@ -86,7 +88,7 @@ The login operation is performed when creating the REDFISH_OBJ. You can continue .. code-block:: python - REDFISH_OBJ.login(auth="session") + REDFISH_OBJ.login(auth="session") Perform a GET operation @@ -97,7 +99,7 @@ An example of rawget operation on the path "/redfish/v1/systems/1" is shown belo .. code-block:: python - response = REDFISH_OBJ.get("/redfish/v1/systems/1", None) + response = REDFISH_OBJ.get("/redfish/v1/systems/1", None) Perform a POST operation @@ -108,8 +110,8 @@ An example of a POST operation on the path "/redfish/v1/systems/1/Actions/Comput .. code-block:: python - body = {"ResetType": "GracefulShutdown"} - response = REDFISH_OBJ.post("/redfish/v1/systems/1/Actions/ComputerSystem.Reset", body=body) + body = {"ResetType": "GracefulShutdown"} + response = REDFISH_OBJ.post("/redfish/v1/systems/1/Actions/ComputerSystem.Reset", body=body) Working with Tasks @@ -121,8 +123,8 @@ An example of a POST operation with a possible Task is shown below. .. code-block:: python - body = {"ResetType": "GracefulShutdown"} - response = REDFISH_OBJ.post("/redfish/v1/systems/1/Actions/ComputerSystem.Reset", body=body) + body = {"ResetType": "GracefulShutdown"} + response = REDFISH_OBJ.post("/redfish/v1/systems/1/Actions/ComputerSystem.Reset", body=body) if(response.is_processing): task = response.monitor(context) @@ -140,7 +142,7 @@ Make sure you logout every session you create as it will remain alive until it t .. code-block:: python - REDFISH_OBJ.logout() + REDFISH_OBJ.logout() A logout deletes the current sesssion from the system. The redfish_client object destructor includes a logout statement. @@ -168,16 +170,18 @@ Contributing Release Process --------------- -1. Update `CHANGELOG.md` with the list of changes since the last release -2. Update the ``__version__`` variable in ``src/redfish/__init__.py``, and ``setup.py`` to reflect the new library version -3. Push changes to Github -4. Create a new release in Github -5. Push the new library version to pypi.org: ``python setup.py sdist && twine upload dist/*`` +Run the `release.sh` script to publish a new version. + +.. code-block:: shell + + sh release.sh + +Enter the release notes when prompted; an empty line signifies no more notes to add. Copyright and License --------------------- Copyright Notice: -Copyright 2016-2019 DMTF. All rights reserved. +Copyright 2016-2021 DMTF. All rights reserved. License: BSD 3-Clause License. For full text see link: `https://github.com/DMTF/python-redfish-library/blob/master/LICENSE.md `_ diff --git a/examples/context_manager.py b/examples/context_manager.py index 8fedd51..c0b60d5 100644 --- a/examples/context_manager.py +++ b/examples/context_manager.py @@ -1,6 +1,7 @@ # Copyright Notice: -# Copyright 2016-2019 DMTF. All rights reserved. -# License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/python-redfish-library/blob/master/LICENSE.md +# Copyright 2016-2021 DMTF. All rights reserved. +# License: BSD 3-Clause License. For full text see link: +# https://github.com/DMTF/python-redfish-library/blob/master/LICENSE.md import sys import redfish diff --git a/examples/discover.py b/examples/discover.py index c135778..3ad06fe 100644 --- a/examples/discover.py +++ b/examples/discover.py @@ -1,6 +1,7 @@ # Copyright Notice: -# Copyright 2016-2019 DMTF. All rights reserved. -# License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/python-redfish-library/blob/master/LICENSE.md +# Copyright 2016-2021 DMTF. All rights reserved. +# License: BSD 3-Clause License. For full text see link: +# https://github.com/DMTF/python-redfish-library/blob/master/LICENSE.md import redfish diff --git a/examples/quickstart.py b/examples/quickstart.py index 2af847d..97b0243 100644 --- a/examples/quickstart.py +++ b/examples/quickstart.py @@ -1,6 +1,7 @@ # Copyright Notice: -# Copyright 2016-2019 DMTF. All rights reserved. -# License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/python-redfish-library/blob/master/LICENSE.md +# Copyright 2016-2021 DMTF. All rights reserved. +# License: BSD 3-Clause License. For full text see link: +# https://github.com/DMTF/python-redfish-library/blob/master/LICENSE.md import sys import redfish @@ -12,7 +13,7 @@ login_password = "password" ## Create a REDFISH object -REDFISH_OBJ = redfish.redfish_client(base_url=login_host, username=login_account, \ +REDFISH_OBJ = redfish.redfish_client(base_url=login_host, username=login_account, password=login_password, default_prefix='/redfish/v1') # Login into the server and create a session diff --git a/examples/quickstart_rmc.py b/examples/quickstart_rmc.py index 01505b2..c14865b 100644 --- a/examples/quickstart_rmc.py +++ b/examples/quickstart_rmc.py @@ -1,6 +1,7 @@ # Copyright Notice: -# Copyright 2016-2019 DMTF. All rights reserved. -# License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/python-redfish-library/blob/master/LICENSE.md +# Copyright 2016-2021 DMTF. All rights reserved. +# License: BSD 3-Clause License. For full text see link: +# https://github.com/DMTF/python-redfish-library/blob/master/LICENSE.md import os import sys @@ -10,7 +11,7 @@ from redfish import redfish_logger from redfish.ris import RmcApp, JSONEncoder -#Config logger used by Restful library +# Config logger used by Restful library LOGGERFILE = "RedfishApiExamples.log" LOGGERFORMAT = "%(asctime)s - %(name)s - %(levelname)s - %(message)s" LOGGER = redfish_logger(LOGGERFILE, LOGGERFORMAT, logging.ERROR) diff --git a/requirements.txt b/requirements.txt index fba487f..9435709 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ jsonpatch<=1.24 ; python_version == '3.4' -jsonpatch ; python_version >= '3.5' or python_version == '2.7' +jsonpatch ; python_version >= '3.5' jsonpath_rw jsonpointer diff --git a/setup.py b/setup.py index 814fe3c..eac341e 100644 --- a/setup.py +++ b/setup.py @@ -1,3 +1,8 @@ +# Copyright Notice: +# Copyright 2016-2021 DMTF. All rights reserved. +# License: BSD 3-Clause License. For full text see link: +# https://github.com/DMTF/python-redfish-library/blob/master/LICENSE.md + from setuptools import setup, find_packages from codecs import open from os import path @@ -14,9 +19,9 @@ author = 'DMTF, https://www.dmtf.org/standards/feedback', license='BSD 3-clause "New" or "Revised License"', classifiers=[ - 'Development Status :: 4 - Beta', + 'Development Status :: 5 - Production/Stable', 'License :: OSI Approved :: BSD License', - 'Programming Language :: Python', + 'Programming Language :: Python :: 3', 'Topic :: Communications' ], keywords='Redfish', @@ -31,7 +36,7 @@ ':python_version == "3.4"': [ 'jsonpatch<=1.24' ], - ':python_version >= "3.5" or python_version == "2.7"': [ + ':python_version >= "3.5"': [ 'jsonpatch' ] }) diff --git a/src/redfish/__init__.py b/src/redfish/__init__.py index 5413efb..a48cb44 100644 --- a/src/redfish/__init__.py +++ b/src/redfish/__init__.py @@ -1,11 +1,12 @@ # Copyright Notice: -# Copyright 2016-2019 DMTF. All rights reserved. -# License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/python-redfish-library/blob/master/LICENSE.md +# Copyright 2016-2021 DMTF. All rights reserved. +# License: BSD 3-Clause License. For full text see link: +# https://github.com/DMTF/python-redfish-library/blob/master/LICENSE.md """ Redfish restful library """ __all__ = ['rest', 'ris', 'discovery'] -__version__ = "2.1.9" +__version__ = "2.1.9" from redfish.rest.v1 import redfish_client from redfish.rest.v1 import AuthMethod diff --git a/src/redfish/discovery/__init__.py b/src/redfish/discovery/__init__.py index d79f734..d8d04f8 100644 --- a/src/redfish/discovery/__init__.py +++ b/src/redfish/discovery/__init__.py @@ -1,4 +1,4 @@ # Copyright Notice: -# Copyright 2016-2019 DMTF. All rights reserved. +# Copyright 2016-2021 DMTF. All rights reserved. # License: BSD 3-Clause License. For full text see link: # https://github.com/DMTF/python-redfish-library/blob/master/LICENSE.md diff --git a/src/redfish/discovery/discovery.py b/src/redfish/discovery/discovery.py index 0d7816b..614540f 100644 --- a/src/redfish/discovery/discovery.py +++ b/src/redfish/discovery/discovery.py @@ -1,16 +1,16 @@ # Copyright Notice: -# Copyright 2016-2019 DMTF. All rights reserved. +# Copyright 2016-2021 DMTF. All rights reserved. # License: BSD 3-Clause License. For full text see link: # https://github.com/DMTF/python-redfish-library/blob/master/LICENSE.md # -*- coding: utf-8 -*- """Discovers Redfish services""" +import http.client import re import socket -from six import BytesIO -from six.moves import http_client +from io import BytesIO class FakeSocket: @@ -26,6 +26,7 @@ def makefile(self, *args, **kwargs): def sanitize(number, minimum, maximum=None): """ Sanity check a given number. + :param number: the number to check :param minimum: the minimum acceptable number :param maximum: the maximum acceptable number (optional) @@ -101,7 +102,7 @@ def discover_ssdp(port=1900, ttl=2, response_time=3, iface=None, protocol="ipv4" "^uuid:([a-f0-9\-]*)::urn:dmtf-org:service:redfish-rest:1(:\d)?$") # noqa while True: try: - response = http_client.HTTPResponse(FakeSocket(sock.recv(1024))) + response = http.client.HTTPResponse(FakeSocket(sock.recv(1024))) response.begin() uuid_search = pattern.search(response.getheader("USN").lower()) if uuid_search: diff --git a/src/redfish/rest/__init__.py b/src/redfish/rest/__init__.py index 0dc41d8..f513583 100644 --- a/src/redfish/rest/__init__.py +++ b/src/redfish/rest/__init__.py @@ -1,5 +1,6 @@ # Copyright Notice: -# Copyright 2016-2019 DMTF. All rights reserved. -# License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/python-redfish-library/blob/master/LICENSE.md +# Copyright 2016-2021 DMTF. All rights reserved. +# License: BSD 3-Clause License. For full text see link: +# https://github.com/DMTF/python-redfish-library/blob/master/LICENSE.md """ Utilities to simplify interaction with Redfish data """ diff --git a/src/redfish/rest/v1.py b/src/redfish/rest/v1.py index 92192ed..9a3ed32 100644 --- a/src/redfish/rest/v1.py +++ b/src/redfish/rest/v1.py @@ -1,6 +1,7 @@ # Copyright Notice: -# Copyright 2016-2019 DMTF. All rights reserved. -# License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/python-redfish-library/blob/master/LICENSE.md +# Copyright 2016-2021 DMTF. All rights reserved. +# License: BSD 3-Clause License. For full text see link: +# https://github.com/DMTF/python-redfish-library/blob/master/LICENSE.md # -*- coding: utf-8 -*- """Helper module for working with REST technology.""" @@ -14,19 +15,15 @@ import gzip import json import base64 -import urllib import logging import inspect +import http.client from collections import (OrderedDict) -import six -from six.moves.urllib.parse import urlparse, urlencode, urlunparse -from six.moves import http_client -from six import raise_from -from six import string_types -from six import StringIO -from six import BytesIO +from urllib.parse import urlparse, urlencode, quote +from io import StringIO +from io import BytesIO #---------End of imports--------- @@ -313,7 +310,7 @@ def __str__(self): headerstr += '%s %s\n' % (header[0], header[1]) return "%(status)s\n%(headerstr)s\n\n%(body)s" % \ - {'status': self.status, 'headerstr': headerstr, \ + {'status': self.status, 'headerstr': headerstr, 'body': self.text} class JSONEncoder(json.JSONEncoder): @@ -381,7 +378,7 @@ def __init__(self, **kwargs): if 'Content' in kwargs: content = kwargs['Content'] - if isinstance(content, string_types): + if isinstance(content, str): self._read = content else: self._read = json.dumps(content) @@ -469,14 +466,14 @@ def _get_connection(url, **kwargs): """ proxy = None if url.scheme.upper() == "HTTPS": - connection = http_client.HTTPSConnection + connection = http.client.HTTPSConnection if 'HTTPS_PROXY' in os.environ: host = urlparse(os.environ['HTTPS_PROXY']).netloc proxy = url.netloc else: host = url.netloc else: - connection = http_client.HTTPConnection + connection = http.client.HTTPConnection if 'HTTP_PROXY' in os.environ: host = urlparse(os.environ['HTTP_PROXY']).netloc proxy = url.netloc @@ -500,7 +497,7 @@ def __init_connection(self, url=None): url = url if url else self.__url if url.scheme.upper() == "HTTPS": - if sys.version_info < (2, 7, 9) and "context" not in inspect.getargspec(http_client.HTTPSConnection.__init__).args: + if sys.version_info < (2, 7, 9) and "context" not in inspect.getargspec(http.client.HTTPSConnection.__init__).args: self._conn = self._get_connection(url, timeout=self._timeout) else: if self.cafile or self.capath is not None: @@ -639,14 +636,16 @@ def get(self, path, args=None, headers=None): """Perform a GET request :param path: the URL path. - :param path: str. - :params args: the arguments to get. - :params args: dict. + :type path: str. + :param args: the arguments to get. + :type args: dict. + :param headers: dict of headers to be appended. + :type headers: dict. :returns: returns a rest request with method 'Get' """ try: - return self._rest_request(path, method='GET', args=args, \ + return self._rest_request(path, method='GET', args=args, headers=headers) except ValueError: LOGGER.debug("Error in json object getting path: %s" % path) @@ -656,22 +655,24 @@ def head(self, path, args=None, headers=None): """Perform a HEAD request :param path: the URL path. - :param path: str. - :params args: the arguments to get. - :params args: dict. + :type path: str. + :param args: the arguments to get. + :type args: dict. + :param headers: dict of headers to be appended. + :type headers: dict. :returns: returns a rest request with method 'Head' """ - return self._rest_request(path, method='HEAD', args=args, \ + return self._rest_request(path, method='HEAD', args=args, headers=headers) def post(self, path, args=None, body=None, headers=None): """Perform a POST request :param path: the URL path. - :param path: str. - :params args: the arguments to post. - :params args: dict. + :type path: str. + :param args: the arguments to post. + :type args: dict. :param body: the body to the sent. :type body: str. :param headers: dict of headers to be appended. @@ -679,7 +680,7 @@ def post(self, path, args=None, body=None, headers=None): :returns: returns a rest request with method 'Post' """ - return self._rest_request(path, method='POST', args=args, body=body, \ + return self._rest_request(path, method='POST', args=args, body=body, headers=headers) def put(self, path, args=None, body=None, headers=None): @@ -696,7 +697,7 @@ def put(self, path, args=None, body=None, headers=None): :returns: returns a rest request with method 'Put' """ - return self._rest_request(path, method='PUT', args=args, body=body, \ + return self._rest_request(path, method='PUT', args=args, body=body, headers=headers) def patch(self, path, args=None, body=None, headers=None): @@ -713,7 +714,7 @@ def patch(self, path, args=None, body=None, headers=None): :returns: returns a rest request with method 'Patch' """ - return self._rest_request(path, method='PATCH', args=args, body=body, \ + return self._rest_request(path, method='PATCH', args=args, body=body, headers=headers) def delete(self, path, args=None, headers=None): @@ -728,7 +729,7 @@ def delete(self, path, args=None, headers=None): :returns: returns a rest request with method 'Delete' """ - return self._rest_request(path, method='DELETE', args=args, \ + return self._rest_request(path, method='DELETE', args=args, headers=headers) def _get_req_headers(self, headers=None): @@ -754,7 +755,7 @@ def _get_req_headers(self, headers=None): return headers - def _rest_request(self, path, method='GET', args=None, body=None, \ + def _rest_request(self, path, method='GET', args=None, body=None, headers=None): """Rest request main function @@ -811,7 +812,20 @@ def _rest_request(self, path, method='GET', args=None, body=None, \ if args: if method == 'GET': - reqpath += '?' + urlencode(args) + # Workaround for this bug: https://bugs.python.org/issue18857 + none_list = [] + args_copy = {} + for query in args: + if args[query] is None: + none_list.append(query) + else: + args_copy[query] = args[query] + reqpath += '?' + urlencode(args_copy, quote_via=quote) + for query in none_list: + if reqpath[-1] == '?': + reqpath += query + else: + reqpath += '&' + query elif method == 'PUT' or method == 'POST' or method == 'PATCH': LOGGER.warning('For POST, PUT and PATCH methods, the provided "args" parameter "{}" is ignored.' .format(args)) @@ -845,7 +859,7 @@ def _rest_request(self, path, method='GET', args=None, body=None, \ if self._conn is None: self.__init_connection() - self._conn.request(method.upper(), reqpath, body=body, \ + self._conn.request(method.upper(), reqpath, body=body, headers=headers) self._conn_count += 1 @@ -888,7 +902,7 @@ def _rest_request(self, path, method='GET', args=None, body=None, \ decompressedfile = gzip.GzipFile(fileobj=compressedfile) restresp.text = decompressedfile.read().decode("utf-8") except Exception as excp: - LOGGER.error('Error occur while decompressing body: %s', \ + LOGGER.error('Error occur while decompressing body: %s', excp) raise DecompressResponseError() except Exception as excp: @@ -921,13 +935,13 @@ def _rest_request(self, path, method='GET', args=None, body=None, \ restresp._http_response.reason, headerstr, restresp.request.path, restresp.read)) except: - LOGGER.debug('HTTP RESPONSE:\nCode:%s', (restresp)) + LOGGER.debug('HTTP RESPONSE:\nCode:%s', restresp) else: LOGGER.debug('HTTP RESPONSE: ') return restresp else: - raise_from(RetriesExhaustedError(), cause_exception) + raise RetriesExhaustedError() from cause_exception def login(self, username=None, password=None, auth=AuthMethod.SESSION): """Login and start a REST session. Remember to call logout() when""" @@ -946,14 +960,14 @@ def login(self, username=None, password=None, auth=AuthMethod.SESSION): self.__password = password if password else self.__password if auth == AuthMethod.BASIC: - auth_key = base64.b64encode(('%s:%s' % (self.__username, \ + auth_key = base64.b64encode(('%s:%s' % (self.__username, self.__password)).encode('utf-8')).decode('utf-8') self.__authorization_key = 'Basic %s' % auth_key headers = dict() headers['Authorization'] = self.__authorization_key - respvalidate = self._rest_request('%s%s' % (self.__url.path, \ + respvalidate = self._rest_request('%s%s' % (self.__url.path, self.login_url), headers=headers) if respvalidate.status == 401: @@ -966,7 +980,7 @@ def login(self, username=None, password=None, auth=AuthMethod.SESSION): data['Password'] = self.__password headers = dict() - resp = self._rest_request(self.login_url, method="POST", \ + resp = self._rest_request(self.login_url, method="POST", body=data, headers=headers) LOGGER.info(json.loads('%s' % resp.text)) @@ -1004,10 +1018,10 @@ def logout(self): class HttpClient(RestClientBase): """A client for Rest""" - def __init__(self, base_url, username=None, password=None, \ - default_prefix='/redfish/v1/', \ - sessionkey=None, capath=None, \ - cafile=None, timeout=None, \ + def __init__(self, base_url, username=None, password=None, + default_prefix='/redfish/v1/', + sessionkey=None, capath=None, + cafile=None, timeout=None, max_retry=None): """Initialize HttpClient @@ -1031,10 +1045,10 @@ def __init__(self, base_url, username=None, password=None, \ :type max_retry: int """ - super(HttpClient, self).__init__(base_url, username=username, \ - password=password, default_prefix=default_prefix, \ - sessionkey=sessionkey, capath=capath, \ - cafile=cafile, timeout=timeout, \ + super(HttpClient, self).__init__(base_url, username=username, + password=password, default_prefix=default_prefix, + sessionkey=sessionkey, capath=capath, + cafile=cafile, timeout=timeout, max_retry=max_retry) try: @@ -1067,7 +1081,7 @@ def _rest_request(self, path='', method="GET", args=None, body=None, else: pass - return super(HttpClient, self)._rest_request(path=path, method=method, \ + return super(HttpClient, self)._rest_request(path=path, method=method, args=args, body=body, headers=headers) def _get_req_headers(self, headers=None, providerheader=None): @@ -1085,10 +1099,10 @@ def _get_req_headers(self, headers=None, providerheader=None): return headers -def redfish_client(base_url=None, username=None, password=None, \ - default_prefix='/redfish/v1/', \ - sessionkey=None, capath=None, \ - cafile=None, timeout=None, \ +def redfish_client(base_url=None, username=None, password=None, + default_prefix='/redfish/v1/', + sessionkey=None, capath=None, + cafile=None, timeout=None, max_retry=None): """Create and return appropriate REDFISH client instance.""" """ Instantiates appropriate Redfish object based on existing""" @@ -1115,7 +1129,7 @@ def redfish_client(base_url=None, username=None, password=None, \ :returns: a client object. """ - return HttpClient(base_url=base_url, username=username, password=password, \ - default_prefix=default_prefix, sessionkey=sessionkey, \ - capath=capath, cafile=cafile, timeout=timeout, \ + return HttpClient(base_url=base_url, username=username, password=password, + default_prefix=default_prefix, sessionkey=sessionkey, + capath=capath, cafile=cafile, timeout=timeout, max_retry=max_retry) diff --git a/src/redfish/ris/__init__.py b/src/redfish/ris/__init__.py index 5df8515..a962b01 100644 --- a/src/redfish/ris/__init__.py +++ b/src/redfish/ris/__init__.py @@ -1,6 +1,7 @@ # Copyright Notice: -# Copyright 2016-2019 DMTF. All rights reserved. -# License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/python-redfish-library/blob/master/LICENSE.md +# Copyright 2016-2021 DMTF. All rights reserved. +# License: BSD 3-Clause License. For full text see link: +# https://github.com/DMTF/python-redfish-library/blob/master/LICENSE.md # -*- coding: utf-8 -*- """ diff --git a/src/redfish/ris/config.py b/src/redfish/ris/config.py index ffab010..d5e130d 100644 --- a/src/redfish/ris/config.py +++ b/src/redfish/ris/config.py @@ -1,6 +1,7 @@ # Copyright Notice: -# Copyright 2016-2019 DMTF. All rights reserved. -# License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/python-redfish-library/blob/master/LICENSE.md +# Copyright 2016-2021 DMTF. All rights reserved. +# License: BSD 3-Clause License. For full text see link: +# https://github.com/DMTF/python-redfish-library/blob/master/LICENSE.md # -*- coding: utf-8 -*- """Module for working with global configuration options.""" @@ -10,8 +11,7 @@ import os import re import logging -import six -from six.moves import configparser +import configparser #---------End of imports--------- @@ -41,7 +41,7 @@ def __init__(self, filename=None): def _get_ac_keys(self): """Retrieve parse option keys""" result = [] - for key in six.iterkeys(self.__dict__): + for key in self.__dict__: match = AutoConfigParser._config_pattern.search(key) if match: result.append(match.group('confkey')) @@ -98,7 +98,7 @@ def load(self, filename=None): except configparser.NoOptionError: # also try with - instead of _ try: - configval = config.get(self._sectionname, \ + configval = config.get(self._sectionname, key.replace('_', '-')) except configparser.NoOptionError: pass diff --git a/src/redfish/ris/ris.py b/src/redfish/ris/ris.py index d4d528b..a4af89b 100644 --- a/src/redfish/ris/ris.py +++ b/src/redfish/ris/ris.py @@ -1,5 +1,5 @@ # Copyright Notice: -# Copyright 2016-2019 DMTF. All rights reserved. +# Copyright 2016-2021 DMTF. All rights reserved. # License: BSD 3-Clause License. For full text see link: # https://github.com/DMTF/python-redfish-library/blob/master/LICENSE.md @@ -12,6 +12,7 @@ import logging import sys import threading +from queue import Queue from collections import OrderedDict import jsonpath_rw @@ -19,10 +20,8 @@ import redfish.rest.v1 from redfish.ris.sharedtypes import Dictable -import six -from six.moves.queue import Queue -from six.moves.urllib.parse import urlparse -from six.moves.urllib.parse import urlunparse +from urllib.parse import urlparse, urlunparse + # ---------End of imports--------- @@ -39,9 +38,9 @@ class SessionExpiredRis(Exception): pass -@six.add_metaclass(abc.ABCMeta) class RisMonolithMemberBase(Dictable): """RIS monolith member base class""" + __metaclass__ = abc.ABCMeta pass diff --git a/src/redfish/ris/rmc.py b/src/redfish/ris/rmc.py index 2bc40ea..be9ec38 100644 --- a/src/redfish/ris/rmc.py +++ b/src/redfish/ris/rmc.py @@ -1,6 +1,7 @@ # Copyright Notice: -# Copyright 2016-2019 DMTF. All rights reserved. -# License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/python-redfish-library/blob/master/LICENSE.md +# Copyright 2016-2021 DMTF. All rights reserved. +# License: BSD 3-Clause License. For full text see link: +# https://github.com/DMTF/python-redfish-library/blob/master/LICENSE.md # -*- coding: utf-8 -*- """RMC implementation """ @@ -66,7 +67,7 @@ def __init__(self, Args=None): # use the default config file if configfile is None: if os.name == 'nt': - configfile = os.path.join(os.path.dirname(sys.executable), \ + configfile = os.path.join(os.path.dirname(sys.executable), 'redfish.conf') else: configfile = '/etc/redfish/redfish.conf' @@ -249,7 +250,7 @@ def get_current_client(self): current_client = property(get_current_client, None) - def login(self, username=None, password=None, base_url=None, verbose=False,\ + def login(self, username=None, password=None, base_url=None, verbose=False, path=None, skipbuild=False, includelogs=False): """Main worker function for login command @@ -270,8 +271,8 @@ def login(self, username=None, password=None, base_url=None, verbose=False,\ """ if not self.check_current_rmc_client(url=base_url): - raise CurrentlyLoggedInError("Currently logged into another " \ - "server. \nPlease log out out first " \ + raise CurrentlyLoggedInError("Currently logged into another " + "server. \nPlease log out out first " "before logging in to another.") existing_client = self.get_rmc_client(url=base_url) @@ -280,7 +281,7 @@ def login(self, username=None, password=None, base_url=None, verbose=False,\ password=password) else: try: - self.add_rmc_client(RmcClient(username=username, \ + self.add_rmc_client(RmcClient(username=username, password=password, url=base_url)) except Exception as excp: raise excp @@ -291,7 +292,7 @@ def login(self, username=None, password=None, base_url=None, verbose=False,\ raise excp if not skipbuild: - self.build_monolith(verbose=verbose, path=path, \ + self.build_monolith(verbose=verbose, path=path, includelogs=includelogs) self.save() @@ -343,7 +344,7 @@ def logout(self, url=None): for session in sessionlocs: try: - self.delete_handler(session[0], url=session[1], \ + self.delete_handler(session[0], url=session[1], sessionid=session[2], silent=True, service=True) except: pass @@ -393,7 +394,7 @@ def get(self, selector=None): return results - def get_save(self, selector=None, currentoverride=False, pluspath=False, \ + def get_save(self, selector=None, currentoverride=False, pluspath=False, onlypath=None): """Special main function for get in save command @@ -469,11 +470,11 @@ def get_save_helper(self, path, instances): skip = False for item in instances: - if (path + "/settings").lower() == (item.resp.request.path).lower(): + if (path + "/settings").lower() == item.resp.request.path.lower(): skip = True break elif (path + "settings/").lower() == \ - (item.resp.request.path).lower(): + item.resp.request.path.lower(): skip = True break @@ -526,7 +527,7 @@ def set(self, selector=None, val=None): if val: if str(val)[0] == "[" and str(val)[-1] == "]": - json_node = jsonpointer.set_pointer(newdict, \ + json_node = jsonpointer.set_pointer(newdict, json_pstr, '"' + str(val) + '"', inplace=True) else: listfound = True @@ -534,7 +535,7 @@ def set(self, selector=None, val=None): listfound = True if listfound: - json_node = jsonpointer.set_pointer(newdict, \ + json_node = jsonpointer.set_pointer(newdict, json_pstr, val, inplace=True) json_node = jsonpointer.resolve_pointer(newdict, json_pstr) @@ -610,7 +611,7 @@ def validate_headers(self, instance, verbose=False): skip = True break except: - if not ("allow" in instance.resp._headers and "PATCH" in \ + if not ("allow" in instance.resp._headers and "PATCH" in instance.resp._headers["allow"]): if verbose: self.warning_handler('Skipping read-only path: ' \ @@ -692,7 +693,7 @@ def loadset(self, dicttolist=None, selector=None, val=None, newargs=None): for ind, item in enumerate(dicttolist): try: if not isinstance(item[1], list): - dicttolist[ind] = items[itemslower.index(\ + dicttolist[ind] = items[itemslower.index( item[0].lower())], item[1] else: templist.append(item[0]) @@ -739,7 +740,7 @@ def loadset(self, dicttolist=None, selector=None, val=None, newargs=None): if iterval: if str(iterval)[0] == "[" and str(iterval)[-1] == "]": - json_node = jsonpointer.set_pointer(newdict, \ + json_node = jsonpointer.set_pointer(newdict, json_pstr, '"' + str(iterval) + \ '"', inplace=True) else: @@ -748,7 +749,7 @@ def loadset(self, dicttolist=None, selector=None, val=None, newargs=None): listfound = True if listfound: - json_node = jsonpointer.set_pointer(newdict, \ + json_node = jsonpointer.set_pointer(newdict, json_pstr, iterval, inplace=True) json_node = jsonpointer.resolve_pointer(newdict, json_pstr) @@ -1143,8 +1144,8 @@ def merge_dict(self, currdict, newdict): :param currdict: current selection dictionary. :type currdict: dict. - :param currdict: new selection dictionary. - :type currdict: dict. + :param newdict: new selection dictionary. + :type newdict: dict. """ for k, itemv2 in list(newdict.items()): @@ -1156,7 +1157,7 @@ def merge_dict(self, currdict, newdict): else: currdict[k] = itemv2 - def patch_handler(self, put_path, body, verbose=False, url=None, \ + def patch_handler(self, put_path, body, verbose=False, url=None, sessionid=None, headers=None, response=False, silent=False): """Main worker function for raw patch command @@ -1174,14 +1175,16 @@ def patch_handler(self, put_path, body, verbose=False, url=None, \ :type headers: str. :param response: flag to return the response. :type response: str. + :param silent: flag to disable output. + :type silent: boolean. :returns: returns RestResponse object containing response data """ if sessionid: - results = RmcClient(url=url, sessionkey=sessionid).set(put_path, \ + results = RmcClient(url=url, sessionkey=sessionid).set(put_path, body=body, headers=headers) else: - results = self.current_client.set(put_path, body=body, \ + results = self.current_client.set(put_path, body=body, headers=headers) if not silent: @@ -1192,7 +1195,7 @@ def patch_handler(self, put_path, body, verbose=False, url=None, \ if response: return results - def get_handler(self, put_path, silent=False, verbose=False, url=None, \ + def get_handler(self, put_path, silent=False, verbose=False, url=None, sessionid=None, uncache=False, headers=None, response=False): """main worker function for raw get command @@ -1216,10 +1219,10 @@ def get_handler(self, put_path, silent=False, verbose=False, url=None, \ """ if sessionid: - results = RmcClient(url=url, sessionkey=sessionid).get(put_path, \ + results = RmcClient(url=url, sessionkey=sessionid).get(put_path, headers=headers) else: - results = self.current_client.get(put_path, uncache=uncache, \ + results = self.current_client.get(put_path, uncache=uncache, headers=headers) if not silent: @@ -1232,7 +1235,7 @@ def get_handler(self, put_path, silent=False, verbose=False, url=None, \ else: return None - def post_handler(self, put_path, body, verbose=False, url=None, \ + def post_handler(self, put_path, body, verbose=False, url=None, sessionid=None, headers=None, response=False, silent=False): """Main worker function for raw post command @@ -1250,14 +1253,16 @@ def post_handler(self, put_path, body, verbose=False, url=None, \ :type headers: str. :param response: flag to return the response. :type response: str. + :param silent: flag to disable output. + :type silent: boolean. :returns: returns a RestResponse from client's Post command """ if sessionid: - results = RmcClient(url=url, sessionkey=sessionid).toolpost(\ + results = RmcClient(url=url, sessionkey=sessionid).toolpost( put_path, body=body, headers=headers) else: - results = self.current_client.toolpost(put_path, body=body, \ + results = self.current_client.toolpost(put_path, body=body, headers=headers) if not silent: @@ -1268,7 +1273,7 @@ def post_handler(self, put_path, body, verbose=False, url=None, \ if response: return results - def put_handler(self, put_path, body, verbose=False, url=None, \ + def put_handler(self, put_path, body, verbose=False, url=None, sessionid=None, headers=None, response=False, silent=False): """Main worker function for raw put command @@ -1286,14 +1291,16 @@ def put_handler(self, put_path, body, verbose=False, url=None, \ :type headers: str. :param response: flag to return the response. :type response: str. + :param silent: flag to disable output. + :type silent: boolean. :returns: returns a RestResponse object from client's Put command """ if sessionid: - results = RmcClient(url=url, sessionkey=sessionid).toolput(\ + results = RmcClient(url=url, sessionkey=sessionid).toolput( put_path, body=body, headers=headers) else: - results = self.current_client.toolput(put_path, body=body, \ + results = self.current_client.toolput(put_path, body=body, headers=headers) if not silent: @@ -1304,7 +1311,7 @@ def put_handler(self, put_path, body, verbose=False, url=None, \ if response: return results - def delete_handler(self, put_path, verbose=False, url=None, \ + def delete_handler(self, put_path, verbose=False, url=None, sessionid=None, headers=None, silent=True): """Main worker function for raw delete command @@ -1324,7 +1331,7 @@ def delete_handler(self, put_path, verbose=False, url=None, \ """ if sessionid: - results = RmcClient(url=url, sessionkey=sessionid).tooldelete(\ + results = RmcClient(url=url, sessionkey=sessionid).tooldelete( put_path, headers=headers) else: results = self.current_client.tooldelete(put_path, headers=headers) @@ -1336,7 +1343,7 @@ def delete_handler(self, put_path, verbose=False, url=None, \ return results - def head_handler(self, put_path, verbose=False, url=None, sessionid=None, \ + def head_handler(self, put_path, verbose=False, url=None, sessionid=None, silent=False): """Main worker function for raw head command @@ -1348,6 +1355,8 @@ def head_handler(self, put_path, verbose=False, url=None, sessionid=None, \ :type url: str. :param sessionid: session id to be used instead of credentials. :type sessionid: str. + :param silent: flag to disable output. + :type silent: boolean. :returns: returns a RestResponse object from client's Head command """ @@ -1383,7 +1392,7 @@ def _parse_query(self, querystr): qgroups = qmatch.groupdict() - return dict(instance=qgroups['instance'], \ + return dict(instance=qgroups['instance'], xpath=qgroups.get('xpath', None)) def invalid_return_handler(self, results, verbose=False): @@ -1403,7 +1412,7 @@ def invalid_return_handler(self, results, verbose=False): self.warning_handler("[%d] The operation completed " \ "successfully.\n" % results.status) else: - self.warning_handler("The operation completed "\ + self.warning_handler("The operation completed " "successfully.\n") else: self.warning_handler("[%d] No message returned.\n" % \ @@ -1598,7 +1607,7 @@ def get_selection(self, selector=None, sel=None, val=None): content = copy.deepcopy(currdict) if self.filterworkerfunction(workdict=\ - content, sel=sel, val=val, \ + content, sel=sel, val=val, newargs=newargs, loopcount=0): instances.append(instance) continue @@ -1612,7 +1621,7 @@ def get_selection(self, selector=None, sel=None, val=None): return instances - def filterworkerfunction(self, workdict=None, sel=None, val=None, \ + def filterworkerfunction(self, workdict=None, sel=None, val=None, newargs=None, loopcount=0): """Helper function for filter application @@ -1632,7 +1641,7 @@ def filterworkerfunction(self, workdict=None, sel=None, val=None, \ if workdict and sel and val and newargs: if isinstance(workdict, list): for item in workdict: - if self.filterworkerfunction(workdict=item, sel=sel, \ + if self.filterworkerfunction(workdict=item, sel=sel, val=val, newargs=newargs, loopcount=loopcount): return True @@ -1648,14 +1657,14 @@ def filterworkerfunction(self, workdict=None, sel=None, val=None, \ return False - if not (isinstance(workdict[newargs[loopcount]], list) or \ + if not (isinstance(workdict[newargs[loopcount]], list) or isinstance(workdict[newargs[loopcount]], dict)): return False workdict = workdict[newargs[loopcount]] loopcount += 1 - if self.filterworkerfunction(workdict=workdict, sel=sel, \ + if self.filterworkerfunction(workdict=workdict, sel=sel, val=val, newargs=newargs, loopcount=loopcount): return True @@ -1722,7 +1731,7 @@ def get_filter_settings(self): if self.current_client: if not self.current_client.filter_attr is None and not \ self.current_client.filter_value is None: - return (self.current_client.filter_attr, \ + return (self.current_client.filter_attr, self.current_client.filter_value) return (None, None) diff --git a/src/redfish/ris/rmc_helper.py b/src/redfish/ris/rmc_helper.py index da402ab..10f941e 100644 --- a/src/redfish/ris/rmc_helper.py +++ b/src/redfish/ris/rmc_helper.py @@ -1,6 +1,7 @@ # Copyright Notice: -# Copyright 2016-2020 DMTF. All rights reserved. -# License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/python-redfish-library/blob/master/LICENSE.md +# Copyright 2016-2021 DMTF. All rights reserved. +# License: BSD 3-Clause License. For full text see link: +# https://github.com/DMTF/python-redfish-library/blob/master/LICENSE.md # -*- coding: utf-8 -*- """RMC helper implementation""" @@ -14,7 +15,7 @@ import hashlib import redfish.rest -from six.moves.urllib.parse import urlparse +from urllib.parse import urlparse from .ris import (RisMonolith) from .sharedtypes import (JSONEncoder) @@ -93,7 +94,7 @@ def __init__(self, url=None, username=None, password=None, sessionkey=None): :type sessionkey: str """ - self._rest_client = redfish.rest.v1.redfish_client(base_url=url, \ + self._rest_client = redfish.rest.v1.redfish_client(base_url=url, username=username, password=password, sessionkey=sessionkey) self._get_cache = dict() @@ -217,6 +218,8 @@ def get(self, path, args=None, uncache=False, headers=None): :rtype: redfish.rest.v1.RestResponse. :param uncache: flag to not store the data downloaded into cache. :type uncache: boolean. + :param headers: dict of headers to be appended. + :type headers: dict. """ resp = self._rest_client.get(path=path, args=args, headers=headers) @@ -233,6 +236,8 @@ def head(self, path, args=None, headers=None): :type path: str. :param args: GET arguments. :type args: str. + :param headers: dict of headers to be appended. + :type headers: dict. :returns: a RestResponse object containing the response data. :rtype: redfish.rest.v1.RestResponse. @@ -258,7 +263,7 @@ def set(self, path, args=None, body=None, headers=None): resp = self._rest_client.get(path=path, args=args) self._get_cache[path] = resp - return self._rest_client.patch(path=path, args=args, body=body, \ + return self._rest_client.patch(path=path, args=args, body=body, headers=headers) def toolpost(self, path, args=None, body=None, headers=None): @@ -279,7 +284,7 @@ def toolpost(self, path, args=None, body=None, headers=None): resp = self._rest_client.get(path=path, args=args) self._get_cache[path] = resp - return self._rest_client.post(path=path, args=args, body=body, \ + return self._rest_client.post(path=path, args=args, body=body, headers=headers) def toolput(self, path, args=None, body=None, headers=None): @@ -300,7 +305,7 @@ def toolput(self, path, args=None, body=None, headers=None): resp = self._rest_client.get(path=path, args=args) self._get_cache[path] = resp - return self._rest_client.put(path=path, args=args, body=body, \ + return self._rest_client.put(path=path, args=args, body=body, headers=headers) def tooldelete(self, path, args=None, headers=None): @@ -310,8 +315,6 @@ def tooldelete(self, path, args=None, headers=None): :type path: str. :param args: DELETE arguments. :type args: str. - :param body: contents of the DELETE request. - :type body: str. :param headers: list of headers to be appended. :type headers: list. :returns: a RestResponse object containing the response data. @@ -541,7 +544,7 @@ def logout_del_function(self, url=None): loc = item['login']['session_location'].\ split(item['login']['url'])[-1] sesurl = item['login']['url'] - sessionlocs.append((loc, sesurl, \ + sessionlocs.append((loc, sesurl, item['login']['session_key'])) os.remove(os.path.join(cachedir, index['href'])) @@ -591,17 +594,17 @@ def _uncache_client(self, cachefn): if 'url' not in login_data: continue - rmc_client = RmcClient(\ - username=login_data.get('username', 'Administrator'), \ - password=login_data.get('password', None), \ - url=login_data.get('url', None), \ + rmc_client = RmcClient( + username=login_data.get('username', 'Administrator'), + password=login_data.get('password', None), + url=login_data.get('url', None), sessionkey=login_data.get('session_key', None)) - rmc_client._rest_client.set_authorization_key(\ + rmc_client._rest_client.set_authorization_key( login_data.get('authorization_key')) - rmc_client._rest_client.set_session_key(\ + rmc_client._rest_client.set_session_key( login_data.get('session_key')) - rmc_client._rest_client.set_session_location(\ + rmc_client._rest_client.set_session_location( login_data.get('session_location')) if 'selector' in client: @@ -617,12 +620,12 @@ def _uncache_client(self, cachefn): rmc_client._get_cache = dict() for key in list(getdata.keys()): - restreq = redfish.rest.v1.RestRequest(\ + restreq = redfish.rest.v1.RestRequest( method='GET', path=key) getdata[key]['restreq'] = restreq - rmc_client._get_cache[key] = (\ - redfish.rest.v1.StaticRestResponse(\ + rmc_client._get_cache[key] = ( + redfish.rest.v1.StaticRestResponse( **getdata[key])) rmc_client._monolith = RisMonolith(rmc_client) @@ -666,22 +669,21 @@ def cache_rmc(self): if self._rmc._rmc_clients: for client in self._rmc._rmc_clients: - login_data = dict(\ - username=client.get_username(), \ - password=client.get_password(), url=client.get_base_url(), \ - session_key=client.get_session_key(), \ - session_location=client.get_session_location(), \ + login_data = dict( + username=client.get_username(), + password=client.get_password(), url=client.get_base_url(), + session_key=client.get_session_key(), + session_location=client.get_session_location(), authorization_key=client.get_authorization_key()) - clients_cache.append(\ - dict(selector=client.selector, login=login_data, \ - filter_attr=client._filter_attr, \ - filter_value=client._filter_value, \ + clients_cache.append( + dict(selector=client.selector, login=login_data, + filter_attr=client._filter_attr, + filter_value=client._filter_value, monolith=client.monolith, get=client._get_cache)) - clientsfh = open('%s/%s' % (cachedir, \ + clientsfh = open('%s/%s' % (cachedir, index_map[client.get_base_url()]), 'w') json.dump(clients_cache, clientsfh, indent=2, cls=JSONEncoder) clientsfh.close() - diff --git a/src/redfish/ris/sharedtypes.py b/src/redfish/ris/sharedtypes.py index d8e80b9..1131bc7 100644 --- a/src/redfish/ris/sharedtypes.py +++ b/src/redfish/ris/sharedtypes.py @@ -1,6 +1,7 @@ # Copyright Notice: -# Copyright 2016-2019 DMTF. All rights reserved. -# License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/python-redfish-library/blob/master/LICENSE.md +# Copyright 2016-2021 DMTF. All rights reserved. +# License: BSD 3-Clause License. For full text see link: +# https://github.com/DMTF/python-redfish-library/blob/master/LICENSE.md # -*- coding: utf-8 -*- """ Shared types used in this module """ @@ -38,6 +39,6 @@ class Dictable(object): """A base class which adds the to_dict method used during json encoding""" def to_dict(self): """Overridable funciton""" - raise RuntimeError("You must override this method in your derived" \ + raise RuntimeError("You must override this method in your derived" " class") diff --git a/tests/__init__.py b/tests/__init__.py index e69de29..3eb8a24 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -0,0 +1,4 @@ +# Copyright Notice: +# Copyright 2016-2021 DMTF. All rights reserved. +# License: BSD 3-Clause License. For full text see link: +# https://github.com/DMTF/python-redfish-library/blob/master/LICENSE.md \ No newline at end of file diff --git a/tests/discovery/__init__.py b/tests/discovery/__init__.py index e69de29..3eb8a24 100644 --- a/tests/discovery/__init__.py +++ b/tests/discovery/__init__.py @@ -0,0 +1,4 @@ +# Copyright Notice: +# Copyright 2016-2021 DMTF. All rights reserved. +# License: BSD 3-Clause License. For full text see link: +# https://github.com/DMTF/python-redfish-library/blob/master/LICENSE.md \ No newline at end of file diff --git a/tests/discovery/test_discovery.py b/tests/discovery/test_discovery.py index f2dbda9..60b2b8b 100644 --- a/tests/discovery/test_discovery.py +++ b/tests/discovery/test_discovery.py @@ -1,10 +1,15 @@ +# Copyright Notice: +# Copyright 2016-2021 DMTF. All rights reserved. +# License: BSD 3-Clause License. For full text see link: +# https://github.com/DMTF/python-redfish-library/blob/master/LICENSE.md + # -*- encoding: utf-8 -*- import unittest from redfish.discovery.discovery import FakeSocket from redfish.discovery.discovery import sanitize -from six import BytesIO +from io import BytesIO class TestFakeSocket(unittest.TestCase): diff --git a/tests/rest/__init__.py b/tests/rest/__init__.py index e69de29..3eb8a24 100644 --- a/tests/rest/__init__.py +++ b/tests/rest/__init__.py @@ -0,0 +1,4 @@ +# Copyright Notice: +# Copyright 2016-2021 DMTF. All rights reserved. +# License: BSD 3-Clause License. For full text see link: +# https://github.com/DMTF/python-redfish-library/blob/master/LICENSE.md \ No newline at end of file diff --git a/tests/rest/test_v1.py b/tests/rest/test_v1.py index 2759408..06346ae 100644 --- a/tests/rest/test_v1.py +++ b/tests/rest/test_v1.py @@ -1,3 +1,8 @@ +# Copyright Notice: +# Copyright 2016-2021 DMTF. All rights reserved. +# License: BSD 3-Clause License. For full text see link: +# https://github.com/DMTF/python-redfish-library/blob/master/LICENSE.md + # -*- encoding: utf-8 -*- import unittest diff --git a/tests/ris/__init__.py b/tests/ris/__init__.py index e69de29..3eb8a24 100644 --- a/tests/ris/__init__.py +++ b/tests/ris/__init__.py @@ -0,0 +1,4 @@ +# Copyright Notice: +# Copyright 2016-2021 DMTF. All rights reserved. +# License: BSD 3-Clause License. For full text see link: +# https://github.com/DMTF/python-redfish-library/blob/master/LICENSE.md \ No newline at end of file diff --git a/tests/ris/test_config.py b/tests/ris/test_config.py index e5febdb..3c714df 100644 --- a/tests/ris/test_config.py +++ b/tests/ris/test_config.py @@ -1,15 +1,15 @@ +# Copyright Notice: +# Copyright 2016-2021 DMTF. All rights reserved. +# License: BSD 3-Clause License. For full text see link: +# https://github.com/DMTF/python-redfish-library/blob/master/LICENSE.md + # -*- encoding: utf-8 -*- -import os -import shutil -import sys import tempfile import textwrap import unittest from redfish.ris.config import AutoConfigParser -py2k = sys.version_info < (3, 0) - CONFIG = textwrap.dedent( """ @@ -33,42 +33,23 @@ class TestAutoConfigParser(unittest.TestCase): def test_init(self): acp = AutoConfigParser() self.assertEqual(acp._configfile, None) - if py2k: - tmpdirname = tempfile.mkdtemp() + with tempfile.TemporaryDirectory() as tmpdirname: cfgfile = "{tmpdir}/config.ini".format(tmpdir=tmpdirname) with open(cfgfile, "w+") as config: config.write(CONFIG) acp = AutoConfigParser(cfgfile) self.assertEqual(acp._configfile, cfgfile) - shutil.rmtree(tmpdirname) - else: - with tempfile.TemporaryDirectory() as tmpdirname: - cfgfile = "{tmpdir}/config.ini".format(tmpdir=tmpdirname) - with open(cfgfile, "w+") as config: - config.write(CONFIG) - acp = AutoConfigParser(cfgfile) - self.assertEqual(acp._configfile, cfgfile) def test_load(self): - if py2k: - tmpdirname = tempfile.mkdtemp() + with tempfile.TemporaryDirectory() as tmpdirname: cfgfile = "{tmpdir}/config.ini".format(tmpdir=tmpdirname) with open(cfgfile, "w+") as config: config.write(CONFIG) acp = AutoConfigParser() acp.load(cfgfile) - shutil.rmtree(tmpdirname) - else: - with tempfile.TemporaryDirectory() as tmpdirname: - cfgfile = "{tmpdir}/config.ini".format(tmpdir=tmpdirname) - with open(cfgfile, "w+") as config: - config.write(CONFIG) - acp = AutoConfigParser() - acp.load(cfgfile) def test_save(self): - if py2k: - tmpdirname = tempfile.mkdtemp() + with tempfile.TemporaryDirectory() as tmpdirname: cfgfile = "{tmpdir}/config.ini".format(tmpdir=tmpdirname) with open(cfgfile, "w+") as config: config.write(CONFIG) @@ -77,14 +58,3 @@ def test_save(self): acp.save() dump = "{tmpdir}/config2.ini".format(tmpdir=tmpdirname) acp.save(dump) - shutil.rmtree(tmpdirname) - else: - with tempfile.TemporaryDirectory() as tmpdirname: - cfgfile = "{tmpdir}/config.ini".format(tmpdir=tmpdirname) - with open(cfgfile, "w+") as config: - config.write(CONFIG) - acp = AutoConfigParser(cfgfile) - acp.load() - acp.save() - dump = "{tmpdir}/config2.ini".format(tmpdir=tmpdirname) - acp.save(dump) diff --git a/tests/ris/test_ris.py b/tests/ris/test_ris.py index adb8bb2..ce2813e 100644 --- a/tests/ris/test_ris.py +++ b/tests/ris/test_ris.py @@ -1,3 +1,8 @@ +# Copyright Notice: +# Copyright 2016-2021 DMTF. All rights reserved. +# License: BSD 3-Clause License. For full text see link: +# https://github.com/DMTF/python-redfish-library/blob/master/LICENSE.md + # -*- encoding: utf-8 -*- import unittest diff --git a/tests/ris/test_rmc_helper.py b/tests/ris/test_rmc_helper.py index dbf4a29..410e1e8 100644 --- a/tests/ris/test_rmc_helper.py +++ b/tests/ris/test_rmc_helper.py @@ -1,7 +1,7 @@ # Copyright Notice: -# Copyright 2020 DMTF. All rights reserved. +# Copyright 2016-2021 DMTF. All rights reserved. # License: BSD 3-Clause License. For full text see link: -# https://github.com/DMTF/Redfish-Protocol-Validator/blob/master/LICENSE.md +# https://github.com/DMTF/python-redfish-library/blob/master/LICENSE.md import unittest try: diff --git a/tox.ini b/tox.ini index 6cf4433..ae6587f 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = py27,py34,py35,py36,py37,py38 +envlist = py34,py35,py36,py37,py38 [testenv] usedevelop = True @@ -14,14 +14,6 @@ commands = --with-timer \ --with-coverage --cover-erase --cover-package=src -[testenv:py27] -deps = - coverage - fixtures - mock - nose - nose-timer - [testenv:py34] deps = coverage From d467dcf0b92e9e329c547f64cd20d8669e1b5d6a Mon Sep 17 00:00:00 2001 From: Mike Raineri Date: Fri, 12 Feb 2021 14:15:00 -0500 Subject: [PATCH 2/3] Removed Python2.7 from Travis checks --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index f8fef32..2c218d7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,7 +3,6 @@ language: python cache: - pip python: -- '2.7' - '3.4' - '3.5' - '3.6' From 02466ce76e39e61ab393f07a9e8662240a34403d Mon Sep 17 00:00:00 2001 From: Mike Raineri Date: Mon, 15 Feb 2021 09:07:26 -0500 Subject: [PATCH 3/3] Removal of Python version checks --- src/redfish/rest/v1.py | 26 +++++++------------------- 1 file changed, 7 insertions(+), 19 deletions(-) diff --git a/src/redfish/rest/v1.py b/src/redfish/rest/v1.py index 9a3ed32..77d0491 100644 --- a/src/redfish/rest/v1.py +++ b/src/redfish/rest/v1.py @@ -16,7 +16,6 @@ import json import base64 import logging -import inspect import http.client from collections import (OrderedDict) @@ -27,13 +26,6 @@ #---------End of imports--------- -#---------Python 3 support--------- - -if sys.version_info > (3,): - buffer = memoryview - -#---------End of Python 3 support--------- - #---------Debug logger--------- LOGGER = logging.getLogger(__name__) @@ -497,17 +489,13 @@ def __init_connection(self, url=None): url = url if url else self.__url if url.scheme.upper() == "HTTPS": - if sys.version_info < (2, 7, 9) and "context" not in inspect.getargspec(http.client.HTTPSConnection.__init__).args: - self._conn = self._get_connection(url, timeout=self._timeout) + if self.cafile or self.capath is not None: + ssl_context = ssl.create_default_context(capath=self.capath, + cafile=self.cafile) else: - if self.cafile or self.capath is not None: - ssl_context = ssl.create_default_context( - capath=self.capath, cafile=self.cafile) - else: - ssl_context = ssl._create_unverified_context() - self._conn = self._get_connection(url, - context=ssl_context, - timeout=self._timeout) + ssl_context = ssl._create_unverified_context() + self._conn = self._get_connection(url, context=ssl_context, + timeout=self._timeout) elif url.scheme.upper() == "HTTP": self._conn = self._get_connection(url, timeout=self._timeout) else: @@ -802,7 +790,7 @@ def _rest_request(self, path, method='GET', args=None, body=None, compresseddata = buf.getvalue() if compresseddata: data = bytearray() - data.extend(buffer(compresseddata)) + data.extend(memoryview(compresseddata)) body = data except BaseException as excp: LOGGER.error('Error occur while compressing body: %s', excp)