From 353cd4ead47b253b9895719afd4f378b28ee0609 Mon Sep 17 00:00:00 2001 From: Robert Wikman Date: Thu, 15 Feb 2018 22:52:35 +0100 Subject: [PATCH 01/10] base_url, base_path, api_path are now public --- pysnow/url_builder.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pysnow/url_builder.py b/pysnow/url_builder.py index f6eada0..3e901ac 100644 --- a/pysnow/url_builder.py +++ b/pysnow/url_builder.py @@ -6,9 +6,9 @@ class URLBuilder(object): def __init__(self, base_url, base_path, api_path): - self._base_url = base_url - self._base_path = base_path - self._api_path = api_path + self.base_url = base_url + self.base_path = base_path + self.api_path = api_path self._resource_url = "%(base_url)s%(base_path)s%(api_path)s" % ( { From 6dc2254927720e086bb6a733816da6fe7f2d6894 Mon Sep 17 00:00:00 2001 From: Robert Wikman Date: Thu, 15 Feb 2018 23:26:57 +0100 Subject: [PATCH 02/10] Properly pass chunk_size in OAuthClient --- pysnow/oauth_client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pysnow/oauth_client.py b/pysnow/oauth_client.py index 669b1df..e659159 100644 --- a/pysnow/oauth_client.py +++ b/pysnow/oauth_client.py @@ -113,7 +113,7 @@ def resource(self, api_path=None, base_path='/api/now', chunk_size=None): if isinstance(self.token, dict): self.session = self._get_oauth_session() - return super(OAuthClient, self).resource(api_path, base_path) + return super(OAuthClient, self).resource(api_path, base_path, chunk_size) raise MissingToken("You must set_token() before creating a resource with OAuthClient") From 25089cd406d6d9ef3f02076fa82a252655c9792e Mon Sep 17 00:00:00 2001 From: Robert Wikman Date: Thu, 15 Feb 2018 23:27:38 +0100 Subject: [PATCH 03/10] Set default chunk size in Client instead of Request --- pysnow/client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pysnow/client.py b/pysnow/client.py index 8b238ea..29ca581 100644 --- a/pysnow/client.py +++ b/pysnow/client.py @@ -146,7 +146,7 @@ def resource(self, api_path=None, base_path='/api/now', chunk_size=None): return Resource(api_path=api_path, base_path=base_path, parameters=self.parameters, - chunk_size=chunk_size, + chunk_size=chunk_size or 8192, session=self.session, base_url=self.base_url) From 0de86d05b40f1815faa1d0f553ffb83361173252 Mon Sep 17 00:00:00 2001 From: Robert Wikman Date: Fri, 16 Feb 2018 00:18:29 +0100 Subject: [PATCH 04/10] Expose full_path in URLBuilder API --- pysnow/url_builder.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pysnow/url_builder.py b/pysnow/url_builder.py index 3e901ac..48e51c0 100644 --- a/pysnow/url_builder.py +++ b/pysnow/url_builder.py @@ -9,12 +9,12 @@ def __init__(self, base_url, base_path, api_path): self.base_url = base_url self.base_path = base_path self.api_path = api_path + self.full_path = base_path + api_path - self._resource_url = "%(base_url)s%(base_path)s%(api_path)s" % ( + self._resource_url = "%(base_url)s%(full_path)s" % ( { 'base_url': base_url, - 'base_path': base_path, - 'api_path': api_path + 'full_path': self.full_path } ) From cb884dd3fe8e121b5e8bb933146e3d9e17c476bd Mon Sep 17 00:00:00 2001 From: Robert Wikman Date: Fri, 16 Feb 2018 00:19:49 +0100 Subject: [PATCH 05/10] Added resource logger --- pysnow/resource.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/pysnow/resource.py b/pysnow/resource.py index af3fb55..5593bf5 100644 --- a/pysnow/resource.py +++ b/pysnow/resource.py @@ -1,10 +1,14 @@ # -*- coding: utf-8 -*- +import logging + from copy import deepcopy from .request import SnowRequest from .url_builder import URLBuilder +logger = logging.getLogger('pysnow') + class Resource(object): """Creates a new :class:`Resource` object @@ -31,8 +35,10 @@ def __init__(self, base_url=None, base_path=None, api_path=None, parameters=None self.parameters = deepcopy(parameters) + logger.debug('(RESOURCE_ADD) Object: %s, chunk_size: %d' % (self, kwargs.get('chunk_size'))) + def __repr__(self): - return '<%s [%s]>' % (self.__class__.__name__, self.path) + return '<%s [%s] at %s>' % (self.__class__.__name__, self.path, hex(id(self))) @property def path(self): @@ -42,7 +48,7 @@ def path(self): def _request(self): parameters = deepcopy(self.parameters) - return SnowRequest(url_builder=self._url_builder, parameters=parameters, **self.kwargs) + return SnowRequest(url_builder=self._url_builder, parameters=parameters, parent=self, **self.kwargs) def get(self, query, limit=None, offset=None, fields=list()): """Queries the API resource From 6fa1f66331c7425246c90d6bcb31f1d74b1cf946 Mon Sep 17 00:00:00 2001 From: Robert Wikman Date: Fri, 16 Feb 2018 00:20:17 +0100 Subject: [PATCH 06/10] Request logger --- pysnow/request.py | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/pysnow/request.py b/pysnow/request.py index a38ca72..6cce274 100644 --- a/pysnow/request.py +++ b/pysnow/request.py @@ -1,10 +1,13 @@ # -*- coding: utf-8 -*- +import logging import json from .response import Response from .exceptions import InvalidUsage +logger = logging.getLogger('pysnow') + class SnowRequest(object): """Creates a new :class:`SnowRequest` object. @@ -14,11 +17,12 @@ class SnowRequest(object): :param url_builder: :class:`url_builder.URLBuilder` object """ - def __init__(self, parameters=None, session=None, url_builder=None, chunk_size=None): + def __init__(self, parameters=None, session=None, url_builder=None, chunk_size=None, parent=None): self._parameters = parameters self._url_builder = url_builder self._session = session - self._chunk_size = chunk_size or 8192 + self._chunk_size = chunk_size + self._parent = parent self._url = url_builder.get_url() @@ -32,9 +36,15 @@ def _get_response(self, method, **kwargs): - :class:`pysnow.Response` object """ - response = self._session.request(method, self._url, stream=True, params=self._parameters.as_dict(), **kwargs) + params = self._parameters.as_dict() + + logger.debug('(REQUEST_SEND) Method: %s, Resource: %s' % (method, self._parent)) + + response = self._session.request(method, self._url, stream=True, params=params, **kwargs) response.raw.decode_content = True + logger.debug('(RESPONSE_RECEIVE) Code: %d, Resource: %s' % (response.status_code, self._parent)) + return Response(response, self._chunk_size) def get(self, query, limit=None, offset=None, fields=list()): From b5c336c1a5149995a5a09e0dcce44571b691d3a3 Mon Sep 17 00:00:00 2001 From: Robert Wikman Date: Fri, 16 Feb 2018 00:21:27 +0100 Subject: [PATCH 07/10] Added logging, use local session when getting new tokens --- pysnow/oauth_client.py | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/pysnow/oauth_client.py b/pysnow/oauth_client.py index e659159..592d5e1 100644 --- a/pysnow/oauth_client.py +++ b/pysnow/oauth_client.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- import warnings -import six +import logging from oauthlib.oauth2 import LegacyApplicationClient from oauthlib.oauth2.rfc6749.errors import OAuth2Error @@ -12,6 +12,8 @@ warnings.simplefilter("always", DeprecationWarning) +logger = logging.getLogger('pysnow') + class OAuthClient(Client): """Pysnow `Client` with extras for oauth session and token handling. @@ -34,7 +36,6 @@ def __init__(self, client_id=None, client_secret=None, token_updater=None, **kwa 'provided user / password credentials or sessions will be ignored.') # Forcibly set session, user and password - kwargs['session'] = OAuth2Session(client=LegacyApplicationClient(client_id=client_id)) kwargs['user'] = None kwargs['password'] = None @@ -128,12 +129,16 @@ def generate_token(self, user, password): - TokenCreateError: If there was an error generating the new token """ + logger.debug('(TOKEN_CREATE) :: User: %s' % user) + + session = OAuth2Session(client=LegacyApplicationClient(client_id=self.client_id)) + try: - return dict(self.session.fetch_token(token_url=self.token_url, - username=user, - password=password, - client_id=self.client_id, - client_secret=self.client_secret)) + return dict(session.fetch_token(token_url=self.token_url, + username=user, + password=password, + client_id=self.client_id, + client_secret=self.client_secret)) except OAuth2Error as exception: raise TokenCreateError('Error creating user token', exception.description, exception.status_code) From 518f6dd1a74ea5d4128f340c3fb3f02f88c603d8 Mon Sep 17 00:00:00 2001 From: Robert Wikman Date: Fri, 16 Feb 2018 00:22:00 +0100 Subject: [PATCH 08/10] Logging, fixes in OAuth session handling --- pysnow/client.py | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/pysnow/client.py b/pysnow/client.py index 29ca581..8524728 100644 --- a/pysnow/client.py +++ b/pysnow/client.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- +import logging import inspect import warnings @@ -16,6 +17,8 @@ warnings.simplefilter("always", DeprecationWarning) +logger = logging.getLogger('pysnow') + class Client(object): """User-created Client object. @@ -61,10 +64,11 @@ def __init__(self, if not (host or instance): raise InvalidUsage("You must supply either 'instance' or 'host'") - if not (user and password) and not session: - raise InvalidUsage("You must supply either username and password or a session object") - elif (user and session) is not None: - raise InvalidUsage("Provide either username and password or a session, not both.") + if not isinstance(self, pysnow.OAuthClient): + if not (user and password) and not session: + raise InvalidUsage("You must supply either username and password or a session object") + elif (user and session) is not None: + raise InvalidUsage("Provide either username and password or a session, not both.") self.parameters = ParamsBuilder() @@ -80,9 +84,12 @@ def __init__(self, self._user = user self._password = password self.use_ssl = use_ssl - self.base_url = URLBuilder.get_base_url(use_ssl, instance, host) - self.session = self._get_session(session) + + if not isinstance(self, pysnow.OAuthClient): + self.session = self._get_session(session) + else: + self.session = None def _get_session(self, session): """Creates a new session with basic auth, unless one was provided, and sets headers. @@ -91,10 +98,13 @@ def _get_session(self, session): :return: - :class:`requests.Session` object """ + if not session: + logger.debug('(SESSION_CREATE) User: %s' % self._user) s = requests.Session() s.auth = HTTPBasicAuth(self._user, self._password) else: + logger.debug('(SESSION_CREATE) Object: %s' % session) s = session s.headers.update( From c8ba9027a6266cfdc2cb07918a4fb521c5277f52 Mon Sep 17 00:00:00 2001 From: Robert Wikman Date: Fri, 16 Feb 2018 00:22:29 +0100 Subject: [PATCH 09/10] Bumped, implemented logger --- pysnow/__init__.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/pysnow/__init__.py b/pysnow/__init__.py index 350574b..64d64fa 100644 --- a/pysnow/__init__.py +++ b/pysnow/__init__.py @@ -7,4 +7,15 @@ from .resource import Resource __author__ = "Robert Wikman " -__version__ = "0.6.7" +__version__ = "0.6.8" + +# Set default logging handler to avoid "No handler found" warnings. +import logging +try: # Python 2.7+ + from logging import NullHandler +except ImportError: + class NullHandler(logging.Handler): + def emit(self, record): + pass + +logging.getLogger(__name__).addHandler(NullHandler()) From 4cbc74a0379fd2831389f14b6b4fe12ae89d69ea Mon Sep 17 00:00:00 2001 From: Robert Wikman Date: Fri, 16 Feb 2018 00:32:41 +0100 Subject: [PATCH 10/10] Removed no longer valid OAuth tests --- tests/test_oauth_client.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/test_oauth_client.py b/tests/test_oauth_client.py index 9aed9af..002dc0e 100644 --- a/tests/test_oauth_client.py +++ b/tests/test_oauth_client.py @@ -68,7 +68,6 @@ def test_oauth_session_user_override(self): c = OAuthClient(instance="test", client_id="test1", client_secret="test2", session="testsess", user="testuser", password="testpass") - self.assertEqual(isinstance(c.session, OAuth2Session), True) self.assertEqual(c._user, None) self.assertEqual(c._password, None) @@ -86,7 +85,6 @@ def test_set_token(self): c.set_token(self.mock_token) self.assertEqual(c.token, self.mock_token) - self.assertEqual(isinstance(c.session, OAuth2Session), True) def test_request_without_token(self): """OauthClient should raise MissingToken when creating query when no token has been set"""