Skip to content

Commit

Permalink
Merge pull request #47 from plaid/bjp-lt-search
Browse files Browse the repository at this point in the history
Adding Long Tail search support
  • Loading branch information
Bpless committed Jan 6, 2016
2 parents e0f495e + 51a29c0 commit f944e9c
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 22 deletions.
28 changes: 27 additions & 1 deletion plaid/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
patch_request,
post_request
)
from plaid.utils import json, urljoin, to_json
from plaid.utils import json, urljoin, to_json, urlencode
from plaid.errors import UnauthorizedError


Expand Down Expand Up @@ -107,6 +107,7 @@ class Client(object):
'info_get': '/info/get',
'institutions': '/institutions',
'institution': '/institutions/{}',
'institution_search': '/institutions/search',
'upgrade': '/upgrade',
'exchange_token': '/exchange_token',
}
Expand Down Expand Up @@ -455,3 +456,28 @@ def institution(self, url, institution_id):
url.format(institution_id),
suppress_errors=self.suppress_http_errors
)

@inject_url('institution_search')
def institution_search(self, url, q=None, p=None, institution_id=None):
'''
Perform simple search query against Long Tail institutions.
`q` str Query against the full list of institutions.
`p` str Filter FIs by a single product (Optional).
`institution_id` str The id of a single institution
for lookup (Optional).
'''

assert q is not None or institution_id is not None, (
'query or institution_id required'
)

params = dict([(key, value) for key, value in [
('q', q),
('p', p),
('id', institution_id)
] if value is not None])
return get_request(
'{}{}{}'.format(url, '?' if params else '', urlencode(params)),
suppress_errors=self.suppress_http_errors
)
66 changes: 52 additions & 14 deletions tests/integration/test_client.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,18 @@
from collections import defaultdict

import pytest
from mock import patch, Mock

from plaid import Client
from plaid.utils import json, to_json
from plaid.utils import to_json
from plaid.errors import (
ResourceNotFoundError,
UnauthorizedError
ResourceNotFoundError,
UnauthorizedError
)

no_mfa_credentials = {
'username': 'plaid_test',
'password': 'plaid_good',
'username': 'plaid_test',
'password': 'plaid_good',
}


def test_auth_no_mfa():
client = Client('test_id', 'test_secret')
response = client.auth('wells', no_mfa_credentials)
Expand Down Expand Up @@ -89,7 +87,7 @@ def test_connect_step_question_loop():
def test_connect_step_device_email():
client = Client('test_id', 'test_secret', access_token='test_chase')
response = client.connect_step('chase', None, options={
'send_method': {'type': 'email'}
'send_method': {'type': 'email'}
})
assert response.status_code == 201
assert to_json(response)['type'] == 'device'
Expand All @@ -99,7 +97,7 @@ def test_connect_step_device_email():
def test_connect_step_device_phone():
client = Client('test_id', 'test_secret', access_token='test_chase')
response = client.connect_step('chase', None, options={
'send_method': {'type': 'phone'}
'send_method': {'type': 'phone'}
})
assert response.status_code == 201
assert to_json(response)['type'] == 'device'
Expand Down Expand Up @@ -139,6 +137,7 @@ def test_exchange():
assert to_json(response)['access_token'] == 'test_chase'
assert client.access_token == 'test_chase'


def test_balance():
client = Client('test_id', 'test_secret', access_token='test_bofa')
response = client.balance()
Expand Down Expand Up @@ -186,16 +185,55 @@ def test_institutions():
def test_institution():
client = Client('test_id', 'test_secret')
response = client.institution(
to_json(client.institutions())[0]['id']
to_json(client.institutions())[0]['id']
)

assert response.status_code == 200


def test_institution_search():
client = Client('test_id', 'test_secret')
response = client.institution_search('wells', 'auth')
assert response.status_code == 200


def test_institution_search_with_multi_tokens():
client = Client('test_id', 'test_secret')
response = client.institution_search('wells fargo', 'auth')
assert response.status_code == 200
assert to_json(response)[0]['name'] == 'Wells Fargo'


def test_institution_search_with_bad_product():
client = Client('test_id', 'test_secret')
response = client.institution_search('wells fargo', 'bad')
assert response.status_code == 200
assert len(to_json(response)) == 0


def test_institution_search_without_product():
client = Client('test_id', 'test_secret')
response = client.institution_search('wells')
assert response.status_code == 200


def test_institution_search_with_bad_id():
client = Client('test_id', 'test_secret')
response = client.institution_search(institution_id='bad')
assert response.status_code == 200
assert len(to_json(response)) == 0


def test_institution_search_requires_q_or_id():
client = Client('test_id', 'test_secret')
with pytest.raises(AssertionError):
client.institution_search(p='auth')


def test_UnauthorizedError_bad_token():
client = Client('test_id', 'test_secret', 'test_zoba')
with pytest.raises(UnauthorizedError):
client.balance()
client.balance()


def test_unauthorizedError_bad_username():
Expand All @@ -213,13 +251,13 @@ def test_unauthorizedError_bad_password():
def test_ResourceNotFound_connect():
client = Client('test_id', 'test_secret')
with pytest.raises(ResourceNotFoundError):
client.connect('pnc', no_mfa_credentials)
client.connect('pnc', no_mfa_credentials)


def test_ResourceNotFound_categories():
client = Client('test_id', 'test_secret')
with pytest.raises(ResourceNotFoundError):
client.category('pnc')
client.category('pnc')


def test_ResourceNotFound_categories_with_suppressed_error():
Expand Down
10 changes: 3 additions & 7 deletions tests/unit/test_client.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
import pytest
from mock import patch, Mock

from plaid.client import (
Client,
inject_credentials,
inject_url,
store_access_token
Expand Down Expand Up @@ -107,8 +103,8 @@ def some_func(self):
return Response()

obj = TestClass()
response = obj.some_func()
assert obj.access_token == None
obj.some_func()
assert obj.access_token is None


def test_store_access_token_on_non_200():
Expand All @@ -126,5 +122,5 @@ def some_func(self):
return Response()

obj = TestClass()
response = obj.some_func()
obj.some_func()
assert obj.access_token == 5

0 comments on commit f944e9c

Please sign in to comment.