Skip to content
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

Handle file objects like file_upload #477

Merged
merged 3 commits into from
Sep 24, 2018
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
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ cache:
env:
global:
# If changing this number, please also change it in `tests/conftest.py`.
- STRIPE_MOCK_VERSION=0.30.0
- STRIPE_MOCK_VERSION=0.32.0

before_install:
# Unpack and start stripe-mock so that the test suite can talk to it
Expand Down
2 changes: 1 addition & 1 deletion stripe/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
client_id = None
api_base = 'https://api.stripe.com'
connect_api_base = 'https://connect.stripe.com'
upload_api_base = 'https://uploads.stripe.com'
upload_api_base = 'https://files.stripe.com'
api_version = None
verify_ssl_certs = True
proxy = None
Expand Down
3 changes: 2 additions & 1 deletion stripe/api_resources/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,9 @@
from stripe.api_resources.ephemeral_key import EphemeralKey
from stripe.api_resources.event import Event
from stripe.api_resources.exchange_rate import ExchangeRate
from stripe.api_resources.file import File
from stripe.api_resources.file import FileUpload
from stripe.api_resources.file_link import FileLink
from stripe.api_resources.file_upload import FileUpload
from stripe.api_resources.invoice import Invoice
from stripe.api_resources.invoice_item import InvoiceItem
from stripe.api_resources.invoice_line_item import InvoiceLineItem
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,13 @@
from stripe.api_resources.abstract import ListableAPIResource


class FileUpload(ListableAPIResource):
OBJECT_NAME = 'file_upload'

@classmethod
def api_base(cls):
return stripe.upload_api_base
class File(ListableAPIResource):
# This resource can have two different object names. In latter API
# versions, only `file` is used, but since stripe-python may be used with
# any API version, we need to support deserializing the older
# `file_upload` object into the same class.
OBJECT_NAME = 'file'
OBJECT_NAME_ALT = 'file_upload'

@classmethod
def class_url(cls):
Expand All @@ -20,7 +21,7 @@ def class_url(cls):
def create(cls, api_key=None, api_version=None, stripe_account=None,
**params):
requestor = api_requestor.APIRequestor(
api_key, api_base=cls.api_base(), api_version=api_version,
api_key, api_base=stripe.upload_api_base, api_version=api_version,
account=stripe_account)
url = cls.class_url()
supplied_headers = {
Expand All @@ -30,3 +31,7 @@ def create(cls, api_key=None, api_version=None, stripe_account=None,
'post', url, params=params, headers=supplied_headers)
return util.convert_to_stripe_object(response, api_key, api_version,
stripe_account)


# For backwards compatibility, the `File` class is aliased to `FileUpload`.
FileUpload = File
3 changes: 2 additions & 1 deletion stripe/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,8 +162,9 @@ def load_object_classes():
api_resources.EphemeralKey.OBJECT_NAME: api_resources.EphemeralKey,
api_resources.Event.OBJECT_NAME: api_resources.Event,
api_resources.ExchangeRate.OBJECT_NAME: api_resources.ExchangeRate,
api_resources.File.OBJECT_NAME: api_resources.File,
api_resources.File.OBJECT_NAME_ALT: api_resources.File,
api_resources.FileLink.OBJECT_NAME: api_resources.FileLink,
api_resources.FileUpload.OBJECT_NAME: api_resources.FileUpload,
api_resources.Invoice.OBJECT_NAME: api_resources.Invoice,
api_resources.InvoiceItem.OBJECT_NAME: api_resources.InvoiceItem,
api_resources.InvoiceLineItem.OBJECT_NAME:
Expand Down
2 changes: 1 addition & 1 deletion tests/api_resources/issuing/test_dispute.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ class TestDispute(object):
def test_is_creatable(self, request_mock):
resource = stripe.issuing.Dispute.create(
reason='fraudulent',
transaction='ipi_123'
disputed_transaction='ipi_123'
)
request_mock.assert_requested(
'post',
Expand Down
67 changes: 67 additions & 0 deletions tests/api_resources/test_file.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
from __future__ import absolute_import, division, print_function

import tempfile

import pytest

import stripe


TEST_RESOURCE_ID = 'file_123'


class TestFile(object):
@pytest.fixture(scope='function')
def setup_upload_api_base(self):
stripe.upload_api_base = stripe.api_base
stripe.api_base = None
yield
stripe.api_base = stripe.upload_api_base
stripe.upload_api_base = 'https://files.stripe.com'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not too familiar with the framework here, but are you sure this doesn't need to be in a finally to guarantee that these values are set back in case of an exception?

Copy link
Contributor Author

@ob-stripe ob-stripe Sep 24, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just tested it, and it's not necessary. The framework already catches exceptions in tests and reports them as errors, and still executes the post-yield code.


def test_is_listable(self, request_mock):
resources = stripe.File.list()
request_mock.assert_requested(
'get',
'/v1/files'
)
assert isinstance(resources.data, list)
assert isinstance(resources.data[0], stripe.File)

def test_is_retrievable(self, request_mock):
resource = stripe.File.retrieve(TEST_RESOURCE_ID)
request_mock.assert_requested(
'get',
'/v1/files/%s' % TEST_RESOURCE_ID
)
assert isinstance(resource, stripe.File)

def test_is_creatable(self, setup_upload_api_base, request_mock):
stripe.multipart_data_generator.MultipartDataGenerator\
._initialize_boundary = lambda self: 1234567890
test_file = tempfile.TemporaryFile()
resource = stripe.File.create(
purpose='dispute_evidence',
file=test_file
)
request_mock.assert_api_base(stripe.upload_api_base)
request_mock.assert_requested(
'post',
'/v1/files',
headers={
'Content-Type': 'multipart/form-data; boundary=1234567890',
}
)
assert isinstance(resource, stripe.File)

def test_deserializes_from_file(self):
obj = stripe.util.convert_to_stripe_object({
'object': 'file',
})
assert isinstance(obj, stripe.File)

def test_deserializes_from_file_upload(self):
obj = stripe.util.convert_to_stripe_object({
'object': 'file_upload',
})
assert isinstance(obj, stripe.File)
25 changes: 24 additions & 1 deletion tests/api_resources/test_file_upload.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,23 @@

import tempfile

import pytest

import stripe


TEST_RESOURCE_ID = 'file_123'


class TestFileUpload(object):
@pytest.fixture(scope='function')
def setup_upload_api_base(self):
stripe.upload_api_base = stripe.api_base
stripe.api_base = None
yield
stripe.api_base = stripe.upload_api_base
stripe.upload_api_base = 'https://files.stripe.com'

def test_is_listable(self, request_mock):
resources = stripe.FileUpload.list()
request_mock.assert_requested(
Expand All @@ -26,14 +36,15 @@ def test_is_retrievable(self, request_mock):
)
assert isinstance(resource, stripe.FileUpload)

def test_is_creatable(self, request_mock):
def test_is_creatable(self, setup_upload_api_base, request_mock):
stripe.multipart_data_generator.MultipartDataGenerator\
._initialize_boundary = lambda self: 1234567890
test_file = tempfile.TemporaryFile()
resource = stripe.FileUpload.create(
purpose='dispute_evidence',
file=test_file
)
request_mock.assert_api_base(stripe.upload_api_base)
request_mock.assert_requested(
'post',
'/v1/files',
Expand All @@ -42,3 +53,15 @@ def test_is_creatable(self, request_mock):
}
)
assert isinstance(resource, stripe.FileUpload)

def test_deserializes_from_file(self):
obj = stripe.util.convert_to_stripe_object({
'object': 'file',
})
assert isinstance(obj, stripe.FileUpload)

def test_deserializes_from_file_upload(self):
obj = stripe.util.convert_to_stripe_object({
'object': 'file_upload',
})
assert isinstance(obj, stripe.FileUpload)
5 changes: 1 addition & 4 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
from tests.request_mock import RequestMock


MOCK_MINIMUM_VERSION = '0.30.0'
MOCK_MINIMUM_VERSION = '0.32.0'
MOCK_PORT = os.environ.get('STRIPE_MOCK_PORT', 12111)


Expand Down Expand Up @@ -43,21 +43,18 @@ def setup_stripe():
'api_key': stripe.api_key,
'client_id': stripe.client_id,
'default_http_client': stripe.default_http_client,
'upload_api_base': stripe.upload_api_base,
}
http_client = stripe.http_client.new_default_http_client()
stripe.api_base = 'http://localhost:%s' % MOCK_PORT
stripe.api_key = 'sk_test_123'
stripe.client_id = 'ca_123'
stripe.default_http_client = http_client
stripe.upload_api_base = 'http://localhost:%s' % MOCK_PORT
yield
http_client.close()
stripe.api_base = orig_attrs['api_base']
stripe.api_key = orig_attrs['api_key']
stripe.client_id = orig_attrs['client_id']
stripe.default_http_client = orig_attrs['default_http_client']
stripe.upload_api_base = orig_attrs['upload_api_base']


@pytest.fixture
Expand Down
19 changes: 19 additions & 0 deletions tests/request_mock.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,25 @@ def stub_request(self, method, url, rbody={}, rcode=200, rheaders={}):
self._stub_request_handler.register(method, url, rbody, rcode,
rheaders)

def assert_api_base(self, expected_api_base):
# Note that this method only checks that an API base was provided
# as a keyword argument in APIRequestor's constructor, not as a
# positional argument.

if 'api_base' not in self.constructor_patcher.call_args[1]:
msg = ("Expected APIRequestor to have been constructed with "
"api_base='%s'. No API base was provided." %
expected_api_base)
raise AssertionError(msg)

actual_api_base = \
self.constructor_patcher.call_args[1]['api_base']
if actual_api_base != expected_api_base:
msg = ("Expected APIRequestor to have been constructed with "
"api_base='%s'. Constructed with api_base='%s' "
"instead." % (expected_api_base, actual_api_base))
raise AssertionError(msg)

def assert_api_version(self, expected_api_version):
# Note that this method only checks that an API version was provided
# as a keyword argument in APIRequestor's constructor, not as a
Expand Down