Skip to content
Permalink
Browse files

small tweaks

  • Loading branch information...
matthewcornell committed Sep 10, 2019
1 parent 31f2d2e commit e348423606af22f99c7074ba7ae7576dc375b000
Showing with 43 additions and 34 deletions.
  1. +23 −19 tests/test_connection.py
  2. +20 −15 zoltpy/connection.py
@@ -1,34 +1,38 @@
'''
WIP
'''

import unittest
from unittest.mock import patch
from unittest.mock import patch, MagicMock

from zoltpy.connection import ZoltarConnection, ZoltarSession


# MOCK_TOKEN is an expired token as returned by zoltar. decoded contents:
# - header: {"typ": "JWT", "alg": "HS256"}
# - payload: {"user_id": 3, "username": "model_owner1", "exp": 1558442805, "email": ""}
# - expiration:
# 05/21/2019 @ 12:46pm (UTC)
# 2019-05-21T12:46:45+00:00 (ISO 8601)
# Tuesday, May 21, 2019 12:46:45 PM (GMT)
# datetime(2019, 5, 21, 12, 46, 45) (python): datetime.utcfromtimestamp(1558442805)
MOCK_TOKEN = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjozLCJ1c2VybmFtZSI6Im1vZGVsX293bmVyMSIsImV4cCI6MTU1ODQ0MjgwNSwiZW1haWwiOiIifQ.o03V2RxkFpA5ThhRAidwDWCdcQNeJzr1wwFkOFKUI74"


class TestConnection(unittest.TestCase):
"""
"""

def test_authenticate(self):
host = 'http://idonotexist.com'
conn = ZoltarConnection(host)
self.assertEqual(host, conn.host)

def test_authenticate(self):
conn = ZoltarConnection('')
u = 'username'
p = 'password'
token = '''eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM
0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2Mj
M5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c'''
with patch.object(ZoltarSession, '_get_token', return_value=token) as mock_method:
# with patch('zoltpy.connection.ZoltarSession._get_token', return_value=token) as mock_method:
with patch('requests.post', return_value=MagicMock()) as post_mock:
post_mock.return_value.status_code = 200
post_mock.return_value.json = MagicMock(return_value={'token': MOCK_TOKEN})
conn.authenticate(u, p)
print('XX', conn.session.token)
self.assertEqual(u, conn.username)
self.assertEqual(p, conn.password)
self.assertIsInstance(conn.session, ZoltarSession)


def test_is_token_expired(self):
self.fail() # todo xx
self.assertEqual(MOCK_TOKEN, conn.session.token)
post_mock.assert_called_once_with('/api-token-auth/', {'username': 'username', 'password': 'password'})


if __name__ == '__main__':
@@ -9,14 +9,14 @@


class ZoltarConnection:
"""
Represents a connection to a Zoltar server. This is an object-oriented interface that may be best suited to zoltpy
developers. See the `util` module for a name-based non-OOP interface.
# notes:
# - implement is_token_expired()
# - get, upload, delete should call re_authenticate_if_necessary()
# - needs tests! should be straightforward to mock internal ZoltarResource json responses
# - incomplete - ZoltarResource children only have a few properties implemented
# - caches resource json, but doesn't automatically handle becoming stale, refreshing, etc.
# - no back-pointers are stored, e.g., Model -> owning Project
Notes:
- This implementation uses the simple approach of caching the JSON response for resource URLs, but doesn't
automatically handle their becoming stale, hence the need to call ZoltarResource.refresh().
"""


def __init__(self, host='https://zoltardata.com'):
@@ -37,14 +37,16 @@ def re_authenticate_if_necessary(self):


@property
def projects(self): # entry point into ZoltarResources. NB: hits API
def projects(self):
"""
The entry point into ZoltarResources. Returns a list of Projects. NB: A property, but hits the API.
"""
# NB: here we are throwing away each project's json, which is here because the API returns json objects for
# projects rather than just URIs
return [Project(self, project_json['url']) for project_json in
self._json_for_uri(self.host + '/api/projects/')]
return [Project(self, project_json['url']) for project_json in self.json_for_uri(self.host + '/api/projects/')]


def _json_for_uri(self, uri):
def json_for_uri(self, uri):
if not self.session:
raise RuntimeError('_validate_authentication(): no session')

@@ -86,16 +88,19 @@ def is_token_expired(self):

class ZoltarResource(ABC):
"""
An abstract proxy for a Zoltar object at a particular URI including its JSON. NB: subclasses not meant to be
directly instantiated by users.
An abstract proxy for a Zoltar object at a particular URI including its JSON. All it does is cache JSON from a
URI. Notes:
- This class and its subclasses are not meant to be directly instantiated by users. Instead the user enters through
ZoltarConnection.projects and then drills down.
- Because the JSON is cached, it will become stale after the source object in the server changes, such as when a
model's forecasts change. Thus, use refresh() as needed.
"""


def __init__(self, zoltar_connection, uri): # NB: hits API
self.zoltar_connection = zoltar_connection
self.uri = uri
self.json = None # cached -> can become stale!

self.refresh()


@@ -105,7 +110,7 @@ def id(self):


def refresh(self):
self.json = self.zoltar_connection._json_for_uri(self.uri)
self.json = self.zoltar_connection.json_for_uri(self.uri)


def delete(self):

0 comments on commit e348423

Please sign in to comment.
You can’t perform that action at this time.