-
Notifications
You must be signed in to change notification settings - Fork 219
APICallWrapper.__get__ must return a bound method #218
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,4 +3,4 @@ | |
| from __future__ import unicode_literals, absolute_import | ||
|
|
||
|
|
||
| __version__ = '2.0.0a5' | ||
| __version__ = '2.0.0a6' | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,116 @@ | ||
| # coding: utf-8 | ||
|
|
||
| from __future__ import absolute_import, unicode_literals | ||
|
|
||
| from boxsdk.object.cloneable import Cloneable | ||
| from boxsdk.util.api_call_decorator import api_call | ||
| from mock import NonCallableMock | ||
| import pytest | ||
|
|
||
|
|
||
| @pytest.fixture | ||
| def api_call_result(): | ||
| return {'bar': 'ƒøø'} | ||
|
|
||
|
|
||
| @pytest.fixture(name='api_call_method') | ||
| def api_call_method_fixture(api_call_result): | ||
|
|
||
| @api_call | ||
| def api_call_method(self, *args, **kwargs): | ||
| return self, args, kwargs, api_call_result | ||
|
|
||
| return api_call_method | ||
|
|
||
|
|
||
| @pytest.fixture | ||
| def cloneable_subclass_with_api_call_method(api_call_method): | ||
| api_call_method_fixture = api_call_method | ||
|
|
||
| # pylint:disable=abstract-method | ||
| class CloneableSubclass(Cloneable): | ||
| api_call_method = api_call_method_fixture | ||
|
|
||
| return CloneableSubclass | ||
|
|
||
|
|
||
| @pytest.fixture | ||
| def mock_cloneable(cloneable_subclass_with_api_call_method): | ||
|
|
||
| # pylint:disable=abstract-method | ||
| class MockCloneable(cloneable_subclass_with_api_call_method, NonCallableMock): | ||
| pass | ||
|
|
||
| return MockCloneable(spec_set=cloneable_subclass_with_api_call_method, name='Cloneable') | ||
|
|
||
|
|
||
| def test_api_call_is_decorator(): | ||
|
|
||
| @api_call | ||
| def func(): | ||
| pass | ||
|
|
||
| assert callable(func) | ||
| assert hasattr(func, '__get__') | ||
|
|
||
|
|
||
| def test_api_call_decorated_function_must_be_a_method(): | ||
|
|
||
| @api_call | ||
| def func(): | ||
| pass | ||
|
|
||
| with pytest.raises(TypeError): | ||
| func() | ||
|
|
||
|
|
||
| def test_api_call_decorated_method_must_be_a_cloneable_method(): | ||
|
|
||
| class Cls(object): | ||
| @api_call | ||
| def func(self): | ||
| pass | ||
|
|
||
| obj = Cls() | ||
| with pytest.raises(TypeError): | ||
| obj.func() | ||
|
|
||
|
|
||
| def test_api_call_decorated_method_must_be_bound_to_an_instance_of_the_owner(mock_cloneable, api_call_method): | ||
| # pylint:disable=abstract-method | ||
| class CloneableSubclass2(Cloneable): | ||
| pass | ||
|
|
||
| with pytest.raises(TypeError): | ||
| api_call_method.__get__(mock_cloneable, CloneableSubclass2) | ||
|
|
||
|
|
||
| def test_api_call_decorated_method_returns_itself_when_bound_to_none(api_call_method, cloneable_subclass_with_api_call_method): | ||
| assert api_call_method.__get__(None, Cloneable) is api_call_method | ||
| assert not hasattr(api_call_method.__get__(None, Cloneable), '__self__') | ||
| assert cloneable_subclass_with_api_call_method.api_call_method is api_call_method | ||
| assert not hasattr(cloneable_subclass_with_api_call_method.api_call_method, '__self__') | ||
|
|
||
|
|
||
| def test_api_call_decorated_method_binds_to_instance(mock_cloneable, api_call_method): | ||
| assert api_call_method.__get__(mock_cloneable, Cloneable) is not api_call_method | ||
| assert api_call_method.__get__(mock_cloneable, Cloneable).__self__ is mock_cloneable | ||
| assert mock_cloneable.api_call_method is not api_call_method | ||
| assert mock_cloneable.api_call_method.__self__ is mock_cloneable | ||
|
|
||
|
|
||
| def test_api_call_decorated_method_delegates_to_wrapped_method(mock_cloneable, api_call_result): | ||
| args = (1, 2, 'ƒøø', 'bar') | ||
| kwargs = {'bar': 'ƒøø'} | ||
| assert mock_cloneable.api_call_method(*args, **kwargs) == (mock_cloneable, args, kwargs, api_call_result) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. you could take the
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would prefer to leave this as-is. If I do what you suggest, then we'll be passing through I could expose a fixture for the unbound method, but I'd rather not do that. I think it's fine as-is. |
||
|
|
||
|
|
||
| def test_api_call_decorated_method_can_be_called_as_an_unbound_method_with_an_instance_as_the_first_argument( | ||
| mock_cloneable, | ||
| api_call_result, | ||
| cloneable_subclass_with_api_call_method, | ||
| ): | ||
| args = (1, 2, 'ƒøø', 'bar') | ||
| kwargs = {'bar': 'ƒøø'} | ||
| api_call_method = cloneable_subclass_with_api_call_method.api_call_method | ||
| assert api_call_method(mock_cloneable, *args, **kwargs) == (mock_cloneable, args, kwargs, api_call_result) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ditto here |
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could call this
NonCloneableinstead ofClsThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.