Skip to content

Commit

Permalink
Merge pull request #5 from lifeomic/LO-6006
Browse files Browse the repository at this point in the history
LO-6006: Upgrade to Python 3
  • Loading branch information
mjtieman committed Dec 31, 2019
2 parents 8399699 + 0c94c8f commit fcd1bf1
Show file tree
Hide file tree
Showing 14 changed files with 81 additions and 102 deletions.
4 changes: 2 additions & 2 deletions dev_requirements.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
boto3==1.6.4
botocore==1.9.4
boto3==1.10.45
botocore==1.13.45
tox>=2.3.1
16 changes: 8 additions & 8 deletions limiter/event_processors.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
#!/bin/bash/env python
import sys
import logging
import functools
from boto3.dynamodb.conditions import Key
from limiter.utils import validate_table_env_fallback
from limiter.clients import dynamodb
from limiter.managers import RESOURCE_COORDINATE, RESOURCE_ID, RESERVATION_ID

logger = logging.getLogger()

class ProcessorPredicate(object):
class ProcessorPredicate:
"""
Determines if an event matches a specific criteria.
Expand Down Expand Up @@ -89,7 +89,7 @@ def test(self, event):
break
return result

class EventProcessor(object):
class EventProcessor:
"""
Validates and extracts the resource id from events.
Expand Down Expand Up @@ -130,7 +130,7 @@ def test_and_get_id(self, event):
"""
return None if self.predicate and not self.predicate.test(event) else _reduce_to_path(event, self.id_path)

class EventProcessorManager(object):
class EventProcessorManager:
"""
Removes non-fungible tokens from DynamoDB represented by termination events.
Expand Down Expand Up @@ -222,7 +222,7 @@ def process_event(self, event):
}
)
else:
logger.warn('Could not find a token for resoure %s', resource_id)
logger.warning('Could not find a token for resoure %s', resource_id)
self.cache.append(resource_id)

def _get_processor(self, event):
Expand Down Expand Up @@ -287,11 +287,11 @@ def _reduce_to_path(obj, path):
str: If the path is valid, otherwise None.
"""
try:
if isinstance(path, basestring):
if isinstance(path, str):
path = path.split('.')
return reduce(lambda x, y: x[y], path, obj)
return functools.reduce(lambda x, y: x[y], path, obj)
except Exception:
sys.exc_clear()
pass
return None

def _build_processor_key(source, type=None):
Expand Down
3 changes: 0 additions & 3 deletions limiter/exceptions.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
class CapacityExhaustedException(Exception):
""" Raised when a token is requested but none are available. """
pass

class ReservationNotFoundException(Exception):
""" Raised when the query result for a non-fungible token reservation is empty. """
pass

class ThrottlingException(Exception):
""" Raised when the limiter is throttled by AWS. """
pass

class RateLimiterException(Exception):
""" Raised by a limiter on unrecoverable errors when fetching a token or account limits. """
4 changes: 2 additions & 2 deletions limiter/limiters.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from limiter.utils import validate_table_env_fallback
from limiter.managers import FungibleTokenManager, NonFungibleTokenManager

class BaseTokenLimiter(object):
class BaseTokenLimiter:
"""
Base class for both fungible and non-fungible token limiters.
Expand Down Expand Up @@ -228,7 +228,7 @@ def __enter__(self):

def __exit__(self, *args):
if any(args):
print str(args)
print(str(args))
self.reservation.delete()

def get_reservation(self):
Expand Down
2 changes: 1 addition & 1 deletion limiter/loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
SERVICE_NAME = 'serviceName'
CONFIG_VERSION = 'configVersion'

class LimitLoader(object):
class LimitLoader:
"""
Performs initial limit loading and updates for a specified service.
Expand Down
16 changes: 8 additions & 8 deletions limiter/managers.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
WINDOW_SEC = 'windowSec'
RESERVATION_ID = 'reservationId'

class BaseTokenManager(object):
class BaseTokenManager:
"""
Base class for both fungible and non-fungible token managers.
Expand Down Expand Up @@ -96,7 +96,7 @@ def _get_account_resource_limit(self, account_id):
except Exception as e:
if isinstance(e, ClientError):
error_code = e.response['Error']['Code']
if error_code == 'ProvisionedThroughputExceededException' or error_code == 'TooManyRequestsException':
if error_code in ('ProvisionedThroughputExceededException', 'TooManyRequestsException'):
message = 'Throttled getting limit on {} for account {}'.format(self.resource_name, account_id)
raise_from(ThrottlingException(message), e)
message = 'Failed to get limit on {} for account {}'.format(self.resource_name, account_id)
Expand Down Expand Up @@ -215,7 +215,7 @@ def _get_bucket_token(self, account_id, exec_time, ms_token):
if error_code == 'ConditionalCheckFailedException':
message = 'Resource capcity exhausted for {}:{}'.format(self.resource_name, account_id)
raise CapacityExhaustedException(message)
elif error_code == 'ProvisionedThroughputExceededException' or error_code == 'TooManyRequestsException':
if error_code in ('ProvisionedThroughputExceededException', 'TooManyRequestsException'):
message = 'Throttled by getting limit on {} for account {}'.format(self.resource_name, account_id)
raise_from(ThrottlingException(message), e)
raise
Expand Down Expand Up @@ -247,8 +247,8 @@ def _refill_bucket_tokens(self, account_id, tokens, refill_time):
)
except Exception as e:
if isinstance(e, ClientError) and e.response['Error']['Code'] == 'ConditionalCheckFailedException':
logger.warn('Failed to refill tokens for %s:%s, already refilled with more current state',
self.resource_name, account_id)
logger.warning('Failed to refill tokens for %s:%s, already refilled with more current state',
self.resource_name, account_id)
else:
logger.exception('Failed to refill tokens for %s:%s', self.resource_name, account_id)

Expand Down Expand Up @@ -357,7 +357,7 @@ def _buid_coordinate(self, account_id):
"""
return '{}:{}'.format(self.resource_name, account_id)

class TokenReservation(object):
class TokenReservation:
"""
Used to represent a temporary placeholder for, and create a non-fungible token, in DynamoDB.
Expand Down Expand Up @@ -430,11 +430,11 @@ def delete(self):
Delete the entry in DynamoDB representing this reservation.
"""
if self.is_token_created:
logger.warn('Cannot delete, a token has already been created from this reservation [%s]', self.id)
logger.warning('Cannot delete, a token has already been created from this reservation [%s]', self.id)
return

if self.is_deleted:
logger.warn('Cannot delete, this reservation [%s], has already been deleted', self.id)
logger.warning('Cannot delete, this reservation [%s], has already been deleted', self.id)
return

self.table.delete_item(
Expand Down
2 changes: 2 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
boto3==1.10.45
botocore==1.13.45
14 changes: 7 additions & 7 deletions setup.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
#!/usr/bin/env python
from setuptools import setup, find_packages

with open('./requirements.txt', 'r') as file:
requirements = file.read().splitlines()

setup(name='rate-limiter-py',
version='0.2.1',
version='0.3.0',
description='Rate-limiter module which leverages DynamoDB to enforce resource limits.',
keywords=['lifeomic', 'dynamodb', 'rate', 'limit'],
author='Matthew Tieman',
author_email='mjtieman55@gmail.com',
url='https://github.com/lifeomic/rate-limiter-py',
download_url='https://github.com/lifeomic/rate-limiter-py/archive/0.2.1.tar.gz',
download_url='https://github.com/lifeomic/rate-limiter-py/archive/0.3.0.tar.gz',
packages=find_packages(),
license='MIT',
install_requires=[
'boto3==1.6.4',
'botocore==1.9.4',
'future==0.16.0'
]
python_requires='>=3.6.0',
install_requires=requirements
)
38 changes: 19 additions & 19 deletions test/test_event_processors.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ def test_with_predicate(self):
processor = EventProcessor(source, 'detail.id', predicate=mock_predicate)
actual_id = processor.test_and_get_id(event)

self.assertEquals(expected_id, actual_id)
self.assertEqual(expected_id, actual_id)

def test_without_predicate(self):
source = random_string()
Expand All @@ -148,7 +148,7 @@ def test_without_predicate(self):
processor = EventProcessor(source, 'detail.id')
actual_id = processor.test_and_get_id(event)

self.assertEquals(expected_id, actual_id)
self.assertEqual(expected_id, actual_id)

def test_invalid_path(self):
source = random_string()
Expand Down Expand Up @@ -181,10 +181,10 @@ def test_processor_properties(self):
predicate = ProcessorPredicate('detail.state', lambda state: True)

processor = EventProcessor(source, id_path, predicate=predicate, type=type)
self.assertEquals(source, processor.source)
self.assertEquals(id_path, processor.id_path)
self.assertEquals(type, processor.type)
self.assertEquals(predicate, processor.predicate)
self.assertEqual(source, processor.source)
self.assertEqual(id_path, processor.id_path)
self.assertEqual(type, processor.type)
self.assertEqual(predicate, processor.predicate)

class EventProcessorManagerTest(TestCase):
def setUp(self):
Expand Down Expand Up @@ -229,7 +229,7 @@ def test_env_params(self):

with patch.dict('os.environ', env_vars):
manager = EventProcessorManager()
self.assertEquals(self.table_name, manager.table_name)
self.assertEqual(self.table_name, manager.table_name)

@mock_dynamodb2
def test_delete_token(self):
Expand All @@ -243,15 +243,15 @@ def test_delete_token(self):

mock_table = create_non_fung_table(self.table_name, self.index_name)
self._insert_token(mock_table)
self.assertEquals(1, self._get_resource_id_count(mock_table))
self.assertEqual(1, self._get_resource_id_count(mock_table))

manager = EventProcessorManager(table_name=self.table_name,
index_name=self.index_name,
processors=[mock_processor])
manager._table = mock_table
manager.process_event(event)

self.assertEquals(0, self._get_resource_id_count(mock_table))
self.assertEqual(0, self._get_resource_id_count(mock_table))

@mock_dynamodb2
def test_delete_no_token_for_id(self):
Expand All @@ -265,15 +265,15 @@ def test_delete_no_token_for_id(self):

mock_table = create_non_fung_table(self.table_name, self.index_name)
self._insert_token(mock_table)
self.assertEquals(1, self._get_resource_id_count(mock_table))
self.assertEqual(1, self._get_resource_id_count(mock_table))

manager = EventProcessorManager(table_name=self.table_name,
index_name=self.index_name,
processors=[mock_processor])
manager._table = mock_table
manager.process_event(event)

self.assertEquals(1, self._get_resource_id_count(mock_table))
self.assertEqual(1, self._get_resource_id_count(mock_table))

@mock_dynamodb2
def test_delete_no_id_from_processor(self):
Expand All @@ -287,15 +287,15 @@ def test_delete_no_id_from_processor(self):

mock_table = create_non_fung_table(self.table_name, self.index_name)
self._insert_token(mock_table)
self.assertEquals(1, self._get_resource_id_count(mock_table))
self.assertEqual(1, self._get_resource_id_count(mock_table))

manager = EventProcessorManager(table_name=self.table_name,
index_name=self.index_name,
processors=[mock_processor])
manager._table = mock_table
manager.process_event(event)

self.assertEquals(1, self._get_resource_id_count(mock_table))
self.assertEqual(1, self._get_resource_id_count(mock_table))

@mock_dynamodb2
def test_delete_on_type(self):
Expand All @@ -306,7 +306,7 @@ def test_delete_on_type(self):
mock_default_processor = Mock()
mock_default_processor.source = event_source
mock_default_processor.type = None
mock_default_processor.test_and_get_id = MagicMock(side_effect=StandardError('Wrong processor invoked'))
mock_default_processor.test_and_get_id = MagicMock(side_effect=Exception('Wrong processor invoked'))

mock_type_processor = Mock()
mock_type_processor.source = event_source
Expand All @@ -315,15 +315,15 @@ def test_delete_on_type(self):

mock_table = create_non_fung_table(self.table_name, self.index_name)
self._insert_token(mock_table)
self.assertEquals(1, self._get_resource_id_count(mock_table))
self.assertEqual(1, self._get_resource_id_count(mock_table))

manager = EventProcessorManager(table_name=self.table_name,
index_name=self.index_name,
processors=[mock_default_processor, mock_type_processor])
manager._table = mock_table
manager.process_event(event)

self.assertEquals(0, self._get_resource_id_count(mock_table))
self.assertEqual(0, self._get_resource_id_count(mock_table))

@mock_dynamodb2
def test_delete_fallback_no_type(self):
Expand All @@ -339,19 +339,19 @@ def test_delete_fallback_no_type(self):
mock_type_processor = Mock()
mock_type_processor.source = event_source
mock_type_processor.type = detail_type + random_string()
mock_type_processor.test_and_get_id = MagicMock(side_effect=StandardError('Wrong processor invoked'))
mock_type_processor.test_and_get_id = MagicMock(side_effect=Exception('Wrong processor invoked'))

mock_table = create_non_fung_table(self.table_name, self.index_name)
self._insert_token(mock_table)
self.assertEquals(1, self._get_resource_id_count(mock_table))
self.assertEqual(1, self._get_resource_id_count(mock_table))

manager = EventProcessorManager(table_name=self.table_name,
index_name=self.index_name,
processors=[mock_default_processor, mock_type_processor])
manager._table = mock_table
manager.process_event(event)

self.assertEquals(0, self._get_resource_id_count(mock_table))
self.assertEqual(0, self._get_resource_id_count(mock_table))

def _get_resource_id_count(self, mock_table):
response = mock_table.query(IndexName=self.index_name,
Expand Down
16 changes: 8 additions & 8 deletions test/test_limiters.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,9 @@ def test_manager_config_ctor_params(self):
self.limit_table_name)
manager = limiter.manager

self.assertEquals(self.token_table_name, manager.token_table_name)
self.assertEquals(self.limit_table_name, manager.limit_table_name)
self.assertEquals(self.resource_name, manager.resource_name)
self.assertEqual(self.token_table_name, manager.token_table_name)
self.assertEqual(self.limit_table_name, manager.limit_table_name)
self.assertEqual(self.resource_name, manager.resource_name)

def test_manager_config_env_params(self):
env_vars = {
Expand All @@ -87,9 +87,9 @@ def test_manager_config_env_params(self):
limiter = rate_limit(self.resource_name, self.limit, self.window)
manager = limiter.manager

self.assertEquals(self.token_table_name, manager.token_table_name)
self.assertEquals(self.limit_table_name, manager.limit_table_name)
self.assertEquals(self.resource_name, manager.resource_name)
self.assertEqual(self.token_table_name, manager.token_table_name)
self.assertEqual(self.limit_table_name, manager.limit_table_name)
self.assertEqual(self.resource_name, manager.resource_name)

@patch('limiter.limiters.FungibleTokenManager')
def test_decoratored_account_id_pos(self, mock_manager_delegate):
Expand Down Expand Up @@ -213,8 +213,8 @@ def test_delete_on_exception(self, mock_manager_delegate):
self.token_table_name,
self.limit_table_name) as reservation:
self.assertNotNone(reservation)
raise StandardError('Deliberately thrown from test_delete_on_exception')
except StandardError:
raise Exception('Deliberately thrown from test_delete_on_exception')
except Exception:
pass

mock_reservation.delete.assert_called()
Loading

0 comments on commit fcd1bf1

Please sign in to comment.