Skip to content
This repository has been archived by the owner on Mar 20, 2018. It is now read-only.

Add support for Python 3 #120

Merged
merged 19 commits into from
Aug 5, 2016
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
8 changes: 6 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
sudo: false
env:
- BREW_HOME=$HOME/.linuxbrew
- BREW_HOME=$HOME/.linuxbrew PATH=$BREW_HOME/bin:$PATH

# Protobuf is very expensive to install, so we cache it between builds
before_install: ./install-protobuf3.sh
before_install:
- pip install --upgrade pip
- ./install-protobuf3.sh
cache:
directories:
- $BREW_HOME

language: python
python:
- "2.7"
- "3.4"
- "3.5"
install: pip install codecov tox-travis
script: tox
after_success:
Expand Down
12 changes: 10 additions & 2 deletions google/gax/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,10 @@ def __iter__(self):
return self

def next(self):
"""For Python 2.7 compatibility; see __next__."""
return self.__next__()

def __next__(self):
"""Retrieves the next page."""
if self._done:
raise StopIteration
Expand All @@ -456,18 +460,22 @@ def __init__(self, page_iterator):
Args:
page_iterator (PageIterator): the base iterator of getting pages.
"""
self._iterator = page_iterator
self._page_iterator = page_iterator
self._current = None
self._index = -1

def __iter__(self):
return self

def next(self):
"""For Python 2.7 compatibility; see __next__."""
return self.__next__()

def __next__(self):
"""Retrieves the next resource."""
# pylint: disable=next-method-called
while not self._current:
self._current = self._iterator.next()
self._current = next(self._page_iterator)
self._index = 0
resource = self._current[self._index]
self._index += 1
Expand Down
6 changes: 3 additions & 3 deletions google/gax/api_callable.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,10 @@

from __future__ import absolute_import, division
import random
import sys
import time

from future.utils import raise_with_traceback

from . import (BackoffSettings, BundleOptions, bundling, CallSettings, config,
PageIterator, ResourceIterator, RetryOptions)
from .errors import GaxError, RetryError
Expand Down Expand Up @@ -429,8 +430,7 @@ def inner(*args, **kwargs):
return a_func(*args, **kwargs)
# pylint: disable=catching-non-exception
except tuple(errors) as exception:
raise (GaxError('RPC failed', cause=exception), None,
sys.exc_info()[2])
raise_with_traceback(GaxError('RPC failed', cause=exception))

return inner

Expand Down
6 changes: 3 additions & 3 deletions google/gax/bundling.py
Original file line number Diff line number Diff line change
Expand Up @@ -179,8 +179,8 @@ def _run_with_subresponses(self, req, subresponse_field, kwargs):
in_sizes = [len(elts) for elts in self._in_deque]
all_subresponses = getattr(resp, subresponse_field)
if len(all_subresponses) != sum(in_sizes):
_LOG.warn(_WARN_DEMUX_MISMATCH, len(all_subresponses),
sum(in_sizes))
_LOG.warning(_WARN_DEMUX_MISMATCH, len(all_subresponses),
sum(in_sizes))
for event in self._event_deque:
event.result = resp
event.set()
Expand Down Expand Up @@ -251,7 +251,7 @@ def canceller():
return canceller


TIMER_FACTORY = threading.Timer
TIMER_FACTORY = threading.Timer # pylint: disable=invalid-name
Copy link
Contributor

Choose a reason for hiding this comment

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

does this mean something, or was it a debugging comment?

Copy link
Contributor

Choose a reason for hiding this comment

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

NVM, I just realized that this is an instruction to pylint

"""A class with an interface similar to threading.Timer.

Defaults to threading.Timer. This makes it easy to plug-in alternate
Expand Down
3 changes: 2 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
grpcio>=0.15.0
future>=0.15.2
grpcio>=1.0rc1
oauth2client>=1.5.2
ply==3.8
protobuf>=3.0.0b3
3 changes: 2 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@
raise RuntimeError("No version number found!")

install_requires = [
'grpcio>=0.15.0',
'future>=0.15.2',
'grpcio>=1.0rc1',
Copy link
Contributor

Choose a reason for hiding this comment

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

Is future needed here, too?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good catch. Fixed.

'ply==3.8',
'protobuf>=3.0.0b3',
'oauth2client>=1.5.2',
Expand Down
27 changes: 13 additions & 14 deletions test/test_api_callable.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,9 +131,9 @@ def test_call_kwargs(self):
settings = CallSettings(kwargs={'key': 'value'})
my_callable = api_callable.create_api_call(
lambda _req, _timeout, **kwargs: kwargs['key'], settings)
self.assertEquals(my_callable(None), 'value')
self.assertEquals(my_callable(None, CallOptions(key='updated')),
'updated')
self.assertEqual(my_callable(None), 'value')
self.assertEqual(my_callable(None, CallOptions(key='updated')),
'updated')

@mock.patch('time.time')
@mock.patch('google.gax.config.exc_to_code')
Expand Down Expand Up @@ -313,8 +313,7 @@ def grpc_return_value(request, *dummy_args, **dummy_kwargs):
return PageStreamingResponse(nums=list(range(page_size)),
next_page_token=page_size)

with mock.patch('grpc.framework.crust.implementations.'
'_UnaryUnaryMultiCallable') as mock_grpc:
with mock.patch('grpc.UnaryUnaryMultiCallable') as mock_grpc:
mock_grpc.side_effect = grpc_return_value
settings = CallSettings(
page_descriptor=fake_grpc_func_descriptor, timeout=0)
Expand Down Expand Up @@ -371,7 +370,7 @@ def my_func(request, dummy_timeout):
self.assertIsInstance(first, bundling.Event)
self.assertIsNone(first.result) # pylint: disable=no-member
second = my_callable(BundlingRequest([0] * 5))
self.assertEquals(second.result, 8) # pylint: disable=no-member
self.assertEqual(second.result, 8) # pylint: disable=no-member

def test_construct_settings(self):
defaults = api_callable.construct_settings(
Expand All @@ -385,14 +384,14 @@ def test_construct_settings(self):
self.assertIsInstance(settings.bundle_descriptor, BundleDescriptor)
self.assertIsNone(settings.page_descriptor)
self.assertIsInstance(settings.retry, RetryOptions)
self.assertEquals(settings.kwargs, {'key1': 'value1'})
self.assertEqual(settings.kwargs, {'key1': 'value1'})
settings = defaults['page_streaming_method']
self.assertAlmostEqual(settings.timeout, 12.0)
self.assertIsNone(settings.bundler)
self.assertIsNone(settings.bundle_descriptor)
self.assertIsInstance(settings.page_descriptor, PageDescriptor)
self.assertIsInstance(settings.retry, RetryOptions)
self.assertEquals(settings.kwargs, {'key1': 'value1'})
self.assertEqual(settings.kwargs, {'key1': 'value1'})

def test_construct_settings_override(self):
_override = {
Expand Down Expand Up @@ -455,8 +454,8 @@ def test_construct_settings_override2(self):
page_descriptors=_PAGE_DESCRIPTORS)
settings = defaults['bundling_method']
backoff = settings.retry.backoff_settings
self.assertEquals(backoff.initial_retry_delay_millis, 1000)
self.assertEquals(settings.retry.retry_codes, [_RETRY_DICT['code_a']])
self.assertEqual(backoff.initial_retry_delay_millis, 1000)
self.assertEqual(settings.retry.retry_codes, [_RETRY_DICT['code_a']])
self.assertIsInstance(settings.bundler, bundling.Executor)
self.assertIsInstance(settings.bundle_descriptor, BundleDescriptor)

Expand All @@ -465,10 +464,10 @@ def test_construct_settings_override2(self):
# not affect the methods which are not in the overrides.
settings = defaults['page_streaming_method']
backoff = settings.retry.backoff_settings
self.assertEquals(backoff.initial_retry_delay_millis, 100)
self.assertEquals(backoff.retry_delay_multiplier, 1.2)
self.assertEquals(backoff.max_retry_delay_millis, 1000)
self.assertEquals(settings.retry.retry_codes, [_RETRY_DICT['code_c']])
self.assertEqual(backoff.initial_retry_delay_millis, 100)
self.assertEqual(backoff.retry_delay_multiplier, 1.2)
self.assertEqual(backoff.max_retry_delay_millis, 1000)
self.assertEqual(settings.retry.retry_codes, [_RETRY_DICT['code_c']])

@mock.patch('google.gax.config.API_ERRORS', (CustomException, ))
def test_catch_error(self):
Expand Down
56 changes: 28 additions & 28 deletions test/test_bundling.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ def test_computes_bundle_ids_ok(self):
for t in tests:
got = bundling.compute_bundle_id(t['object'], t['fields'])
message = 'failed while making an id for {}'.format(t['message'])
self.assertEquals(got, t['want'], message)
self.assertEqual(got, t['want'], message)

def test_should_raise_if_fields_are_missing(self):
tests = [
Expand Down Expand Up @@ -169,7 +169,7 @@ def test_extend_increases_the_element_count(self):
t['update'](test_task)
got = test_task.element_count
message = 'bad message count when {}'.format(t['message'])
self.assertEquals(got, t['want'], message)
self.assertEqual(got, t['want'], message)

def test_extend_increases_the_request_byte_count(self):
simple_msg = 'a simple msg'
Expand All @@ -193,7 +193,7 @@ def test_extend_increases_the_request_byte_count(self):
t['update'](test_task)
got = test_task.request_bytesize
message = 'bad message count when {}'.format(t['message'])
self.assertEquals(got, t['want'], message)
self.assertEqual(got, t['want'], message)

def test_run_sends_the_bundle_elements(self):
simple_msg = 'a simple msg'
Expand Down Expand Up @@ -221,26 +221,26 @@ def test_run_sends_the_bundle_elements(self):
for t in tests:
test_task = _make_a_test_task()
event = t['update'](test_task)
self.assertEquals(test_task.element_count, t['count_before_run'])
self.assertEqual(test_task.element_count, t['count_before_run'])
test_task.run()
self.assertEquals(test_task.element_count, 0)
self.assertEquals(test_task.request_bytesize, 0)
self.assertEqual(test_task.element_count, 0)
self.assertEqual(test_task.request_bytesize, 0)
if t['has_event']:
self.assertIsNotNone(
event,
'expected event for {}'.format(t['message']))
got = event.result
message = 'bad output when run with {}'.format(t['message'])
self.assertEquals(got, t['want'], message)
self.assertEqual(got, t['want'], message)

def test_run_adds_an_error_if_execution_fails(self):
simple_msg = 'a simple msg'
test_task = _make_a_test_task(api_call=_raise_exc)
event = test_task.extend([simple_msg])
self.assertEquals(test_task.element_count, 1)
self.assertEqual(test_task.element_count, 1)
test_task.run()
self.assertEquals(test_task.element_count, 0)
self.assertEquals(test_task.request_bytesize, 0)
self.assertEqual(test_task.element_count, 0)
self.assertEqual(test_task.request_bytesize, 0)
self.assertTrue(isinstance(event.result, ValueError))

def test_calling_the_canceller_stops_the_element_from_getting_sent(self):
Expand All @@ -249,14 +249,14 @@ def test_calling_the_canceller_stops_the_element_from_getting_sent(self):
test_task = _make_a_test_task()
an_event = test_task.extend([an_elt])
another_event = test_task.extend([another_msg])
self.assertEquals(test_task.element_count, 2)
self.assertEqual(test_task.element_count, 2)
self.assertTrue(an_event.cancel())
self.assertEquals(test_task.element_count, 1)
self.assertEqual(test_task.element_count, 1)
self.assertFalse(an_event.cancel())
self.assertEquals(test_task.element_count, 1)
self.assertEqual(test_task.element_count, 1)
test_task.run()
self.assertEquals(test_task.element_count, 0)
self.assertEquals(_Bundled([another_msg]), another_event.result)
self.assertEqual(test_task.element_count, 0)
self.assertEqual(_Bundled([another_msg]), another_event.result)
self.assertFalse(an_event.is_set())
self.assertIsNone(an_event.result)

Expand Down Expand Up @@ -301,8 +301,8 @@ def test_api_calls_are_grouped_by_bundle_id(self):
self.assertTrue(
got_event.is_set(),
'event is not set after triggering element')
self.assertEquals(_Bundled([an_elt] * threshold),
got_event.result)
self.assertEqual(_Bundled([an_elt] * threshold),
got_event.result)

def test_each_event_has_exception_when_demuxed_api_call_fails(self):
an_elt = 'dummy message'
Expand Down Expand Up @@ -366,8 +366,8 @@ def test_each_event_has_its_result_from_a_demuxed_api_call(self):
self.assertTrue(previous_event != event)
self.assertTrue(event.is_set(),
'event is not set after triggering element')
self.assertEquals(event.result,
_Bundled(['%s%d' % (an_elt, index)] * index))
self.assertEqual(event.result,
_Bundled(['%s%d' % (an_elt, index)] * index))
previous_event = event

def test_each_event_has_same_result_from_mismatched_demuxed_api_call(self):
Expand All @@ -394,7 +394,7 @@ def test_each_event_has_same_result_from_mismatched_demuxed_api_call(self):
self.assertTrue(previous_event != event)
self.assertTrue(event.is_set(),
'event is not set after triggering element')
self.assertEquals(event.result, mismatched_result)
self.assertEqual(event.result, mismatched_result)
previous_event = event

def test_schedule_passes_kwargs(self):
Expand All @@ -409,8 +409,8 @@ def test_schedule_passes_kwargs(self):
_Bundled([an_elt]),
{'an_option': 'a_value'}
)
self.assertEquals('a_value',
event.result['an_option'])
self.assertEqual('a_value',
event.result['an_option'])


class TestExecutor_ElementCountTrigger(unittest2.TestCase):
Expand All @@ -437,8 +437,8 @@ def test_api_call_not_invoked_until_threshold(self):
self.assertIsNone(got_event.result)
else:
self.assertTrue(got_event.is_set())
self.assertEquals(_Bundled([an_elt] * threshold),
got_event.result)
self.assertEqual(_Bundled([an_elt] * threshold),
got_event.result)


class TestExecutor_RequestByteTrigger(unittest2.TestCase):
Expand Down Expand Up @@ -466,8 +466,8 @@ def test_api_call_not_invoked_until_threshold(self):
self.assertIsNone(got_event.result)
else:
self.assertTrue(got_event.is_set())
self.assertEquals(_Bundled([an_elt] * elts_for_threshold),
got_event.result)
self.assertEqual(_Bundled([an_elt] * elts_for_threshold),
got_event.result)


class TestExecutor_DelayThreshold(unittest2.TestCase):
Expand All @@ -490,8 +490,8 @@ def test_api_call_is_scheduled_on_timer(self, timer_class):
self.assertIsNone(got_event.result)
self.assertTrue(timer_class.called)
timer_args, timer_kwargs = timer_class.call_args_list[0]
self.assertEquals(delay_threshold, timer_args[0])
self.assertEquals({'args': [an_id]}, timer_kwargs)
self.assertEqual(delay_threshold, timer_args[0])
self.assertEqual({'args': [an_id]}, timer_kwargs)
timer_class.return_value.start.assert_called_once_with()


Expand Down
6 changes: 3 additions & 3 deletions test/test_grpc.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ def test_creates_a_stub_ok_with_no_scopes(
chan.assert_called_once_with(self.FAKE_SERVICE_PATH, self.FAKE_PORT,
comp.return_value)
auth.assert_called_once_with([])
self.assertEquals(got_channel, chan.return_value)
self.assertEqual(got_channel, chan.return_value)

@mock.patch('grpc.beta.implementations.composite_channel_credentials')
@mock.patch('grpc.beta.implementations.ssl_channel_credentials')
Expand Down Expand Up @@ -86,7 +86,7 @@ def test_creates_a_stub_with_given_channel(
got_channel = grpc.create_stub(
_fake_create_stub, self.FAKE_SERVICE_PATH, self.FAKE_PORT,
channel=fake_channel)
self.assertEquals(got_channel, fake_channel)
self.assertEqual(got_channel, fake_channel)
self.assertFalse(auth.called)
self.assertFalse(chan_creds.called)
self.assertFalse(chan.called)
Expand All @@ -111,7 +111,7 @@ def test_creates_a_stub_ok_with_given_creds(self, auth, chan, chan_creds,
self.assertFalse(chan_creds.called)
self.assertTrue(comp.called)
self.assertTrue(md.called)
self.assertEquals(got_channel, chan.return_value)
self.assertEqual(got_channel, chan.return_value)

@mock.patch('grpc.beta.implementations.composite_channel_credentials')
@mock.patch('grpc.beta.implementations.ssl_channel_credentials')
Expand Down
Loading