Repository: prometheus/client_python
Pull request #4 (2015-02-20 07:28:26)

Make code and tests for for python 3 too.


Patch:
diff --git a/README.md b/README.md
index ca0b3fd..6455d82 100644
--- a/README.md
+++ b/README.md
@@ -116,6 +116,8 @@ There are several options for exporting metrics.
 
 Metrics are usuall exposed over HTTP, to be read by the Prometheus server. For example:
 
+Python 2:
+
 ```python
 from prometheus_client import MetricsHandler
 from BaseHTTPServer import HTTPServer
@@ -124,6 +126,16 @@ httpd = HTTPServer(server_address, MetricsHandler)
 httpd.serve_forever()
 ```
 
+Python 3:
+
+```python
+from prometheus_client import MetricsHandler
+from http.server import HTTPServer
+server_address = ('', 8000)
+httpd = HTTPServer(server_address, MetricsHandler)
+httpd.serve_forever()
+```
+
 Visit [http://localhost:8000/](http://localhost:8000/) to view the metrics.
 
 ## Node exporter textfile collector
diff --git a/prometheus_client/__init__.py b/prometheus_client/__init__.py
index e100b27..8a87285 100644
--- a/prometheus_client/__init__.py
+++ b/prometheus_client/__init__.py
@@ -1,12 +1,18 @@
 #!/usr/bin/python
 
+from __future__ import unicode_literals
+
 import copy
 import re
 import os
 import time
 import threading
 from contextlib import contextmanager
-from BaseHTTPServer import BaseHTTPRequestHandler
+try:
+  from BaseHTTPServer import BaseHTTPRequestHandler
+except ImportError:
+  # Python 3
+  from http.server import BaseHTTPRequestHandler
 from functools import wraps
 from threading import Lock
 
@@ -116,7 +122,7 @@ class _LabelWrapper(object):
   def _samples(self):
     with self._lock:
       metrics = self._metrics.copy()
-    for labels, metric in metrics.iteritems():
+    for labels, metric in metrics.items():
       for suffix, _, value in metric._samples():
         yield (suffix, dict(zip(self._labelnames, labels)), value)
 
@@ -298,18 +304,18 @@ def generate_latest(registry=REGISTRY):
     '''Returns the metrics from the registry in latest text format as a string.'''
     output = []
     for metric in registry.collect():
-      output.append(u'# HELP %s %s' % (
+      output.append('# HELP {0} {1}'.format(
         metric._name, metric._documentation.replace('\\', r'\\').replace('\n', r'\n')))
-      output.append(u'\n# TYPE %s %s\n' % (metric._name, metric._type))
+      output.append('\n# TYPE {0} {1}\n'.format(metric._name, metric._type))
       for name, labels, value in metric._samples:
         if labels:
-          labelstr = u'{%s}' % ','.join(
-              [u'%s="%s"' % (
+          labelstr = '{{{0}}}'.format(','.join(
+              ['{0}="{1}"'.format(
                   k, v.replace('\\', r'\\').replace('\n', r'\n').replace('\'', r'\''))
-               for k, v in labels.items()])
+               for k, v in labels.items()]))
         else:
-          labelstr = u''
-        output.append(u'%s%s %s\n' % (name, labelstr, value))
+          labelstr = ''
+        output.append('{0}{1} {2}\n'.format(name, labelstr, value))
     return ''.join(output).encode('utf-8')
 
 


Test patch:
diff --git a/tests/test_client.py b/tests/test_client.py
index 2eae272..9bf82ed 100644
--- a/tests/test_client.py
+++ b/tests/test_client.py
@@ -1,3 +1,4 @@
+from __future__ import unicode_literals
 import unittest
 
 from prometheus_client import Gauge, Counter, Summary
@@ -9,11 +10,11 @@ class TestCounter(unittest.TestCase):
     self.counter = Counter('c', 'help', registry=self.registry)
 
   def test_increment(self):
-    self.assertEquals(0, self.registry.get_sample_value('c'))
+    self.assertEqual(0, self.registry.get_sample_value('c'))
     self.counter.inc()
-    self.assertEquals(1, self.registry.get_sample_value('c'))
+    self.assertEqual(1, self.registry.get_sample_value('c'))
     self.counter.inc(7)
-    self.assertEquals(8, self.registry.get_sample_value('c'))
+    self.assertEqual(8, self.registry.get_sample_value('c'))
  
   def test_negative_increment_raises(self):
     self.assertRaises(ValueError, self.counter.inc, -1)
@@ -29,17 +30,17 @@ class TestCounter(unittest.TestCase):
       f(False)
     except TypeError:
       pass
-    self.assertEquals(0, self.registry.get_sample_value('c'))
+    self.assertEqual(0, self.registry.get_sample_value('c'))
     try:
       f(True)
     except ValueError:
       raised = True
-    self.assertEquals(1, self.registry.get_sample_value('c'))
+    self.assertEqual(1, self.registry.get_sample_value('c'))
 
   def test_block_decorator(self):
     with self.counter.count_exceptions():
       pass
-    self.assertEquals(0, self.registry.get_sample_value('c'))
+    self.assertEqual(0, self.registry.get_sample_value('c'))
     raised = False
     try:
       with self.counter.count_exceptions():
@@ -47,7 +48,7 @@ class TestCounter(unittest.TestCase):
     except:
       raised = True
     self.assertTrue(raised)
-    self.assertEquals(1, self.registry.get_sample_value('c'))
+    self.assertEqual(1, self.registry.get_sample_value('c'))
 
 class TestGauge(unittest.TestCase):
   def setUp(self):
@@ -55,27 +56,27 @@ class TestGauge(unittest.TestCase):
     self.gauge = Gauge('g', 'help', registry=self.registry)
 
   def test_gauge(self):
-    self.assertEquals(0, self.registry.get_sample_value('g'))
+    self.assertEqual(0, self.registry.get_sample_value('g'))
     self.gauge.inc()
-    self.assertEquals(1, self.registry.get_sample_value('g'))
+    self.assertEqual(1, self.registry.get_sample_value('g'))
     self.gauge.dec(3)
-    self.assertEquals(-2, self.registry.get_sample_value('g'))
+    self.assertEqual(-2, self.registry.get_sample_value('g'))
     self.gauge.set(9)
-    self.assertEquals(9, self.registry.get_sample_value('g'))
+    self.assertEqual(9, self.registry.get_sample_value('g'))
 
   def test_function_decorator(self):
-    self.assertEquals(0, self.registry.get_sample_value('g'))
+    self.assertEqual(0, self.registry.get_sample_value('g'))
     @self.gauge.track_inprogress()
     def f():
-      self.assertEquals(1, self.registry.get_sample_value('g'))
+      self.assertEqual(1, self.registry.get_sample_value('g'))
     f()
-    self.assertEquals(0, self.registry.get_sample_value('g'))
+    self.assertEqual(0, self.registry.get_sample_value('g'))
 
   def test_block_decorator(self):
-    self.assertEquals(0, self.registry.get_sample_value('g'))
+    self.assertEqual(0, self.registry.get_sample_value('g'))
     with self.gauge.track_inprogress():
-      self.assertEquals(1, self.registry.get_sample_value('g'))
-    self.assertEquals(0, self.registry.get_sample_value('g'))
+      self.assertEqual(1, self.registry.get_sample_value('g'))
+    self.assertEqual(0, self.registry.get_sample_value('g'))
 
 class TestSummary(unittest.TestCase):
   def setUp(self):
@@ -83,25 +84,25 @@ class TestSummary(unittest.TestCase):
     self.summary = Summary('s', 'help', registry=self.registry)
 
   def test_summary(self):
-    self.assertEquals(0, self.registry.get_sample_value('s_count'))
-    self.assertEquals(0, self.registry.get_sample_value('s_sum'))
+    self.assertEqual(0, self.registry.get_sample_value('s_count'))
+    self.assertEqual(0, self.registry.get_sample_value('s_sum'))
     self.summary.observe(10)
-    self.assertEquals(1, self.registry.get_sample_value('s_count'))
-    self.assertEquals(10, self.registry.get_sample_value('s_sum'))
+    self.assertEqual(1, self.registry.get_sample_value('s_count'))
+    self.assertEqual(10, self.registry.get_sample_value('s_sum'))
 
   def test_function_decorator(self):
-    self.assertEquals(0, self.registry.get_sample_value('s_count'))
+    self.assertEqual(0, self.registry.get_sample_value('s_count'))
     @self.summary.time()
     def f():
       pass
     f()
-    self.assertEquals(1, self.registry.get_sample_value('s_count'))
+    self.assertEqual(1, self.registry.get_sample_value('s_count'))
 
   def test_block_decorator(self):
-    self.assertEquals(0, self.registry.get_sample_value('s_count'))
+    self.assertEqual(0, self.registry.get_sample_value('s_count'))
     with self.summary.time():
       pass
-    self.assertEquals(1, self.registry.get_sample_value('s_count'))
+    self.assertEqual(1, self.registry.get_sample_value('s_count'))
 
 class TestMetricWrapper(unittest.TestCase):
   def setUp(self):
@@ -111,18 +112,18 @@ class TestMetricWrapper(unittest.TestCase):
 
   def test_child(self):
     self.counter.labels('x').inc()
-    self.assertEquals(1, self.registry.get_sample_value('c', {'l': 'x'}))
+    self.assertEqual(1, self.registry.get_sample_value('c', {'l': 'x'}))
     self.two_labels.labels('x', 'y').inc(2)
-    self.assertEquals(2, self.registry.get_sample_value('two', {'a': 'x', 'b': 'y'}))
+    self.assertEqual(2, self.registry.get_sample_value('two', {'a': 'x', 'b': 'y'}))
 
   def test_remove(self):
     self.counter.labels('x').inc()
     self.counter.labels('y').inc(2)
-    self.assertEquals(1, self.registry.get_sample_value('c', {'l': 'x'}))
-    self.assertEquals(2, self.registry.get_sample_value('c', {'l': 'y'}))
+    self.assertEqual(1, self.registry.get_sample_value('c', {'l': 'x'}))
+    self.assertEqual(2, self.registry.get_sample_value('c', {'l': 'y'}))
     self.counter.remove('x')
-    self.assertEquals(None, self.registry.get_sample_value('c', {'l': 'x'}))
-    self.assertEquals(2, self.registry.get_sample_value('c', {'l': 'y'}))
+    self.assertEqual(None, self.registry.get_sample_value('c', {'l': 'x'}))
+    self.assertEqual(2, self.registry.get_sample_value('c', {'l': 'y'}))
 
   def test_incorrect_label_count_raises(self):
     self.assertRaises(ValueError, self.counter.labels)
@@ -133,7 +134,7 @@ class TestMetricWrapper(unittest.TestCase):
   def test_namespace_subsystem_concatenated(self):
     c = Counter('c', 'help', namespace='a', subsystem='b', registry=self.registry)
     c.inc()
-    self.assertEquals(1, self.registry.get_sample_value('a_b_c'))
+    self.assertEqual(1, self.registry.get_sample_value('a_b_c'))
 
   def test_invalid_names_raise(self):
     self.assertRaises(ValueError, Counter, '', 'help')
@@ -150,22 +151,27 @@ class TestGenerateText(unittest.TestCase):
   def test_counter(self):
     c = Counter('cc', 'A counter', registry=self.registry)
     c.inc()
-    self.assertEquals('# HELP cc A counter\n# TYPE cc counter\ncc 1.0\n', generate_latest(self.registry))
+    self.assertEqual(b'# HELP cc A counter\n# TYPE cc counter\ncc 1.0\n', generate_latest(self.registry))
 
   def test_gauge(self):
     g = Gauge('gg', 'A gauge', registry=self.registry)
     g.set(17)
-    self.assertEquals('# HELP gg A gauge\n# TYPE gg gauge\ngg 17.0\n', generate_latest(self.registry))
+    self.assertEqual(b'# HELP gg A gauge\n# TYPE gg gauge\ngg 17.0\n', generate_latest(self.registry))
 
   def test_summary(self):
     s = Summary('ss', 'A summary', ['a', 'b'], registry=self.registry)
     s.labels('c', 'd').observe(17)
-    self.assertEquals('# HELP ss A summary\n# TYPE ss summary\nss_count{a="c",b="d"} 1.0\nss_sum{a="c",b="d"} 17.0\n', generate_latest(self.registry))
+    self.assertEqual(b'# HELP ss A summary\n# TYPE ss summary\nss_count{a="c",b="d"} 1.0\nss_sum{a="c",b="d"} 17.0\n', generate_latest(self.registry))
+
+  def test_unicode(self):
+    c = Counter('cc', '\u4500', ['l'], registry=self.registry)
+    c.labels('\u4500').inc()
+    self.assertEqual(b'# HELP cc \xe4\x94\x80\n# TYPE cc counter\ncc{l="\xe4\x94\x80"} 1.0\n', generate_latest(self.registry))
 
   def test_escaping(self):
     c = Counter('cc', 'A\ncount\\er', ['a'], registry=self.registry)
     c.labels('\\x\n').inc(1)
-    self.assertEquals('# HELP cc A\\ncount\\\\er\n# TYPE cc counter\ncc{a="\\\\x\\n"} 1.0\n', generate_latest(self.registry))
+    self.assertEqual(b'# HELP cc A\\ncount\\\\er\n# TYPE cc counter\ncc{a="\\\\x\\n"} 1.0\n', generate_latest(self.registry))
 
 
 if __name__ == '__main__':