1- from __future__ import unicode_literals
2-
31import base64
42from contextlib import closing
3+ from http .server import BaseHTTPRequestHandler
54import os
65import socket
6+ from socketserver import ThreadingMixIn
77import sys
88import threading
9+ from urllib .error import HTTPError
10+ from urllib .parse import parse_qs , quote_plus , urlparse
11+ from urllib .request import (
12+ build_opener , HTTPHandler , HTTPRedirectHandler , Request ,
13+ )
914from wsgiref .simple_server import make_server , WSGIRequestHandler , WSGIServer
1015
1116from .openmetrics import exposition as openmetrics
1217from .registry import REGISTRY
1318from .utils import floatToGoString
1419
15- try :
16- from urllib import quote_plus
17-
18- from BaseHTTPServer import BaseHTTPRequestHandler
19- from SocketServer import ThreadingMixIn
20- from urllib2 import (
21- build_opener , HTTPError , HTTPHandler , HTTPRedirectHandler , Request ,
22- )
23- from urlparse import parse_qs , urlparse
24- except ImportError :
25- # Python 3
26- from http .server import BaseHTTPRequestHandler
27- from socketserver import ThreadingMixIn
28- from urllib .error import HTTPError
29- from urllib .parse import parse_qs , quote_plus , urlparse
30- from urllib .request import (
31- build_opener , HTTPHandler , HTTPRedirectHandler , Request ,
32- )
33-
34- CONTENT_TYPE_LATEST = str ('text/plain; version=0.0.4; charset=utf-8' )
20+ CONTENT_TYPE_LATEST = 'text/plain; version=0.0.4; charset=utf-8'
3521"""Content type of the latest text format"""
36- PYTHON27_OR_OLDER = sys .version_info < (3 , )
3722PYTHON376_OR_NEWER = sys .version_info > (3 , 7 , 5 )
3823
3924
@@ -88,11 +73,7 @@ def redirect_request(self, req, fp, code, msg, headers, newurl):
8873 unverifiable = True ,
8974 data = req .data ,
9075 )
91- if PYTHON27_OR_OLDER :
92- # the `method` attribute did not exist for Request in Python 2.7.
93- new_request .get_method = lambda : m
94- else :
95- new_request .method = m
76+ new_request .method = m
9677 return new_request
9778
9879
@@ -102,7 +83,7 @@ def _bake_output(registry, accept_header, params):
10283 if 'name[]' in params :
10384 registry = registry .restricted_registry (params ['name[]' ])
10485 output = encoder (registry )
105- return str ( '200 OK' ) , (str ( 'Content-Type' ) , content_type ), output
86+ return '200 OK' , ('Content-Type' , content_type ), output
10687
10788
10889def make_wsgi_app (registry = REGISTRY ):
@@ -114,8 +95,8 @@ def prometheus_app(environ, start_response):
11495 params = parse_qs (environ .get ('QUERY_STRING' , '' ))
11596 if environ ['PATH_INFO' ] == '/favicon.ico' :
11697 # Serve empty response for browsers
117- status = str ( '200 OK' )
118- header = (str ( '' ), str ( '' ) )
98+ status = '200 OK'
99+ header = ('' , '' )
119100 output = b''
120101 else :
121102 # Bake output
@@ -160,17 +141,16 @@ def generate_latest(registry=REGISTRY):
160141 def sample_line (line ):
161142 if line .labels :
162143 labelstr = '{{{0}}}' .format (',' .join (
163- ['{0 }="{1 }"' .format (
144+ ['{}="{}"' .format (
164145 k , v .replace ('\\ ' , r'\\' ).replace ('\n ' , r'\n' ).replace ('"' , r'\"' ))
165146 for k , v in sorted (line .labels .items ())]))
166147 else :
167148 labelstr = ''
168149 timestamp = ''
169150 if line .timestamp is not None :
170151 # Convert to milliseconds.
171- timestamp = ' {0:d}' .format (int (float (line .timestamp ) * 1000 ))
172- return '{0}{1} {2}{3}\n ' .format (
173- line .name , labelstr , floatToGoString (line .value ), timestamp )
152+ timestamp = f' { int (float (line .timestamp ) * 1000 ):d} '
153+ return f'{ line .name } { labelstr } { floatToGoString (line .value )} { timestamp } \n '
174154
175155 output = []
176156 for metric in registry .collect ():
@@ -192,9 +172,9 @@ def sample_line(line):
192172 elif mtype == 'unknown' :
193173 mtype = 'untyped'
194174
195- output .append ('# HELP {0 } {1 }\n ' .format (
175+ output .append ('# HELP {} {}\n ' .format (
196176 mname , metric .documentation .replace ('\\ ' , r'\\' ).replace ('\n ' , r'\n' )))
197- output .append ('# TYPE {0 } {1 }\n ' . format ( mname , mtype ) )
177+ output .append (f '# TYPE { mname } { mtype } \n ' )
198178
199179 om_samples = {}
200180 for s in metric .samples :
@@ -210,9 +190,9 @@ def sample_line(line):
210190 raise
211191
212192 for suffix , lines in sorted (om_samples .items ()):
213- output .append ('# HELP {0}{1 } {2 }\n ' .format (metric .name , suffix ,
214- metric .documentation .replace ('\\ ' , r'\\' ).replace ('\n ' , r'\n' )))
215- output .append ('# TYPE {0}{1 } gauge\n ' . format ( metric . name , suffix ) )
193+ output .append ('# HELP {}{ } {}\n ' .format (metric .name , suffix ,
194+ metric .documentation .replace ('\\ ' , r'\\' ).replace ('\n ' , r'\n' )))
195+ output .append (f '# TYPE { metric . name } { suffix } gauge\n ' )
216196 output .extend (lines )
217197 return '' .join (output ).encode ('utf-8' )
218198
@@ -267,25 +247,13 @@ def write_to_textfile(path, registry):
267247
268248 This is intended for use with the Node exporter textfile collector.
269249 The path must end in .prom for the textfile collector to process it."""
270- tmppath = '%s.%s.%s' % ( path , os .getpid (), threading .current_thread ().ident )
250+ tmppath = f' { path } . { os .getpid ()} . { threading .current_thread ().ident } '
271251 with open (tmppath , 'wb' ) as f :
272252 f .write (generate_latest (registry ))
273253
274254 # rename(2) is atomic but fails on Windows if the destination file exists
275255 if os .name == 'nt' :
276- if sys .version_info <= (3 , 3 ):
277- # Unable to guarantee atomic rename on Windows and Python<3.3
278- # Remove and rename instead (risks losing the file)
279- try :
280- os .remove (path )
281- except FileNotFoundError :
282- pass
283-
284- os .rename (tmppath , path )
285- else :
286- # os.replace is introduced in Python 3.3 but there is some dispute whether
287- # it is a truly atomic file operation: https://bugs.python.org/issue8828
288- os .replace (tmppath , path )
256+ os .replace (tmppath , path )
289257 else :
290258 os .rename (tmppath , path )
291259
@@ -299,8 +267,7 @@ def handle():
299267 request .add_header (k , v )
300268 resp = build_opener (base_handler ).open (request , timeout = timeout )
301269 if resp .code >= 400 :
302- raise IOError ("error talking to pushgateway: {0} {1}" .format (
303- resp .code , resp .msg ))
270+ raise OSError (f"error talking to pushgateway: { resp .code } { resp .msg } " )
304271
305272 return handle
306273
@@ -337,7 +304,7 @@ def handle():
337304 """Handler that implements HTTP Basic Auth.
338305 """
339306 if username is not None and password is not None :
340- auth_value = '{0 }:{1 }' .format ( username , password ). encode ('utf-8' )
307+ auth_value = f' { username } :{ password } ' .encode ()
341308 auth_token = base64 .b64encode (auth_value )
342309 auth_header = b'Basic ' + auth_token
343310 headers .append (['Authorization' , auth_header ])
@@ -447,10 +414,10 @@ def _use_gateway(method, gateway, job, registry, grouping_key, timeout, handler)
447414 PYTHON376_OR_NEWER
448415 and gateway_url .scheme not in ['http' , 'https' ]
449416 ):
450- gateway = 'http://{0}' . format ( gateway )
417+ gateway = f 'http://{ gateway } '
451418
452419 gateway = gateway .rstrip ('/' )
453- url = '{0 }/metrics/{1 }/{2 }' .format (gateway , * _escape_grouping_key ("job" , job ))
420+ url = '{}/metrics/{}/{}' .format (gateway , * _escape_grouping_key ("job" , job ))
454421
455422 data = b''
456423 if method != 'DELETE' :
@@ -459,7 +426,7 @@ def _use_gateway(method, gateway, job, registry, grouping_key, timeout, handler)
459426 if grouping_key is None :
460427 grouping_key = {}
461428 url += '' .join (
462- '/{0 }/{1 }' .format (* _escape_grouping_key (str (k ), str (v )))
429+ '/{}/{}' .format (* _escape_grouping_key (str (k ), str (v )))
463430 for k , v in sorted (grouping_key .items ()))
464431
465432 handler (
@@ -495,8 +462,4 @@ def instance_ip_grouping_key():
495462 return {'instance' : s .getsockname ()[0 ]}
496463
497464
498- try :
499- # Python >3.5 only
500- from .asgi import make_asgi_app # noqa
501- except :
502- pass
465+ from .asgi import make_asgi_app # noqa
0 commit comments