Fix up code-base to pass hacking

This commit is contained in:
Ian Cordasco
2016-06-23 15:15:24 -05:00
parent d30f605ec7
commit f0ae354ebc
15 changed files with 188 additions and 39 deletions

View File

@@ -11,6 +11,7 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
"""Craton API Client Library and Command-Line Application."""
import pbr.version import pbr.version

View File

@@ -11,8 +11,11 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
"""Client for CRUD operations.""" """Client for CRUD operations."""
import copy
from oslo_utils import strutils
class CRUDClient(object): class CRUDClient(object):
"""Class that handles the basic create, read, upload, delete workflow.""" """Class that handles the basic create, read, upload, delete workflow."""
@@ -22,6 +25,7 @@ class CRUDClient(object):
resource_class = None resource_class = None
def __init__(self, session, url): def __init__(self, session, url):
"""Initialize our Client with a session and base url."""
self.session = session self.session = session
self.url = url.rstrip('/') self.url = url.rstrip('/')
@@ -179,13 +183,17 @@ class Resource(object):
return self._info == other._info return self._info == other._info
def is_loaded(self): def is_loaded(self):
"""Check if the resource has been loaded."""
return self._loaded return self._loaded
def set_loaded(self, val): def set_loaded(self, val):
"""Set whether the resource has been loaded or not."""
self._loaded = val self._loaded = val
def to_dict(self): def to_dict(self):
"""Return the resource as a dictionary."""
return copy.deepcopy(self._info) return copy.deepcopy(self._info)
def delete(self): def delete(self):
"""Delete the resource from the service."""
return self.manager.delete(self) return self.manager.delete(self)

View File

@@ -13,6 +13,7 @@
# under the License. # under the License.
"""Exception classes and logic for cratonclient.""" """Exception classes and logic for cratonclient."""
class ClientException(Exception): class ClientException(Exception):
"""Base exception class for all exceptions in cratonclient.""" """Base exception class for all exceptions in cratonclient."""
@@ -34,6 +35,11 @@ class Timeout(ClientException):
message = 'Request timed out' message = 'Request timed out'
def __init__(self, message=None, **kwargs): def __init__(self, message=None, **kwargs):
"""Initialize our Timeout exception.
This takes an optional keyword-only argument of
``original_exception``.
"""
self.original_exception = kwargs.pop('exception', None) self.original_exception = kwargs.pop('exception', None)
super(Timeout, self).__init__(message) super(Timeout, self).__init__(message)
@@ -45,6 +51,14 @@ class HTTPError(ClientException):
status_code = None status_code = None
def __init__(self, message=None, **kwargs): def __init__(self, message=None, **kwargs):
"""Initialize our HTTPError instance.
Optional keyword-only arguments include:
- response: for the response generating the error
- original_exception: in the event that this is a requests exception
that we are re-raising.
"""
self.response = kwargs.pop('response', None) self.response = kwargs.pop('response', None)
self.original_exception = kwargs.pop('exception', None) self.original_exception = kwargs.pop('exception', None)
self.status_code = (self.status_code self.status_code = (self.status_code

View File

@@ -14,8 +14,11 @@
"""Craton-specific session details.""" """Craton-specific session details."""
import logging import logging
from oslo_utils import encodeutils
from oslo_utils import strutils
import requests import requests
from requests import exceptions as requests_exc from requests import exceptions as requests_exc
import six
import cratonclient import cratonclient
from cratonclient import exceptions as exc from cratonclient import exceptions as exc
@@ -31,7 +34,21 @@ class Session(object):
immediately. immediately.
""" """
def __init__(self, session=None, username=None, token=None, project_id=None): def __init__(self, session=None, username=None, token=None,
project_id=None):
"""Initialize our Session.
:param session:
The session instance (either keystoneauth1's session or requests
Session) to use as an underlying HTTP transport. If not provided,
we will create a requests Session object.
:param str username:
The username of the person authenticating against the API.
:param str token:
The authentication token of the user authenticating.
:param str project_id:
The user's project id in Craton.
"""
if session is None: if session is None:
session = requests.Session() session = requests.Session()
@@ -48,24 +65,131 @@ class Session(object):
self._session.headers['Accept'] = 'application/json' self._session.headers['Accept'] = 'application/json'
def delete(self, url, **kwargs): def delete(self, url, **kwargs):
"""Make a DELETE request with url and optional parameters.
See the :meth:`Session.request` documentation for more details.
.. code-block:: python
>>> from cratonclient import session as craton
>>> session = craton.Session(
... username='demo',
... token='p@$$w0rd',
... project_id='1',
... )
>>> response = session.delete('http://example.com')
"""
return self.request('DELETE', url, **kwargs) return self.request('DELETE', url, **kwargs)
def get(self, url, **kwargs): def get(self, url, **kwargs):
"""Make a GET request with url and optional parameters.
See the :meth:`Session.request` documentation for more details.
.. code-block:: python
>>> from cratonclient import session as craton
>>> session = craton.Session(
... username='demo',
... token='p@$$w0rd',
... project_id='1',
... )
>>> response = session.get('http://example.com')
"""
return self.request('GET', url, **kwargs) return self.request('GET', url, **kwargs)
def head(self, url, **kwargs): def head(self, url, **kwargs):
"""Make a HEAD request with url and optional parameters.
See the :meth:`Session.request` documentation for more details.
.. code-block:: python
>>> from cratonclient import session as craton
>>> session = craton.Session(
... username='demo',
... token='p@$$w0rd',
... project_id='1',
... )
>>> response = session.head('http://example.com')
"""
return self.request('HEAD', url, **kwargs) return self.request('HEAD', url, **kwargs)
def options(self, url, **kwargs): def options(self, url, **kwargs):
"""Make an OPTIONS request with url and optional parameters.
See the :meth:`Session.request` documentation for more details.
.. code-block:: python
>>> from cratonclient import session as craton
>>> session = craton.Session(
... username='demo',
... token='p@$$w0rd',
... project_id='1',
... )
>>> response = session.options('http://example.com')
"""
return self.request('OPTIONS', url, **kwargs) return self.request('OPTIONS', url, **kwargs)
def post(self, url, **kwargs): def post(self, url, **kwargs):
"""Make a POST request with url and optional parameters.
See the :meth:`Session.request` documentation for more details.
.. code-block:: python
>>> from cratonclient import session as craton
>>> session = craton.Session(
... username='demo',
... token='p@$$w0rd',
... project_id='1',
... )
>>> response = session.post(
... 'http://example.com',
... data=b'foo',
... headers={'Content-Type': 'text/plain'},
... )
"""
return self.request('POST', url, **kwargs) return self.request('POST', url, **kwargs)
def put(self, url, **kwargs): def put(self, url, **kwargs):
"""Make a PUT request with url and optional parameters.
See the :meth:`Session.request` documentation for more details.
.. code-block:: python
>>> from cratonclient import session as craton
>>> session = craton.Session(
... username='demo',
... token='p@$$w0rd',
... project_id='1',
... )
>>> response = session.put(
... 'http://example.com',
... data=b'foo',
... headers={'Content-Type': 'text/plain'},
... )
"""
return self.request('PUT', url, **kwargs) return self.request('PUT', url, **kwargs)
def request(self, method, url, **kwargs): def request(self, method, url, **kwargs):
"""Make a request with a method, url, and optional parameters.
See also: python-requests.org for documentation of acceptable
parameters.
.. code-block:: python
>>> from cratonclient import session as craton
>>> session = craton.Session(
... username='demo',
... token='p@$$w0rd',
... project_id='1',
... )
>>> response = session.request('GET', 'http://example.com')
"""
self._http_log_request(method=method, self._http_log_request(method=method,
url=url, url=url,
data=kwargs.get('data'), data=kwargs.get('data'),
@@ -91,7 +215,6 @@ class Session(object):
return response return response
def _http_log_request(self, url, method=None, data=None, def _http_log_request(self, url, method=None, data=None,
headers=None, logger=LOG): headers=None, logger=LOG):
if not logger.isEnabledFor(logging.DEBUG): if not logger.isEnabledFor(logging.DEBUG):
@@ -135,16 +258,14 @@ class Session(object):
if not logger.isEnabledFor(logging.DEBUG): if not logger.isEnabledFor(logging.DEBUG):
return return
text = _remove_service_catalog(response.text)
string_parts = [ string_parts = [
'RESP:', 'RESP:',
'[%s]' % response.status_code '[%s]' % response.status_code
] ]
for header in six.iteritems(response.headers): for header in six.iteritems(response.headers):
string_parts.append('%s: %s' % self._process_header(header)) string_parts.append('%s: %s' % self._process_header(header))
if text: if response.text:
string_parts.append('\nRESP BODY: %s\n' % string_parts.append('\nRESP BODY: %s\n' %
strutils.mask_password(text)) strutils.mask_password(response.text))
logger.debug(' '.join(string_parts)) logger.debug(' '.join(string_parts))

View File

@@ -9,3 +9,4 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
"""Command-line application that interfaces with Craton API."""

View File

@@ -9,13 +9,11 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
"""Main shell for parsing arguments directed toward Craton."""
"""
Main shell for parsing arguments directed toward Craton.
"""
def main(): def main():
"""Main entry-point for cratonclient's CLI."""
return 0 return 0
if __name__ == "__main__": if __name__ == "__main__":

View File

@@ -10,8 +10,6 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
""" """Command-line interface to the OpenStack Craton API V1."""
Command-line interface to the OpenStack Craton API V1.
"""
# TODO(cmspence): from cratonclient.v1 import client # TODO(cmspence): from cratonclient.v1 import client

View File

@@ -0,0 +1,12 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
"""Test suite for Craton client and shell."""

View File

@@ -14,10 +14,10 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
"""Base TestCase for all cratonclient tests."""
from oslotest import base from oslotest import base
class TestCase(base.BaseTestCase): class TestCase(base.BaseTestCase):
"""Test case base class for all unit tests.""" """Test case base class for all unit tests."""

View File

@@ -11,18 +11,14 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
"""Tests for `cratonclient` module."""
"""
test_cratonclient
----------------------------------
Tests for `cratonclient` module.
"""
from cratonclient.tests import base from cratonclient.tests import base
class TestCratonclient(base.TestCase): class TestCratonclient(base.TestCase):
"""Tests for the top-level module."""
def test_something(self): def test_something(self):
"""Do nothing."""
pass pass

View File

@@ -21,11 +21,11 @@ import cratonclient
from cratonclient import session from cratonclient import session
from cratonclient.tests import base from cratonclient.tests import base
USERNAME = 'example' USERNAME = 'example'
TOKEN = uuid.uuid4().hex TOKEN = uuid.uuid4().hex
PROJECT_ID = 1 PROJECT_ID = 1
class TestSession(base.TestCase): class TestSession(base.TestCase):
"""Test our session class.""" """Test our session class."""
@@ -60,4 +60,3 @@ class TestSession(base.TestCase):
'Accept': 'application/json', 'Accept': 'application/json',
} }
self.assertItemsEqual(expected_headers, craton._session.headers) self.assertItemsEqual(expected_headers, craton._session.headers)

View File

@@ -9,3 +9,4 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
"""Unit tests for cratonclient."""

View File

@@ -12,8 +12,8 @@
"""Tests for `cratonclient.shell.main` module.""" """Tests for `cratonclient.shell.main` module."""
from cratonclient.tests import base
from cratonclient.shell import main from cratonclient.shell import main
from cratonclient.tests import base
class TestMainShell(base.TestCase): class TestMainShell(base.TestCase):
@@ -21,5 +21,4 @@ class TestMainShell(base.TestCase):
def test_main_returns_successfully(self): def test_main_returns_successfully(self):
"""Verify that cratonclient shell main returns as expected.""" """Verify that cratonclient shell main returns as expected."""
self.assertEqual(main.main(), 0) self.assertEqual(main.main(), 0)

View File

@@ -11,3 +11,4 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
"""Client library for version 1 of Craton's API."""

View File

@@ -57,4 +57,4 @@ commands = oslo_debug_helper {posargs}
show-source = True show-source = True
ignore = E123,E125 ignore = E123,E125
builtins = _ builtins = _
exclude=.venv,.git,.tox,dist,doc,*lib/python*,*egg,build exclude=.venv,.git,.tox,dist,doc,*lib/python*,*egg,build,setup.py