diff --git a/.travis.yml b/.travis.yml index 2fdda0e..f7b94ae 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,4 +11,7 @@ install: - "pip install ." - "pip install six" - "pip install mock" -script: nosetests tests/ + - "pip install pep8" +script: + - nosetests tests/ + - pep8 --max-line-length=120 diff --git a/librato/__init__.py b/librato/__init__.py index 2c9c583..1aea95e 100644 --- a/librato/__init__.py +++ b/librato/__init__.py @@ -20,16 +20,9 @@ # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + import re import six - -__version__ = "1.0.7" - -# Defaults -HOSTNAME = "metrics-api.librato.com" -BASE_PATH = "/v1/" -DEFAULT_TIMEOUT = 10 - import platform import time import logging @@ -49,6 +42,13 @@ from librato.annotations import Annotation from librato.spaces import Space, Chart +__version__ = "1.0.7" + +# Defaults +HOSTNAME = "metrics-api.librato.com" +BASE_PATH = "/v1/" +DEFAULT_TIMEOUT = 10 + log = logging.getLogger("librato") # Alias HTTPSConnection so the tests can mock it out. @@ -83,8 +83,8 @@ class LibratoConnection(object): [...] """ - def __init__(self, username, api_key, hostname=HOSTNAME, base_path=BASE_PATH, sanitizer=sanitize_no_op, protocol="https", - tags={}): + def __init__(self, username, api_key, hostname=HOSTNAME, base_path=BASE_PATH, sanitizer=sanitize_no_op, + protocol="https", tags={}): """Create a new connection to Librato Metrics. Doesn't actually connect yet or validate until you make a request. @@ -108,7 +108,7 @@ def __init__(self, username, api_key, hostname=HOSTNAME, base_path=BASE_PATH, sa # these two attributes ared used to control fake server errors when doing # unit testing. self.fake_n_errors = 0 - self.backoff_logic = lambda backoff: backoff*2 + self.backoff_logic = lambda backoff: backoff * 2 self.sanitize = sanitizer self.timeout = DEFAULT_TIMEOUT self.tags = dict(tags) @@ -133,9 +133,9 @@ def _url_encode_params(self, params={}): if not isinstance(params, dict): raise Exception("You must pass in a dictionary!") params_list = [] - for k,v in params.items(): + for k, v in params.items(): if isinstance(v, list): - params_list.extend([(k+'[]', x) for x in v]) + params_list.extend([(k + '[]', x) for x in v]) else: params_list.append((k, v)) return urlencode(params_list) @@ -179,7 +179,7 @@ def _mexe(self, path, method="GET", query_props=None, p_headers=None): """Internal method for executing a command. If we get server errors we exponentially wait before retrying """ - conn = self._setup_connection() + conn = self._setup_connection() headers = self._set_headers(p_headers) success = False backoff = 1 @@ -255,7 +255,7 @@ def submit(self, name, value, type="gauge", **query_props): metric[k] = v payload[type + 's'].append(metric) self._mexe("metrics", method="POST", query_props=payload) - + def submit_tagged(self, name, value, **query_props): payload = {'measurements': []} if self.tags: @@ -391,7 +391,7 @@ def get_annotation_stream(self, name, **query_props): def get_annotation(self, name, id, **query_props): """Get a specific annotation event by ID""" - resp = self._mexe("annotations/%s/%s" % (name,id), method="GET", query_props=query_props) + resp = self._mexe("annotations/%s/%s" % (name, id), method="GET", query_props=query_props) return Annotation.from_dict(self, resp) def update_annotation_stream(self, name, **query_props): @@ -403,8 +403,8 @@ def update_annotation_stream(self, name, **query_props): return Annotation.from_dict(self, resp) def post_annotation(self, name, **query_props): - """Create an annotation event on :name. - If the annotation stream does not exist, it will be created automatically.""" + """ Create an annotation event on :name. """ + """ If the annotation stream does not exist, it will be created automatically. """ resp = self._mexe("annotations/%s" % name, method="POST", query_props=query_props) return resp @@ -518,7 +518,6 @@ def delete_space(self, id): resp = self._mexe("spaces/%s" % id, method="DELETE") return resp - # # Charts # @@ -572,8 +571,8 @@ def update_chart(self, chart, space, **query_props): for k, v in query_props.items(): payload[k] = v resp = self._mexe("spaces/%s/charts/%s" % (space.id, chart.id), - method="PUT", - query_props=payload) + method="PUT", + query_props=payload) return resp def delete_chart(self, chart_id, space_id, **query_props): @@ -581,7 +580,6 @@ def delete_chart(self, chart_id, space_id, **query_props): resp = self._mexe("spaces/%s/charts/%s" % (space_id, chart_id), method="DELETE") return resp - # # Queue # @@ -600,7 +598,9 @@ def new_queue(self, **kwargs): def set_timeout(self, timeout): self.timeout = timeout -def connect(username, api_key, hostname=HOSTNAME, base_path=BASE_PATH, sanitizer=sanitize_no_op, protocol="https", tags={}): + +def connect(username, api_key, hostname=HOSTNAME, base_path=BASE_PATH, sanitizer=sanitize_no_op, + protocol="https", tags={}): """ Connect to Librato Metrics """ @@ -626,6 +626,7 @@ def _decode_body(resp): return resp_data + def _getcharset(resp, default='utf-8'): """ Extract the charset from an HTTPResponse. @@ -640,6 +641,7 @@ def _getcharset(resp, default='utf-8'): m['content-type'] = resp.getheader('content-type') return m.get_content_charset(default) + def _get_content_type(resp): """ Get Content-Type header ignoring parameters diff --git a/librato/aggregator.py b/librato/aggregator.py index 183cfff..949e117 100644 --- a/librato/aggregator.py +++ b/librato/aggregator.py @@ -44,22 +44,18 @@ def __init__(self, connection, **args): self.period = args.get('period') self.measure_time = args.get('measure_time') - # Get a shallow copy of the top-level tag set def get_tags(self): return dict(self.tags) - # Define the top-level tag set for posting measurements def set_tags(self, d): self.tags = dict(d) # Create a copy - # Add one or more top-level tags for posting measurements def add_tags(self, d): self.tags.update(d) - def add(self, name, value): if name not in self.measurements: self.measurements[name] = { @@ -67,7 +63,7 @@ def add(self, name, value): 'sum': value, 'min': value, 'max': value - } + } else: m = self.measurements[name] m['sum'] += value @@ -79,7 +75,6 @@ def add(self, name, value): return self.measurements - def add_tagged(self, name, value): if name not in self.tagged_measurements: self.tagged_measurements[name] = { @@ -87,7 +82,7 @@ def add_tagged(self, name, value): 'sum': value, 'min': value, 'max': value - } + } else: m = self.tagged_measurements[name] m['sum'] += value @@ -99,7 +94,6 @@ def add_tagged(self, name, value): return self.tagged_measurements - def to_payload(self): # Map measurements into Librato POST (array) format # { @@ -130,7 +124,6 @@ def to_payload(self): return result - def to_md_payload(self): # Map measurements into Librato MD POST format # { @@ -158,7 +151,6 @@ def to_md_payload(self): return result - # Get/set the measure time if it is ever queried, that way you'll know the measure_time # that was submitted, and we'll guarantee the same measure_time for all measurements # extracted into a queue @@ -168,7 +160,6 @@ def get_measure_time(self): self.measure_time = mt return self.measure_time - # Return floored measure time if period is set # otherwise return user specified value if set # otherwise return none @@ -186,13 +177,11 @@ def floor_measure_time(self): # Use the user-specified value with no flooring return self.measure_time - def clear(self): self.measurements = {} self.tagged_measurements = {} self.measure_time = None - def submit(self): # Submit any legacy or tagged measurements to API # This will actually return an empty 200 response (no body) diff --git a/librato/alerts.py b/librato/alerts.py index a3df5e9..00b30fc 100644 --- a/librato/alerts.py +++ b/librato/alerts.py @@ -2,7 +2,7 @@ class Alert(object): """Librato Alert Base class""" def __init__(self, connection, name, _id=None, description=None, version=2, - conditions=[], services=[], attributes={}, active=True, rearm_seconds=None): + conditions=[], services=[], attributes={}, active=True, rearm_seconds=None): self.connection = connection self.name = name self.description = description @@ -67,6 +67,7 @@ def get_payload(self): def save(self): self.connection.update_alert(self) + class Condition(object): ABOVE = 'above' BELOW = 'below' @@ -129,8 +130,8 @@ def from_dict(cls, data): def get_payload(self): obj = {'condition_type': self.condition_type, - 'metric_name': self.metric_name, - 'source': self.source} + 'metric_name': self.metric_name, + 'source': self.source} if self.condition_type in [self.ABOVE, self.BELOW]: obj['threshold'] = self.threshold obj['summary_function'] = self.summary_function @@ -140,6 +141,7 @@ def get_payload(self): obj['duration'] = self._duration return obj + class Service(object): def __init__(self, _id, title=None, type=None, settings=None): self._id = _id diff --git a/librato/annotations.py b/librato/annotations.py index 86fdb08..1500db5 100644 --- a/librato/annotations.py +++ b/librato/annotations.py @@ -27,7 +27,7 @@ class Annotation(object): """Librato Annotation Stream Base class""" - def __init__(self, connection, name, display_name=None ): + def __init__(self, connection, name, display_name=None): self.connection = connection self.name = name self.display_name = display_name @@ -44,5 +44,5 @@ def from_dict(cls, connection, data): obj.query = data['query'] if 'query' in data else {} return obj - def get_payload(self): - return {'name': self.name,'display_name': self.display_name} + def get_payload(self): + return {'name': self.name, 'display_name': self.display_name} diff --git a/librato/exceptions.py b/librato/exceptions.py index b741580..f1e22e8 100644 --- a/librato/exceptions.py +++ b/librato/exceptions.py @@ -146,6 +146,7 @@ def __init__(self, msg=None): 404: NotFound } + # http://dev.librato.com/v1/responses-errors def get(code, resp_data): if code in CODES: diff --git a/librato/instruments.py b/librato/instruments.py index daf7698..e562d06 100644 --- a/librato/instruments.py +++ b/librato/instruments.py @@ -1,5 +1,6 @@ from librato.streams import Stream + class Instrument(object): """Librato Instrument Base class""" @@ -47,9 +48,9 @@ def is_persisted(self): def save(self): if not self.is_persisted(): dummy_inst = self.connection.create_instrument( - self.name, - attributes=self.attributes, - streams=self.streams_payload()) + self.name, + attributes=self.attributes, + streams=self.streams_payload()) self.id = dummy_inst.id else: self.connection.update_instrument(self) diff --git a/librato/metrics.py b/librato/metrics.py index 15425a4..c1ad3bd 100644 --- a/librato/metrics.py +++ b/librato/metrics.py @@ -27,7 +27,7 @@ class Metric(object): """Librato Metric Base class""" - def __init__(self, connection, name, attributes=None, period=None, description=None ): + def __init__(self, connection, name, attributes=None, period=None, description=None): self.connection = connection self.name = name self.attributes = attributes or {} @@ -88,4 +88,3 @@ def add(self, value, source=None, **params): def what_am_i(self): return 'counters' - diff --git a/librato/queue.py b/librato/queue.py index 573e568..8a99b5e 100644 --- a/librato/queue.py +++ b/librato/queue.py @@ -154,7 +154,8 @@ def _add_measurement(self, type, nm): self.chunks[-1][type + 's'].append(nm) def _add_tagged_measurement(self, nm): - if not self.tagged_chunks or self._num_measurements_in_current_chunk(tagged=True) == self.MAX_MEASUREMENTS_PER_CHUNK: + if (not self.tagged_chunks or + self._num_measurements_in_current_chunk(tagged=True) == self.MAX_MEASUREMENTS_PER_CHUNK): self.tagged_chunks.append({'measurements': []}) self.tagged_chunks[-1]['measurements'].append(nm) @@ -183,5 +184,5 @@ def _num_measurements_in_queue(self): num += self._num_measurements_in_current_chunk() + self.MAX_MEASUREMENTS_PER_CHUNK * (len(self.chunks) - 1) if self.tagged_chunks: num += (self._num_measurements_in_current_chunk(tagged=True) + - self.MAX_MEASUREMENTS_PER_CHUNK * (len(self.tagged_chunks) - 1)) + self.MAX_MEASUREMENTS_PER_CHUNK * (len(self.tagged_chunks) - 1)) return num diff --git a/librato/spaces.py b/librato/spaces.py index 7e406f7..b75418a 100644 --- a/librato/spaces.py +++ b/librato/spaces.py @@ -75,9 +75,9 @@ def add_bignumber_chart(self, name, metric, source='*', 'summary_function': summary_function } chart = self.add_chart(name, - type='bignumber', - use_last_value=use_last_value, - streams=[stream]) + type='bignumber', + use_last_value=use_last_value, + streams=[stream]) return chart # This currently only updates the name of the Space @@ -177,7 +177,7 @@ def space(self): def known_attributes(self): return ['min', 'max', 'label', 'use_log_yaxis', 'use_last_value', - 'related_space'] + 'related_space'] def get_payload(self): # Set up the things that we aren't considering just "attributes" diff --git a/librato/streams.py b/librato/streams.py index 08b63d1..4bb4a42 100644 --- a/librato/streams.py +++ b/librato/streams.py @@ -45,9 +45,8 @@ def __init__(self, metric=None, source='*', composite=None, def _attrs(self): return ['metric', 'source', 'composite', 'name', - 'type', 'id', 'group_function', 'summary_function', 'transform_function', 'downsample_function', - 'period', 'split_axis', 'min', 'max', 'units_short', 'units_long'] - + 'type', 'id', 'group_function', 'summary_function', 'transform_function', 'downsample_function', + 'period', 'split_axis', 'min', 'max', 'units_short', 'units_long'] def get_payload(self): payload = {} diff --git a/setup.py b/setup.py index cfd5b8b..d1053bd 100644 --- a/setup.py +++ b/setup.py @@ -5,32 +5,32 @@ from setuptools import setup if sys.argv[-1] == 'publish': - os.system('python setup.py sdist upload') - sys.exit() + os.system('python setup.py sdist upload') + sys.exit() setup( - name = "librato-metrics", - version = "1.0.7", # Update also in __init__ ; look into zest.releaser to avoid having two versions - description = "Python API Wrapper for Librato", - long_description="Python Wrapper for the Librato Metrics API: http://dev.librato.com/v1/metrics", - author = "Librato", - author_email = "support@librato.com", - url = 'http://github.com/librato/python-librato', - license = 'https://github.com/librato/python-librato/blob/master/LICENSE', - packages= ['librato'], - package_data={'': ['LICENSE', 'README.md', 'CHANGELOG.md']}, - package_dir={'librato': 'librato'}, - include_package_data=True, - platforms = 'Posix; MacOS X; Windows', - classifiers = [ - 'Development Status :: 3 - Alpha', - 'Intended Audience :: Developers', - 'License :: OSI Approved :: MIT License', - 'Operating System :: OS Independent', - 'Topic :: Internet', - 'Programming Language :: Python', - 'Programming Language :: Python :: 3', - ], - dependency_links = [], - install_requires = ['six'], + name="librato-metrics", + version="1.0.7", # Update also in __init__ ; look into zest.releaser to avoid having two versions + description="Python API Wrapper for Librato", + long_description="Python Wrapper for the Librato Metrics API: http://dev.librato.com/v1/metrics", + author="Librato", + author_email="support@librato.com", + url='http://github.com/librato/python-librato', + license='https://github.com/librato/python-librato/blob/master/LICENSE', + packages=['librato'], + package_data={'': ['LICENSE', 'README.md', 'CHANGELOG.md']}, + package_dir={'librato': 'librato'}, + include_package_data=True, + platforms='Posix; MacOS X; Windows', + classifiers=[ + 'Development Status :: 3 - Alpha', + 'Intended Audience :: Developers', + 'License :: OSI Approved :: MIT License', + 'Operating System :: OS Independent', + 'Topic :: Internet', + 'Programming Language :: Python', + 'Programming Language :: Python :: 3', + ], + dependency_links=[], + install_requires=['six'], ) diff --git a/tests/integration.py b/tests/integration.py index 307ebb2..a0bdfc8 100644 --- a/tests/integration.py +++ b/tests/integration.py @@ -30,6 +30,7 @@ import time logging.basicConfig(level=logging.INFO) + class TestLibratoBase(unittest.TestCase): @classmethod def setUpClass(cls): @@ -75,7 +76,7 @@ def _delete_and_verify_metric(self, names, connection=None): assert(metric is None) def test_long_sanitized_metric(self): - name, desc = 'a'*256, 'Too long, will error' + name, desc = 'a' * 256, 'Too long, will error' with self.assertRaises(BadRequest): self._add_and_verify_metric(name, 10, desc, self.conn) self._add_and_verify_metric(name, 10, desc, self.conn_sanitize) @@ -118,20 +119,20 @@ def test_send_batch_gauge_measurements(self): q.submit() for t in range(1, 10): - q.add('temperature', randint(20, 40), measure_time=time.time()+t) + q.add('temperature', randint(20, 40), measure_time=time.time() + t) q.submit() for t in range(1, 10): - q.add('temperature', randint(20, 40), source='upstairs', measure_time=time.time()+t) + q.add('temperature', randint(20, 40), source='upstairs', measure_time=time.time() + t) q.submit() for t in range(1, 50): - q.add('temperature', randint(20, 30), source='downstairs', measure_time=time.time()+t) + q.add('temperature', randint(20, 30), source='downstairs', measure_time=time.time() + t) q.submit() self.conn.delete('temperature') def test_batch_sanitation(self): - name_one, name_two = 'a'*500, r'DSJAK#32102391S,m][][[{{]\\' + name_one, name_two = 'a' * 500, r'DSJAK#32102391S,m][][[{{]\\' def run_batch(connection): q = connection.new_queue() @@ -151,8 +152,8 @@ def test_submit_empty_queue(self): def test_send_batch_counter_measurements(self): q = self.conn.new_queue() for nr in range(1, 2): - q.add('num_req', nr, type='counter', source='server1', measure_time=time.time()-1) - q.add('num_req', nr, type='counter', source='server2', measure_time=time.time()-1) + q.add('num_req', nr, type='counter', source='server1', measure_time=time.time() - 1) + q.add('num_req', nr, type='counter', source='server2', measure_time=time.time() - 1) q.submit() def test_update_metrics_attributes(self): @@ -174,7 +175,7 @@ def test_update_metrics_attributes(self): self.conn.delete(name) def test_sanitized_update(self): - name, desc = 'a'*1000, 'too long, really' + name, desc = 'a' * 1000, 'too long, really' new_desc = 'different' self.conn_sanitize.submit(name, 10, description=desc) gauge = self.conn_sanitize.get(name) @@ -192,12 +193,11 @@ def test_instruments(self): _c.submit("environmental_temp", value="18", source="rack1") _c.create_instrument("Server Temperature", - streams = [ - { "metric": "server_temp", "source":"app1" }, - { "metric": "environmental_temp", "source":"rack1" } - ], - attributes = { "display_integral": True} ) - + streams=[ + {"metric": "server_temp", "source": "app1"}, + {"metric": "environmental_temp", "source": "rack1"} + ], + attributes={"display_integral": True}) """ dbs = _c.list_dashboards() @@ -234,9 +234,10 @@ def test_instrument_save_updates_existing_record(self): i = self.conn.get_instrument(i.id) assert i.name == 'NEW instrument name' + class TestLibratoAlertsIntegration(TestLibratoBase): - alerts_created_during_test=[] + alerts_created_during_test = [] gauges_used_during_test = ['metric_test', 'cpu'] def setUp(self): @@ -265,7 +266,7 @@ def test_inactive_alert_with_rearm_seconds(self): alert_id = alert._id alert = self.conn.get_alert(name) assert alert.rearm_seconds == 1200 - assert alert.active == False + assert alert.active is False def test_add_alert_with_a_condition(self): name = self.unique_name("test_add_alert_with_a_condition") @@ -333,7 +334,7 @@ def test_add_alert_with_an_absent_condition(self): def test_add_alert_with_multiple_conditions(self): name = self.unique_name("test_add_alert_with_multiple_conditions") - alert=self.conn.create_alert(name) + alert = self.conn.create_alert(name) alert.add_condition_for('cpu').above(0, 'sum') alert.add_condition_for('cpu').stops_reporting_for(3600) alert.add_condition_for('cpu').stops_reporting_for(3600) @@ -345,6 +346,7 @@ def unique_name(self, prefix): self.alerts_created_during_test.append(name) return name + class TestSpacesApi(TestLibratoBase): @classmethod def setUpClass(cls): @@ -407,9 +409,9 @@ def test_create_chart(self): 'memory', type='line', streams=[ - {'metric': 'memory.free', 'source': '*'}, - {'metric': 'memory.used', 'source': '*', - 'group_function': 'breakout', 'summary_function': 'average'} + {'metric': 'memory.free', 'source': '*'}, + {'metric': 'memory.used', 'source': '*', + 'group_function': 'breakout', 'summary_function': 'average'} ], min=0, max=50, @@ -431,14 +433,14 @@ def test_create_big_number(self): 'memory', type='bignumber', streams=[ - {'metric': 'memory.free', 'source': '*'} + {'metric': 'memory.free', 'source': '*'} ], use_last_value=False ) # Shortcut chart2 = space.add_bignumber_chart('memory 2', 'memory.free', 'foo*', - use_last_value=True) + use_last_value=True) self.wait_for_replication() diff --git a/tests/mock_connection.py b/tests/mock_connection.py index 6d58d20..dd5eb5c 100644 --- a/tests/mock_connection.py +++ b/tests/mock_connection.py @@ -5,6 +5,7 @@ import six from six.moves.urllib.parse import urlparse, parse_qs + class MockServer(object): """Mock the data storing in the backend""" def __init__(self): @@ -25,7 +26,7 @@ def clean(self): self.last_chrt_id = 0 # metric_name, tag_name, tag_value -> (time1, value1), (time2, value2), ... - self.md_measurements = defaultdict(lambda : defaultdict(lambda: defaultdict(list))) + self.md_measurements = defaultdict(lambda: defaultdict(lambda: defaultdict(list))) def list_of_metrics(self): answer = self.__an_empty_list_metrics() @@ -47,7 +48,7 @@ def create_metric(self, payload): if 'value' in metric: value = metric.pop('value') elif 'sum' in metric and 'count' in metric: - value = metric.pop('sum')/metric.pop('count') + value = metric.pop('sum') / metric.pop('count') if value is not None: if 'source' not in metric: @@ -166,17 +167,17 @@ def list_of_alerts(self, name=None): c_alert["id"] = _id if name is None: alert.append(c_alert) - elif name==c_alert["name"]: + elif name == c_alert["name"]: alert.append(c_alert) return json.dumps(answer).encode('utf-8') def list_of_services(self): - #{ - # 'services': [ - # {'id': 1, 'title': 'A Service', 'type': 'mail', - # 'settings': {'addresses': 'someone@example.com'}} - # ] - #} + # { + # 'services': [ + # {'id': 1, 'title': 'A Service', 'type': 'mail', + # 'settings': {'addresses': 'someone@example.com'}} + # ] + # } answer = {} answer['query'] = {} answer['services'] = [] @@ -200,7 +201,7 @@ def get_annotation_stream(self): annotation_resp = {} annotation_resp['name'] = name annotation_resp['display_name'] = name - annotation_resp['events'] = {'event':'mocked event'} + annotation_resp['events'] = {'event': 'mocked event'} annotation_resp['query'] = {'query': 'mocked query'} return json.dumps(annotation_resp).encode('utf-8') @@ -533,7 +534,7 @@ def _json_body_based_on_request(self): elif self._req_is_create_md_measurements(): return server.create_md_measurements(r.body) elif self._req_is_delete(): - #check for single delete. Batches don't include name in the url + # check for single delete. Batches don't include name in the url try: name = self._extract_from_url() except AttributeError: @@ -545,7 +546,7 @@ def _json_body_based_on_request(self): query = urlparse(self.request.uri).query d = parse_qs(query) # Flatten since parse_qs likes to build lists of values - payload = {k:v[0] for k,v in six.iteritems(d)} + payload = {k: v[0] for k, v in six.iteritems(d)} return server.get_md_measurements(self._extract_from_url(tagged=True), payload) elif self._req_is_list_of_instruments(): return server.list_of_instruments() @@ -652,10 +653,14 @@ def _req_is_get_instrument(self): # Alerts def _req_is_create_alert(self): return self._method_is('POST') and self._path_is('/v1/alerts') + def _req_is_list_of_alerts(self): return self._method_is('GET') and self._path_is('/v1/alerts?version=2') and not self._req_is_get_alert() + def _req_is_get_alert(self): - return self._method_is('GET') and re.match('/v1/alerts\?(version=2|name=.+)\&(name=.+|version=2)', self.request.uri) + return self._method_is('GET') and re.match('/v1/alerts\?(version=2|name=.+)\&(name=.+|version=2)', + self.request.uri) + def _req_is_delete_alert(self): return (self._method_is('DELETE') and re.match('/v1/alerts/\d+', self.request.uri)) diff --git a/tests/test_aggregator.py b/tests/test_aggregator.py index be951f0..e22662c 100644 --- a/tests/test_aggregator.py +++ b/tests/test_aggregator.py @@ -3,9 +3,9 @@ import librato from librato.aggregator import Aggregator from mock_connection import MockConnect, server -#from random import randint +# from random import randint -#logging.basicConfig(level=logging.DEBUG) +# logging.basicConfig(level=logging.DEBUG) librato.HTTPSConnection = MockConnect @@ -99,11 +99,10 @@ def test_add_multiple_metrics(self): meas = self.agg.measurements[m2] assert meas['count'] == 3 - assert meas['sum'] == 42+43+44 + assert meas['sum'] == 42 + 43 + 44 assert meas['min'] == 42 assert meas['max'] == 44 - # Only gauges are supported (not counters) def test_to_payload(self): self.agg.source = 'mysource' @@ -112,7 +111,7 @@ def test_to_payload(self): assert self.agg.to_payload() == { 'gauges': [ {'name': 'test.metric', 'count': 2, 'sum': 85, 'min': 42, 'max': 43} - ], + ], 'source': 'mysource' } assert 'gauges' in self.agg.to_payload() @@ -131,7 +130,7 @@ def test_to_payload_no_source(self): 'min': 42, 'max': 42 } - ] + ] } # If 'value' is specified in the payload, the API will throw an error diff --git a/tests/test_alerts.py b/tests/test_alerts.py index e888e3b..e982547 100644 --- a/tests/test_alerts.py +++ b/tests/test_alerts.py @@ -25,7 +25,7 @@ def test_adding_a_new_alert_without_services_or_conditions(self): assert len(alert.services) == 0 assert len(alert.conditions) == 0 assert len(self.conn.list_alerts()) == 1 - + def test_adding_an_alert_with_description(self): alert = self.conn.create_alert(self.name, description="test_description") assert alert.description == "test_description" @@ -37,20 +37,20 @@ def test_adding_a_new_alert_with_a_condition(self): assert len(alert.conditions) == 1 assert alert.conditions[0].condition_type == 'above' assert alert.conditions[0].metric_name == 'cpu' - assert alert.conditions[0].threshold == 200 + assert alert.conditions[0].threshold == 200 def test_deleting_an_alert(self): alert = self.conn.create_alert(self.name) - #TODO: use requests directly instead of the client methods? + # TODO: use requests directly instead of the client methods? assert len(self.conn.list_alerts()) == 1 self.conn.delete_alert(self.name) assert len(self.conn.list_alerts()) == 0 - + def test_deleting_an_inexistent_alert(self): self.conn.create_alert('say_my_name') self.conn.delete_alert('say_my_wrong_name') assert self.conn.get_alert('say_my_name') is not None - + def test_adding_a_new_alert_with_a_service(self): alert = self.conn.create_alert(self.name) alert.add_service(1) @@ -91,14 +91,15 @@ def test_immediate_condition(self): cond = librato.alerts.Condition('foo') cond._duration = None - assert cond.immediate() == True + assert cond.immediate() is True # Not even sure this is a valid case, but testing anyway cond._duration = 0 - assert cond.immediate() == True + assert cond.immediate() is True cond._duration = 60 - assert cond.immediate() == False + assert cond.immediate() is False + class TestService(unittest.TestCase): def setUp(self): @@ -128,7 +129,7 @@ def test_list_services(self): def test_init_service(self): s = librato.alerts.Service(123, title='the title', type='mail', - settings={'addresses': 'someone@example.com'}) + settings={'addresses': 'someone@example.com'}) self.assertEqual(s._id, 123) self.assertEqual(s.title, 'the title') self.assertEqual(s.type, 'mail') @@ -136,7 +137,7 @@ def test_init_service(self): def test_service_from_dict(self): payload = {'id': 123, 'title': 'the title', 'type': 'slack', - 'settings': {'room': 'a room'}} + 'settings': {'room': 'a room'}} s = librato.alerts.Service.from_dict(self.conn, payload) self.assertEqual(s._id, 123) self.assertEqual(s.title, payload['title']) diff --git a/tests/test_annotations.py b/tests/test_annotations.py index 40d2e6e..9ded709 100644 --- a/tests/test_annotations.py +++ b/tests/test_annotations.py @@ -3,7 +3,7 @@ import librato from mock_connection import MockConnect, server -#logging.basicConfig(level=logging.DEBUG) +# logging.basicConfig(level=logging.DEBUG) # Mock the server librato.HTTPSConnection = MockConnect @@ -26,7 +26,7 @@ def test_get_payload(self): assert payload['display_name'] == 'My_Annotation_Display' def test_from_dict(self): - data = {'name': 'My_Annotation', 'display_name': 'My_Annotation_Display', 'query': {}, 'events': {} } + data = {'name': 'My_Annotation', 'display_name': 'My_Annotation_Display', 'query': {}, 'events': {}} resp = librato.Annotation.from_dict(self.cls, data) assert resp.display_name == 'My_Annotation_Display' assert resp.name == 'My_Annotation' diff --git a/tests/test_charts.py b/tests/test_charts.py index a1d35d7..5ac0c79 100644 --- a/tests/test_charts.py +++ b/tests/test_charts.py @@ -9,11 +9,13 @@ # Mock the server librato.HTTPSConnection = MockConnect + class ChartsTest(unittest.TestCase): def setUp(self): self.conn = librato.connect('user_test', 'key_test') server.clean() + # Charts class TestChartsConnection(ChartsTest): def setUp(self): @@ -148,7 +150,7 @@ def test_init_streams_list(self): def test_init_streams_group_functions(self): streams_dict = [ {'metric': 'my.metric', 'source': '*', - 'group_function': 'sum', 'summary_function': 'max'} + 'group_function': 'sum', 'summary_function': 'max'} ] chart = Chart(self.conn, streams=streams_dict) stream = chart.streams[0] @@ -289,7 +291,7 @@ def test_get_payload(self): def test_get_payload_bignumber(self): streams = [{'metric': 'my.metric', 'source': '*'}] chart = Chart(self.conn, type='bignumber', streams=streams, - use_last_value=False) + use_last_value=False) payload = chart.get_payload() self.assertEqual(payload['name'], chart.name) self.assertEqual(payload['type'], chart.type) @@ -298,16 +300,16 @@ def test_get_payload_bignumber(self): def test_streams_payload(self): streams_payload = [ - {'metric': 'some.metric', 'source': None, 'composite': None}, - {'metric': None, 'source': None, 'composite': 's("other.metric", "sf", {function: "sum"})'} + {'metric': 'some.metric', 'source': None, 'composite': None}, + {'metric': None, 'source': None, 'composite': 's("other.metric", "sf", {function: "sum"})'} ] chart = Chart(self.conn, streams=streams_payload) self.assertEqual(chart.streams_payload()[0]['metric'], streams_payload[0]['metric']) def test_get_payload_with_streams_dict(self): streams_payload = [ - {'metric': 'some.metric', 'source': None, 'composite': None}, - {'metric': 'another.metric', 'source': None, 'composite': None} + {'metric': 'some.metric', 'source': None, 'composite': None}, + {'metric': 'another.metric', 'source': None, 'composite': None} ] chart = Chart(self.conn, type='bignumber', space_id=42, streams=streams_payload) chart_payload = chart.get_payload() diff --git a/tests/test_connection.py b/tests/test_connection.py index 1b38221..0264ef3 100644 --- a/tests/test_connection.py +++ b/tests/test_connection.py @@ -7,10 +7,11 @@ import librato from mock_connection import MockConnect, server -#logging.basicConfig(level=logging.DEBUG) +# logging.basicConfig(level=logging.DEBUG) # Mock the server librato.HTTPSConnection = MockConnect + class TestConnection(unittest.TestCase): def setUp(self): self.conn = librato.connect('user_test', 'key_test', tags={'sky': 'blue'}) diff --git a/tests/test_dashboards.py b/tests/test_dashboards.py index c62a965..c24f04b 100644 --- a/tests/test_dashboards.py +++ b/tests/test_dashboards.py @@ -3,7 +3,7 @@ import librato from mock_connection import MockConnect, server -#logging.basicConfig(level=logging.DEBUG) +# logging.basicConfig(level=logging.DEBUG) # Mock the server librato.HTTPSConnection = MockConnect diff --git a/tests/test_exceptions.py b/tests/test_exceptions.py index d603655..0e5ead4 100644 --- a/tests/test_exceptions.py +++ b/tests/test_exceptions.py @@ -2,6 +2,7 @@ import unittest from librato import exceptions + class TestClientError(unittest.TestCase): def setUp(self): pass @@ -19,57 +20,57 @@ def test_parse_error_message_standard(self): def test_parse_error_message_request_scalar(self): error_resp = { - "errors": { - "request": "test error message" - } + "errors": { + "request": "test error message" + } } ex = exceptions.ClientError(400, error_resp) self.assertEqual("request: test error message", ex._parse_error_message()) def test_parse_error_message_request(self): error_resp = { - "errors": { - "request": ["Not found"] - } + "errors": { + "request": ["Not found"] + } } ex = exceptions.ClientError(400, error_resp) self.assertEqual("request: Not found", ex._parse_error_message()) def test_parse_error_message_request_multiple(self): error_resp = { - "errors": { - "request": ["Not found", "Another error"] - } + "errors": { + "request": ["Not found", "Another error"] + } } ex = exceptions.ClientError(400, error_resp) self.assertEqual("request: Not found, request: Another error", ex._parse_error_message()) def test_parse_error_message_params(self): error_resp = { - "errors": { - "params": {"measure_time": ["too far in past"]} - } + "errors": { + "params": {"measure_time": ["too far in past"]} + } } ex = exceptions.ClientError(400, error_resp) self.assertEqual("params: measure_time: too far in past", ex._parse_error_message()) def test_parse_error_message_params_multi_message(self): error_resp = { - "errors": { - "params": {"name": ["duplicate etc", "bad character etc"]} - } + "errors": { + "params": {"name": ["duplicate etc", "bad character etc"]} + } } ex = exceptions.ClientError(400, error_resp) self.assertEqual("params: name: duplicate etc, bad character etc", ex._parse_error_message()) def test_parse_error_message_params_multiple(self): error_resp = { - "errors": { - "params": { - "measure_time": ["too far in past"], - "name": "mymetricname" + "errors": { + "params": { + "measure_time": ["too far in past"], + "name": "mymetricname" + } } - } } ex = exceptions.ClientError(400, error_resp) msg = ex._parse_error_message() @@ -78,13 +79,13 @@ def test_parse_error_message_params_multiple(self): def test_parse_error_message_params_multiple_2nd_level(self): error_resp = { - "errors": { - "params": { - "conditions": { - "duration": ["must be set"] - } + "errors": { + "params": { + "conditions": { + "duration": ["must be set"] + } + } } - } } ex = exceptions.ClientError(400, error_resp) msg = ex._parse_error_message() diff --git a/tests/test_instruments.py b/tests/test_instruments.py index baf2289..a58a969 100644 --- a/tests/test_instruments.py +++ b/tests/test_instruments.py @@ -3,7 +3,7 @@ import librato from mock_connection import MockConnect, server -#logging.basicConfig(level=logging.DEBUG) +# logging.basicConfig(level=logging.DEBUG) # Mock the server librato.HTTPSConnection = MockConnect @@ -35,12 +35,12 @@ def test_adding_a_new_instrument_with_streams(self): self.conn.submit('a_gauge', 12, description='the desc for a gauge') ins.new_stream(metric='a_gauge') self.conn.update_instrument(ins) - #list_ins = self.conn.list_instruments() + # list_ins = self.conn.list_instruments() assert ins.name == name assert len(ins.streams) == 1 assert ins.id == 1 assert ins.streams[0].metric == "a_gauge" - assert ins.streams[0].composite == None + assert ins.streams[0].composite is None def test_get_instrument(self): name = "my_INST_with_STREAMS" @@ -56,7 +56,7 @@ def test_get_instrument(self): assert len(si.streams) == 1 assert si.id == 1 assert si.streams[0].metric == "a_gauge" - assert si.streams[0].composite == None + assert si.streams[0].composite is None def test_adding_a_new_instrument_with_composite_metric_stream(self): name = "my_INST_with_STREAMS" @@ -76,9 +76,9 @@ def test_adding_a_new_instrument_with_composite_metric_stream(self): def test_is_persisted(self): i = librato.Instrument(self.conn, 'test inst') - assert i.is_persisted() == False + assert i.is_persisted() is False i = librato.Instrument(self.conn, 'test inst', id=1234) - assert i.is_persisted() == True + assert i.is_persisted() is True if __name__ == '__main__': unittest.main() diff --git a/tests/test_metrics.py b/tests/test_metrics.py index 1aad518..bed584e 100644 --- a/tests/test_metrics.py +++ b/tests/test_metrics.py @@ -8,10 +8,11 @@ import time from mock_connection import MockConnect, server -#logging.basicConfig(level=logging.DEBUG) +# logging.basicConfig(level=logging.DEBUG) # Mock the server librato.HTTPSConnection = MockConnect + class TestLibrato(unittest.TestCase): def setUp(self): self.conn = librato.connect('user_test', 'key_test') @@ -28,7 +29,7 @@ def mock_list(**args): # I don't care what the metrics are # this is about testing the logic and the calls result = [{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}] - return result[offset:length+offset] + return result[offset:length + offset] expected_call_list = [({'length': 5, 'offset': 0},), ({'length': 5, 'offset': 5},), @@ -182,7 +183,7 @@ def test_add_in_gauge(self): def test_md_submit(self): mt1 = int(time.time()) - 5 - tags={'hostname': 'web-1'} + tags = {'hostname': 'web-1'} self.conn.submit_tagged('user_cpu', 20.2, time=mt1, tags=tags) resp = self.conn.get_tagged('user_cpu', duration=60, tags_search="hostname=web-1") @@ -200,7 +201,7 @@ def test_merge_tags(self): mt1 = int(time.time()) - 5 self.conn.set_tags({'company': 'Librato'}) - tags={'hostname': 'web-1'} + tags = {'hostname': 'web-1'} self.conn.submit_tagged('user_cpu', 20.2, time=mt1, tags=tags) # Ensure 'company' and 'hostname' tags made it through diff --git a/tests/test_param_url_encoding.py b/tests/test_param_url_encoding.py index d588f11..2827c84 100644 --- a/tests/test_param_url_encoding.py +++ b/tests/test_param_url_encoding.py @@ -2,17 +2,18 @@ import unittest import librato + class TestLibratoUrlEncoding(unittest.TestCase): def setUp(self): self.conn = librato.connect('user_test', 'key_test') def test_string_encoding(self): - params = {"name":"abcd"} + params = {"name": "abcd"} assert self.conn._url_encode_params(params) == 'name=abcd' def test_list_encoding(self): - params = {"sources": ['a','b']} + params = {"sources": ['a', 'b']} assert self.conn._url_encode_params(params) == 'sources%5B%5D=a&sources%5B%5D=b' def test_empty_encoding(self): diff --git a/tests/test_process_response.py b/tests/test_process_response.py index 99ed42f..5d06760 100644 --- a/tests/test_process_response.py +++ b/tests/test_process_response.py @@ -8,10 +8,11 @@ from mock_connection import MockConnect, server from six.moves.http_client import HTTPResponse -#logging.basicConfig(level=logging.DEBUG) +# logging.basicConfig(level=logging.DEBUG) # Mock the server librato.HTTPSConnection = MockConnect + class TestLibrato(unittest.TestCase): def setUp(self): self.conn = librato.connect('user_test', 'key_test') diff --git a/tests/test_queue.py b/tests/test_queue.py index 4b28423..c6ef075 100644 --- a/tests/test_queue.py +++ b/tests/test_queue.py @@ -6,7 +6,7 @@ from random import randint import time -#logging.basicConfig(level=logging.DEBUG) +# logging.basicConfig(level=logging.DEBUG) librato.HTTPSConnection = MockConnect @@ -99,7 +99,7 @@ def test_single_measurement_counter(self): def test_num_metrics_in_queue(self): q = self.q # With only one chunk - for _ in range(q.MAX_MEASUREMENTS_PER_CHUNK-10): + for _ in range(q.MAX_MEASUREMENTS_PER_CHUNK - 10): q.add('temperature', randint(20, 30)) assert q._num_measurements_in_queue() == 290 # Now ensure multiple chunks @@ -121,7 +121,7 @@ def test_auto_submit_on_metric_count(self): def test_reach_chunk_limit(self): q = self.q - for i in range(1, q.MAX_MEASUREMENTS_PER_CHUNK+1): + for i in range(1, q.MAX_MEASUREMENTS_PER_CHUNK + 1): q.add('temperature', randint(20, 30)) assert len(q.chunks) == 1 assert q._num_measurements_in_current_chunk() == q.MAX_MEASUREMENTS_PER_CHUNK @@ -149,7 +149,7 @@ def test_submit_one_measurement_batch_mode(self): assert len(metrics) == 1 gauge = self.conn.get('temperature', resolution=1, count=2) assert gauge.name == 'temperature' - assert gauge.description == None + assert gauge.description is None assert len(gauge.measurements['unassigned']) == 1 # Add another measurements for temperature @@ -159,7 +159,7 @@ def test_submit_one_measurement_batch_mode(self): assert len(metrics) == 1 gauge = self.conn.get('temperature', resolution=1, count=2) assert gauge.name == 'temperature' - assert gauge.description == None + assert gauge.description is None assert len(gauge.measurements['unassigned']) == 2 assert gauge.measurements['unassigned'][0]['value'] == 22.1 assert gauge.measurements['unassigned'][1]['value'] == 23 @@ -169,27 +169,27 @@ def test_submit_tons_of_measurement_batch_mode(self): metrics = self.conn.list_metrics() assert len(metrics) == 0 - for t in range(1, q.MAX_MEASUREMENTS_PER_CHUNK+1): + for t in range(1, q.MAX_MEASUREMENTS_PER_CHUNK + 1): q.add('temperature', t) q.submit() metrics = self.conn.list_metrics() assert len(metrics) == 1 - gauge = self.conn.get('temperature', resolution=1, count=q.MAX_MEASUREMENTS_PER_CHUNK+1) + gauge = self.conn.get('temperature', resolution=1, count=q.MAX_MEASUREMENTS_PER_CHUNK + 1) assert gauge.name == 'temperature' - assert gauge.description == None - for t in range(1, q.MAX_MEASUREMENTS_PER_CHUNK+1): - assert gauge.measurements['unassigned'][t-1]['value'] == t + assert gauge.description is None + for t in range(1, q.MAX_MEASUREMENTS_PER_CHUNK + 1): + assert gauge.measurements['unassigned'][t - 1]['value'] == t - for cl in range(1, q.MAX_MEASUREMENTS_PER_CHUNK+1): + for cl in range(1, q.MAX_MEASUREMENTS_PER_CHUNK + 1): q.add('cpu_load', cl) q.submit() metrics = self.conn.list_metrics() assert len(metrics) == 2 - gauge = self.conn.get('cpu_load', resolution=1, count=q.MAX_MEASUREMENTS_PER_CHUNK+1) + gauge = self.conn.get('cpu_load', resolution=1, count=q.MAX_MEASUREMENTS_PER_CHUNK + 1) assert gauge.name == 'cpu_load' - assert gauge.description == None - for t in range(1, q.MAX_MEASUREMENTS_PER_CHUNK+1): - assert gauge.measurements['unassigned'][t-1]['value'] == t + assert gauge.description is None + for t in range(1, q.MAX_MEASUREMENTS_PER_CHUNK + 1): + assert gauge.measurements['unassigned'][t - 1]['value'] == t def test_add_aggregator(self): q = self.q diff --git a/tests/test_retry_logic.py b/tests/test_retry_logic.py index 36d5af4..e9ea589 100644 --- a/tests/test_retry_logic.py +++ b/tests/test_retry_logic.py @@ -3,7 +3,7 @@ import librato import mock_connection -#logging.basicConfig(level=logging.DEBUG) +# logging.basicConfig(level=logging.DEBUG) # Mock the server librato.HTTPSConnection = mock_connection.MockConnect diff --git a/tests/test_sanitization.py b/tests/test_sanitization.py index e3d4713..73c01f7 100644 --- a/tests/test_sanitization.py +++ b/tests/test_sanitization.py @@ -13,7 +13,7 @@ def test_sanitize_metric_name(self): for name, expected in [ (valid_chars, valid_chars), (valid_chars.upper(), valid_chars.upper()), - ('a'*500, 'a'*255), + ('a' * 500, 'a' * 255), (' \t\nbat$$$*[]()m#@%^&=`~an', '-bat-m-an'), # throw in a unicode char ('Just*toBeSafe', 'Just-toBeSafe') ]: diff --git a/tests/test_spaces.py b/tests/test_spaces.py index 7873089..1ec7513 100644 --- a/tests/test_spaces.py +++ b/tests/test_spaces.py @@ -9,6 +9,7 @@ # Mock the server librato.HTTPSConnection = MockConnect + class SpacesTest(unittest.TestCase): def setUp(self): self.conn = librato.connect('user_test', 'key_test') @@ -166,13 +167,12 @@ def test_new_chart_type(self): def test_new_chart_attrs(self): chart = self.space.new_chart('test', - label='hello', - min=-5, - max=30, - use_log_yaxis=True, - use_last_value=True, - related_space=1234 - ) + label='hello', + min=-5, + max=30, + use_log_yaxis=True, + use_last_value=True, + related_space=1234) self.assertEqual(chart.label, 'hello') self.assertEqual(chart.min, -5) self.assertEqual(chart.max, 30) @@ -182,7 +182,7 @@ def test_new_chart_attrs(self): def test_new_chart_bignumber(self): chart = self.space.new_chart('test', type='bignumber', - use_last_value=False) + use_last_value=False) self.assertEqual(chart.type, 'bignumber') self.assertFalse(chart.use_last_value) @@ -293,13 +293,13 @@ def test_add_bignumber_chart_source(self): def test_add_bignumber_chart_summary_function(self): space = self.conn.create_space('foo') chart = space.add_bignumber_chart('cpu', 'my.metric', - summary_function='min') + summary_function='min') self.assertEqual(chart.streams[0].summary_function, 'min') def test_add_bignumber_chart_group_function(self): space = self.conn.create_space('foo') chart = space.add_bignumber_chart('cpu', 'my.metric', - group_function='max') + group_function='max') self.assertEqual(chart.streams[0].group_function, 'max') def test_add_bignumber_chart_use_last_value(self): diff --git a/tests/test_streams.py b/tests/test_streams.py index 7dd783d..64a177d 100644 --- a/tests/test_streams.py +++ b/tests/test_streams.py @@ -8,6 +8,7 @@ # Mock the server librato.HTTPSConnection = MockConnect + class TestStreamModel(unittest.TestCase): def setUp(self): self.conn = librato.connect('user_test', 'key_test') @@ -91,19 +92,18 @@ def test_init_with_extra_attributes(self): self.assertEqual(s.color, '#f00') self.assertEqual(s.something, 'foo') - def test_get_payload(self): self.assertEqual(Stream(metric='my.metric').get_payload(), - {'metric': 'my.metric', 'source': '*'}) + {'metric': 'my.metric', 'source': '*'}) def test_payload_all_attributes(self): s = Stream(metric='my.metric', source='*', name='my display name', - type='gauge', id=1234, - group_function='min', summary_function='max', - transform_function='x/p', downsample_function='min', - period=60, split_axis=False, - min=0, max=42, - units_short='req/s', units_long='requests per second') + type='gauge', id=1234, + group_function='min', summary_function='max', + transform_function='x/p', downsample_function='min', + period=60, split_axis=False, + min=0, max=42, + units_short='req/s', units_long='requests per second') payload = { 'metric': 'my.metric', 'source': '*', @@ -124,6 +124,5 @@ def test_payload_all_attributes(self): self.assertEqual(s.get_payload(), payload) - if __name__ == '__main__': unittest.main()