Skip to content

Commit

Permalink
Merge pull request myemma#14 from myemma/feature/add-automation-resource
Browse files Browse the repository at this point in the history
Adds support for new Automation models and Workflow Resource
  • Loading branch information
travishathaway authored Feb 8, 2018
2 parents d823336 + 2f52953 commit a25da6d
Show file tree
Hide file tree
Showing 5 changed files with 213 additions and 0 deletions.
7 changes: 7 additions & 0 deletions emma/model/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@


SERIALIZED_DATETIME_FORMAT = "@D:%Y-%m-%dT%H:%M:%S"
SERIALIZED_DATETIME_ALT_FORMAT = "%Y-%m-%d %H:%M:%S.%f"


def str_fields_to_datetime(fields, raw):
Expand All @@ -13,6 +14,12 @@ def str_fields_to_datetime(fields, raw):
for x in raw.items() if x[0] in fields and x[1] is not None)


def str_fields_to_datetime_alt(fields, raw):
"""Parses Emma date fields to :class:`datetime` objects"""
return dict((x[0], datetime.strptime(x[1], SERIALIZED_DATETIME_ALT_FORMAT))
for x in raw.items() if x[0] in fields and x[1] is not None)


class BaseApiModel(collections.MutableMapping):
"""Creates a model with dictionary access"""
def __init__(self, raw=None):
Expand Down
84 changes: 84 additions & 0 deletions emma/model/account.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import emma.model.search
import emma.model.trigger
import emma.model.webhook
import emma.model.automation


class Account(object):
Expand Down Expand Up @@ -54,6 +55,7 @@ def __init__(self, account_id, public_key, private_key):
self.searches = AccountSearchCollection(self)
self.triggers = AccountTriggerCollection(self)
self.webhooks = AccountWebHookCollection(self)
self.workflows = AccountWorkflowCollect(self)


class AccountFieldCollection(BaseApiModel):
Expand Down Expand Up @@ -1132,3 +1134,85 @@ def list_events(self):
"""
path = '/webhooks/events'
return self.account.adapter.get(path)


class AccountWorkflowCollect(BaseApiModel):
"""
Encapsulates operations for the set of :class:`Workflow` objects of an
:class:`account`
:param account: The Account which owns this collection
:type account: :class:`Account`
"""

def __init__(self, account):
self.account = account
super(AccountWorkflowCollect, self).__init__()

def factory(self, raw=None):
"""
New :class:`Workflow` factory
:param raw: Raw data with which to populate class
:type raw: :class:`dict`
:rtype: :class:`Workflow`
Usage::
>>> from emma.model.account import Account
>>> acct = Account(1234, "08192a3b4c5d6e7f", "f7e6d5c4b3a29180")
>>> acct.workflows.factory()
<Workflow{}>
>>> acct.triggers.factory({'id': u"test-automation-id", ...})
<Workflow{'id': ...}>
"""
return emma.model.automation.Workflow(self.account, raw)

def fetch_all(self):
"""
Lazy-loads the full set of :class:`Workflow` objects
:rtype: :class:`dict` of :class:`Workflow` objects
Usage::
>>> from emma.model.account import Account
>>> acct = Account(1234, "08192a3b4c5d6e7f", "f7e6d5c4b3a29180")
>>> acct.workflows.fetch_all()
{'adfasdfasdf123123': <Workflow>, 'afadf23324': <Workflow>, ...}
"""
automation = emma.model.automation
path = '/automation/workflows'
if not self._dict:
self._dict = dict(
(x['workflow_id'], automation.Workflow(self.account, x))
for x in self.account.adapter.paginated_get(path))
return self._dict

def find_one_by_workflow_id(self, workflow_id):
"""
Lazy-loads a single :class:`WorkFlow` by ID
:param workflow_id: The workflow identifier
:type workflow_id: :class:`int`
:rtype: :class:`Field` or :class:`None`
Usage::
>>> from emma.model.account import Account
>>> acct = Account(1234, "08192a3b4c5d6e7f", "f7e6d5c4b3a29180")
>>> acct.workflows.find_one_by_workflow_id('1kj131hj31239231') # does not exist
raises <KeyError>
>>> acct.workflows.find_one_by_workflow_id('21123123jnl123')
<Workflow>
>>> acct.workflows[123]
<Workflow>
"""
path = '/automation/workflows/%s' % workflow_id
if workflow_id not in self._dict:
automation = emma.model.automation
raw = self.account.adapter.get(path)
if raw:
self._dict[workflow_id] = automation.Workflow(self.account, raw)

return (workflow_id in self._dict) and self._dict[workflow_id] or None
36 changes: 36 additions & 0 deletions emma/model/automation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
"""Automation models"""

from emma.model import BaseApiModel, str_fields_to_datetime_alt


class Workflow(BaseApiModel):
"""
Encapsulates operations for a :class:`Workflow`
:param account: The Account which owns this Workflow
:type account: :class:`Account`
:param raw: The raw values of this :class:`Workflow`
:type raw: :class:`dict`
Usage::
>>> from emma.model.account import Account
>>> acct = Account(1234, "08192a3b4c5d6e7f", "f7e6d5c4b3a29180")
>>> auto = acct.workflows[123]
>>> auto
<Workflow>
"""
def __init__(self, account, raw=None):
self.account = account
super(Workflow, self).__init__(raw)

# def __repr__(self):
# return '<Workflow: {}>'.format(self.workflow_id)

def _parse_raw(self, raw):
raw.update(
str_fields_to_datetime_alt(
['created_at', 'updated_at'], raw
)
)
return raw
50 changes: 50 additions & 0 deletions tests/model/account_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
from emma.model.search import Search
from emma.model.trigger import Trigger
from emma.model.webhook import WebHook
from emma.model.automation import Workflow
from tests.model import MockAdapter


Expand Down Expand Up @@ -2027,3 +2028,52 @@ def test_can_list_events(self):
self.webhooks.account.adapter.call,
('GET', '/webhooks/events', {}))
self.assertEquals(0, len(self.webhooks))


class AccountWorkflowTest(unittest.TestCase):
def setUp(self):
Account.default_adapter = MockAdapter
self.workflows = Account(
account_id="100",
public_key="xxx",
private_key="yyy").workflows

def test_fetch_all_returns_a_dictionary(self):
MockAdapter.expected = [{'workflow_id': 201}]
self.assertIsInstance(self.workflows.fetch_all(), dict)
self.assertEquals(self.workflows.account.adapter.called, 1)
self.assertEquals(
self.workflows.account.adapter.call,
('GET', '/automation/workflows', {}))

def test_fetch_all_returns_a_dictionary(self):
MockAdapter.expected = [{'workflow_id': 201}]
self.assertIsInstance(self.workflows.fetch_all(), dict)
self.assertEquals(self.workflows.account.adapter.called, 1)
self.assertEquals(
self.workflows.account.adapter.call,
('GET', '/automation/workflows', {}))

def test_find_one_by_workflow_id_returns_an_import_object(self):
MockAdapter.expected = {'workflow_id': 201}
workflow = self.workflows.find_one_by_workflow_id(201)
self.assertIsInstance(workflow, Workflow)
self.assertEquals(workflow['workflow_id'], 201)
self.assertEquals(self.workflows.account.adapter.called, 1)
self.assertEquals(
self.workflows.account.adapter.call,
('GET', '/automation/workflows/201', {}))

def test_find_one_by_workflow_id_populates_collection(self):
MockAdapter.expected = {'workflow_id': 201}
self.workflows.find_one_by_workflow_id(201)
self.assertIn(201, self.workflows)
self.assertIsInstance(self.workflows[201], Workflow)
self.assertEquals(self.workflows[201]['workflow_id'], 201)

def test_find_one_by_workflow_id_caches_result(self):
MockAdapter.expected = {'workflow_id': 201}
self.workflows.find_one_by_workflow_id(201)
self.workflows.find_one_by_workflow_id(201)
self.assertEquals(self.workflows.account.adapter.called, 1)

36 changes: 36 additions & 0 deletions tests/model/automation_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
from datetime import datetime
import unittest

from emma.model import SERIALIZED_DATETIME_ALT_FORMAT
from emma import exceptions as ex
from emma.model.account import Account
from emma.model.automation import Workflow

from tests.model import MockAdapter


class WorkflowTest(unittest.TestCase):
"""
Tests for the Workflow model
"""

def setUp(self):
"""
Set up tasks for our tests
"""
Account.default_adapter = MockAdapter
self.workflow = Workflow(
Account(account_id="100", public_key="xxx", private_key="yyy"),
{
'workflow_id': '22048a49-9533-4014-ae03-2af3598ed9a7',
'status': 'active',
'name': 'Test',
'created_at': datetime.now().strftime(SERIALIZED_DATETIME_ALT_FORMAT),
'updated_at': datetime.now().strftime(SERIALIZED_DATETIME_ALT_FORMAT),
}
)

def test_can_represent_workflow(self):
self.assertEquals(
u"<Workflow" + repr(self.workflow._dict) + u">",
repr(self.workflow))

0 comments on commit a25da6d

Please sign in to comment.