Skip to content

Commit ce8437a

Browse files
committed
Merge branch 'master' into jwt
2 parents da79dbe + f26bb9c commit ce8437a

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

64 files changed

+1600
-123
lines changed

.pylintrc

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,6 @@
77
# pygtk.require().
88
#init-hook=
99

10-
# Profiled execution.
11-
profile=no
12-
1310
# Add files or directories to the blacklist. They should be base names, not
1411
# paths.
1512
#ignore=CVS
@@ -68,20 +65,13 @@ reports=no
6865
# (RP0004).
6966
evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)
7067

71-
# Add a comment according to your evaluation note. This is used by the global
72-
# evaluation report (RP0004).
73-
comment=no
74-
7568
# Template used to display messages. This is a python new-style format string
7669
# used to format the massage information. See doc for all details
7770
msg-template={module}:{line}:{column}: [{msg_id}({symbol}), {obj}] {msg}
7871

7972

8073
[BASIC]
8174

82-
# Required attributes for module, separated by a comma
83-
required-attributes=
84-
8575
# List of builtins function names that should not be used, separated by a comma
8676
bad-functions=map,filter,apply,input
8777

@@ -131,6 +121,8 @@ no-docstring-rgx=__.*__
131121
# ones are exempt.
132122
docstring-min-length=-1
133123

124+
# Maximum number of nested blocks for function / method body
125+
max-nested-blocks=6
134126

135127
[FORMAT]
136128

@@ -180,10 +172,6 @@ ignore-mixin-members=yes
180172
#ignored-classes=SQLObject
181173
ignored-classes=pytest, _pytest
182174

183-
# When zope mode is activated, add a predefined set of Zope acquired attributes
184-
# to generated-members.
185-
zope=no
186-
187175
# List of members which are set dynamically and missed by pylint inference
188176
# system, and so shouldn't trigger E0201 when accessed. Python regular
189177
# expressions are accepted.
@@ -206,10 +194,6 @@ additional-builtins=
206194

207195
[CLASSES]
208196

209-
# List of interface methods to ignore, separated by a comma. This is used for
210-
# instance to not check methods defines in Zope's Interface base class.
211-
ignore-iface-methods=
212-
213197
# List of method names used to declare (i.e. assign) instance attributes.
214198
defining-attr-methods=__init__,__new__,setUp
215199

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ matrix:
2121
- python: 3.5
2222
env: TOX_ENV=py35
2323
- python: pypy
24-
env: TOX_ENV=pypy
24+
env: TOX_ENV=pypy PYPY_VERSION='4.0.0'
2525
- python: 2.7
2626
env: TOX_ENV=pep8
2727
- python: 2.7

.travis/install.sh

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,21 +42,21 @@ if [[ "$(uname -s)" == 'Darwin' ]]; then
4242
pyenv global 3.5.0
4343
;;
4444
pypy)
45-
pyenv install pypy-2.6.0
46-
pyenv global pypy-2.6.0
45+
pyenv install "pypy-${PYPY_VERSION}"
46+
pyenv global "pypy-${PYPY_VERSION}"
4747
;;
4848
esac
4949
pyenv rehash
5050
python -m pip install -U --user virtualenv
5151
else
52-
# temporary pyenv installation to get pypy-2.6 before container infra upgrade
52+
# pyenv installation to get specified pypy version (Travis may only have older version(s))
5353
if [[ "${TOX_ENV}" == "pypy" ]]; then
5454
git clone https://github.com/yyuu/pyenv.git $PWD/.pyenv
5555
export PYENV_ROOT="$PWD/.pyenv"
5656
export PATH="$PYENV_ROOT/bin:$PATH"
5757
eval "$(pyenv init -)"
58-
pyenv install pypy-2.6.0
59-
pyenv global pypy-2.6.0
58+
pyenv install "pypy-${PYPY_VERSION}"
59+
pyenv global "pypy-${PYPY_VERSION}"
6060
fi
6161
pip install -U virtualenv
6262
fi

.travis/run.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ else
1414
export PYENV_ROOT="$PWD/.pyenv"
1515
export PATH="$PYENV_ROOT/bin:$PATH"
1616
eval "$(pyenv init -)"
17-
pyenv global pypy-2.6.0
17+
pyenv global "pypy-${PYPY_VERSION}"
1818
fi
1919
fi
2020
source $PWD/.venv/bin/activate

HISTORY.rst

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,46 @@ Release History
66
Upcoming
77
++++++++
88

9+
1.3.3 (2016-01-04)
10+
++++++++++++++++++
11+
12+
**Bugfixes**
13+
14+
- Fixed import error for installations that don't have redis installed.
15+
- Fixed use of ``raw_input`` in the developer token auth for py3 compatibility.
16+
17+
18+
1.3.3 (2015-12-22)
19+
++++++++++++++++++
20+
21+
- Added a new class, ``DeveloperTokenClient`` that makes it easy to get started using the SDK with a Box developer
22+
token. It uses another new class, ``DeveloperTokenAuth`` for auth.
23+
24+
**Bugfixes**
25+
26+
- Added limit, offset, and filter_term parameters to ``client.users()`` to match up with the Box API.
27+
28+
1.3.2 (2015-11-16)
29+
++++++++++++++++++
30+
31+
- Fix ``boxsdk.util.log.setup_logging()`` on Python 3.
32+
33+
1.3.1 (2015-11-06)
34+
++++++++++++++++++
35+
36+
- Add requests-toolbelt to setup.py (it was accidentally missing from 1.3.0).
37+
38+
1.3.0 (2015-11-05)
39+
++++++++++++++++++
40+
941
- CPython 3.5 support.
1042
- Support for cryptography>=1.0 on PyPy 2.6.
1143
- Travis CI testing for CPython 3.5 and PyPy 2.6.0.
44+
- Added a logging network class that logs requests and responses.
45+
- Added new options for auth classes, including storing tokens in Redis and storing them on a remote server.
46+
- Stream uploads of files from disk.
1247

13-
1.2.1 (2015-07-22)
48+
1.2.2 (2015-07-22)
1449
++++++++++++++++++
1550

1651
- The SDK now supports setting a password when creating a shared link.
@@ -26,11 +61,11 @@ Upcoming
2661
++++++++++++++++++
2762

2863
- Added support for Box Developer Edition. This includes JWT auth (auth as enterprise or as app user),
29-
and `create_user` functionality.
64+
and ``create_user`` functionality.
3065
- Added support for setting shared link expiration dates.
3166
- Added support for setting shared link permissions.
3267
- Added support for 'As-User' requests. See https://box-content.readme.io/#as-user-1
33-
- Improved support for accessing shared items. Items returned from the `client.get_shared_item` method will
68+
- Improved support for accessing shared items. Items returned from the ``client.get_shared_item`` method will
3469
remember the shared link (and the optionally provided shared link password) so methods called on the returned
3570
items will be properly authorized.
3671

@@ -65,7 +100,7 @@ Upcoming
65100
1.1.3 (2015-03-26)
66101
++++++++++++++++++
67102

68-
- Added support for the /shared_items endpoint. `client.get_shared_item` can be used to get information about
103+
- Added support for the /shared_items endpoint. ``client.get_shared_item`` can be used to get information about
69104
a shared link. See https://developers.box.com/docs/#shared-items
70105

71106
1.1.2 (2015-03-20)

README.rst

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,8 @@ Authenticate (get access/refresh token)
6363

6464
If you navigate the user to the auth_url, the user will eventually get
6565
redirected to http://YOUR_REDIRECT_URL?code=YOUR_AUTH_CODE. After
66-
getting the code, you will be able to use the code to exchange for
67-
access token and fresh token.
66+
getting the code, you will be able to use the code to exchange for an
67+
access token and refresh token.
6868

6969
The SDK handles all the work for you; all you need to do is run:
7070

@@ -248,7 +248,7 @@ instead use an instance of `JWTAuth`.
248248
auth = JWTAuth(
249249
client_id='YOUR_CLIENT_ID',
250250
client_secret='YOUR_CLIENT_SECRET',
251-
enterprise_token='YOUR_ENTERPRISE_TOKEN',
251+
enterprise_id='YOUR_ENTERPRISE_ID',
252252
rsa_private_key_file_sys_path='CERT.PEM',
253253
store_tokens=your_store_tokens_callback_method,
254254
)
@@ -272,7 +272,7 @@ These users can then be authenticated:
272272
ned_auth = JWTAuth(
273273
client_id='YOUR_CLIENT_ID',
274274
client_secret='YOUR_CLIENT_SECRET',
275-
enterprise_token='YOUR_ENTERPRISE_TOKEN',
275+
enterprise_id='YOUR_ENTERPRISE_ID',
276276
rsa_private_key_file_sys_path='CERT.PEM',
277277
store_tokens=your_store_tokens_callback_method,
278278
)
@@ -282,6 +282,31 @@ These users can then be authenticated:
282282
Requests made with `ned_client` (or objects returned from `ned_client`'s methods)
283283
will be performed on behalf of the newly created app user.
284284

285+
Other Auth Options
286+
------------------
287+
288+
For advanced uses of the SDK, two additional auth classes are provided:
289+
290+
- `CooperativelyManagedOAuth2`: Allows multiple auth instances to share tokens.
291+
- `RemoteOAuth2`: Allows use of the SDK on clients without access to your application's client secret. Instead, you
292+
provide a `retrieve_access_token` callback. That callback should perform the token refresh, perhaps on your server
293+
that does have access to the client secret.
294+
- `RedisManagedOAuth2`: Stores access and refresh tokens in Redis. This allows multiple processes (possibly spanning
295+
multiple machines) to share access tokens while synchronizing token refresh. This could be useful for a multiprocess
296+
web server, for example.
297+
298+
Other Network Options
299+
---------------------
300+
301+
For more insight into the network calls the SDK is making, you can use the `LoggingNetwork` class. This class logs
302+
information about network requests and responses made to the Box API.
303+
304+
.. code-block:: python
305+
306+
from boxsdk import Client
307+
from boxsdk.network.logging_network import LoggingNetwork
308+
309+
client = Client(oauth, network_layer=LoggingNetwork())
285310
286311
Contributing
287312
------------
@@ -312,7 +337,7 @@ Run all tests using -
312337
The tox tests include code style checks via pep8 and pylint.
313338

314339
The tox tests are configured to run on Python 2.6, 2.7, 3.3, 3.4, 3.5, and
315-
PyPy 2.6.
340+
PyPy (our CI is configured to run PyPy tests on PyPy 4.0).
316341

317342

318343
Support

boxsdk/__init__.py

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,6 @@
22

33
from __future__ import unicode_literals
44

5-
try:
6-
from .auth.jwt_auth import JWTAuth
7-
except ImportError:
8-
JWTAuth = None # If extras are not installed, JWTAuth won't be available.
9-
from .auth.oauth2 import OAuth2
10-
from .client import Client
5+
from .auth import JWTAuth, OAuth2
6+
from .client import Client, DeveloperTokenClient
117
from .object import * # pylint:disable=wildcard-import,redefined-builtin

boxsdk/auth/__init__.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,20 @@
11
# coding: utf-8
22

33
from __future__ import unicode_literals
4+
5+
from .cooperatively_managed_oauth2 import CooperativelyManagedOAuth2
6+
from .developer_token_auth import DeveloperTokenAuth
7+
try:
8+
from .jwt_auth import JWTAuth
9+
except ImportError:
10+
JWTAuth = None # If extras[jwt] are not installed, JWTAuth won't be available.
11+
from .oauth2 import OAuth2
12+
try:
13+
from .redis_managed_oauth2 import RedisManagedOAuth2
14+
except ImportError:
15+
RedisManagedOAuth2 = None # If extras[redis] are not installed, RedisManagedOAuth2 won't be available.
16+
try:
17+
from .redis_managed_jwt_auth import RedisManagedJWTAuth
18+
except ImportError:
19+
RedisManagedJWTAuth = None # If extras[jwt,redis] are not installed, RedisManagedJWTAuth won't be available.
20+
from .remote_managed_oauth2 import RemoteOAuth2
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# coding: utf-8
2+
3+
from __future__ import unicode_literals
4+
from .oauth2 import OAuth2
5+
6+
7+
class CooperativelyManagedOAuth2Mixin(OAuth2):
8+
"""
9+
Box SDK OAuth2 mixin.
10+
Allows for sharing auth tokens between multiple clients.
11+
"""
12+
def __init__(self, retrieve_tokens=None, *args, **kwargs):
13+
"""
14+
:param retrieve_tokens:
15+
Callback to get the current access/refresh token pair.
16+
:type retrieve_tokens:
17+
`callable` of () => (`unicode`, `unicode`)
18+
"""
19+
self._retrieve_tokens = retrieve_tokens
20+
super(CooperativelyManagedOAuth2Mixin, self).__init__(*args, **kwargs)
21+
22+
def _get_tokens(self):
23+
"""
24+
Base class override. Get the tokens from the user-specified callback.
25+
"""
26+
return self._retrieve_tokens()
27+
28+
29+
class CooperativelyManagedOAuth2(CooperativelyManagedOAuth2Mixin):
30+
"""
31+
Box SDK OAuth2 subclass.
32+
Allows for sharing auth tokens between multiple clients. The retrieve_tokens callback should
33+
return the current access/refresh token pair.
34+
"""
35+
pass
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# coding: utf-8
2+
3+
from __future__ import unicode_literals, absolute_import
4+
5+
from six.moves import input # pylint:disable=redefined-builtin
6+
7+
from .oauth2 import OAuth2
8+
9+
10+
class DeveloperTokenAuth(OAuth2):
11+
ENTER_TOKEN_PROMPT = 'Enter developer token: '
12+
13+
def __init__(self, get_new_token_callback=None, **kwargs):
14+
self._get_new_token = get_new_token_callback
15+
super(DeveloperTokenAuth, self).__init__(
16+
client_id=None,
17+
client_secret=None,
18+
access_token=self._refresh_developer_token(),
19+
**kwargs
20+
)
21+
22+
def _refresh_developer_token(self):
23+
if self._get_new_token is not None:
24+
return self._get_new_token()
25+
else:
26+
return input(self.ENTER_TOKEN_PROMPT)
27+
28+
def _refresh(self, access_token):
29+
"""
30+
Base class override.
31+
Ask for a new developer token.
32+
"""
33+
self._access_token = self._refresh_developer_token()
34+
return self._access_token, None

0 commit comments

Comments
 (0)