Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,17 @@ Release History
Upcoming
++++++++

1.3.2
1.3.3 (2015-12-22)
++++++++++++++++++

- Added a new class, ``DeveloperTokenClient`` that makes it easy to get started using the SDK with a Box developer
token. It uses another new class, ``DeveloperTokenAuth`` for auth.

**Bugfixes**

- Added limit, offset, and filter_term parameters to ``client.users()`` to match up with the Box API.

1.3.2 (2015-11-16)
++++++++++++++++++

- Fix ``boxsdk.util.log.setup_logging()`` on Python 3.
Expand Down
54 changes: 43 additions & 11 deletions boxsdk/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,21 +100,48 @@ def group(self, group_id):
"""
return Group(session=self._session, object_id=group_id)

def users(self):
def users(self, limit=None, offset=0, filter_term=None):
"""
Get a list of all users for the Enterprise along with their user_id, public_name, and login.

:param limit:
The maximum number of users to return. If not specified, the Box API will determine an appropriate limit.
:type limit:
`int` or None
:param offset:
The user index at which to start the response.
:type offset:
`int`
:param filter_term:
Filters the results to only users starting with the filter_term in either the name or the login.
:type filter_term:
`unicode` or None
:return:
The list of all users in the enterprise.
:rtype:
`list` of :class:`User`
"""
url = '{0}/users'.format(API.BASE_API_URL)
box_response = self._session.get(url)
params = dict(offset=offset)
if limit is not None:
params['limit'] = limit
if filter_term is not None:
params['filter_term'] = filter_term
box_response = self._session.get(url, params=params)
response = box_response.json()
return [User(self._session, item['id'], item) for item in response['entries']]

def search(self, query, limit, offset, ancestor_folders=None, file_extensions=None, metadata_filters=None, result_type=None, content_types=None):
def search(
self,
query,
limit,
offset,
ancestor_folders=None,
file_extensions=None,
metadata_filters=None,
result_type=None,
content_types=None
):
"""
Search Box for items matching the given query.

Expand Down Expand Up @@ -155,14 +182,16 @@ def search(self, query, limit, offset, ancestor_folders=None, file_extensions=No
:rtype:
`list` of :class:`Item`
"""
return Search(self._session).search(query=query,
limit=limit,
offset=offset,
ancestor_folders=ancestor_folders,
file_extensions=file_extensions,
metadata_filters=metadata_filters,
result_type=result_type,
content_types=content_types)
return Search(self._session).search(
query=query,
limit=limit,
offset=offset,
ancestor_folders=ancestor_folders,
file_extensions=file_extensions,
metadata_filters=metadata_filters,
result_type=result_type,
content_types=content_types,
)

def events(self):
"""
Expand Down Expand Up @@ -333,5 +362,8 @@ def with_shared_link(self, shared_link, shared_link_password):


class DeveloperTokenClient(Client):
"""
Box client subclass which authorizes with a developer token.
"""
def __init__(self, oauth=None, network_layer=None, session=None):
super(DeveloperTokenClient, self).__init__(oauth or DeveloperTokenAuth(), network_layer, session)
4 changes: 2 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,15 +61,15 @@ def main():
install_requires.append('ordereddict>=1.1')
setup(
name='boxsdk',
version='1.3.2',
version='1.3.3',
description='Official Box Python SDK',
long_description=open(join(base_dir, 'README.rst')).read(),
author='Box',
author_email='oss@box.com',
url='http://opensource.box.com',
packages=find_packages(exclude=['demo', 'docs', 'test']),
install_requires=install_requires,
extras_require={'jwt': jwt_requires, 'redis': redis_requires},
extras_require={'jwt': jwt_requires, 'redis': redis_requires, 'all': jwt_requires + redis_requires},
tests_require=['pytest', 'pytest-xdist', 'mock', 'sqlalchemy', 'bottle', 'jsonpatch'],
cmdclass={'test': PyTest},
classifiers=CLASSIFIERS,
Expand Down
34 changes: 32 additions & 2 deletions test/unit/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,10 +159,40 @@ def test_factory_returns_the_correct_object(mock_client, test_class, factory_met
assert obj.object_id == fake_id


def test_users_return_the_correct_user_objects(mock_client, mock_box_session, users_response, user_id_1, user_id_2):
@pytest.fixture(scope='module', params=(None, 'user1'))
def users_filter_term(request):
return request.param


@pytest.fixture(scope='module', params=(0, 10))
def users_offset(request):
return request.param


@pytest.fixture(scope='module', params=(0, 10))
def users_limit(request):
return request.param


def test_users_return_the_correct_user_objects(
mock_client,
mock_box_session,
users_response,
user_id_1,
user_id_2,
users_filter_term,
users_offset,
users_limit,
):
# pylint:disable=redefined-outer-name
mock_box_session.get.return_value = users_response
users = mock_client.users()
users = mock_client.users(users_limit, users_offset, users_filter_term)
expected_params = {'offset': users_offset}
if users_limit is not None:
expected_params['limit'] = users_limit
if users_filter_term is not None:
expected_params['filter_term'] = users_filter_term
mock_box_session.get.assert_called_once_with('{0}/users'.format(API.BASE_API_URL), params=expected_params)
assert users[0].object_id == user_id_1
assert users[1].object_id == user_id_2

Expand Down