From 7260dff9a297d02dce46aeb7164b08f339221115 Mon Sep 17 00:00:00 2001
From: A_D <aunderscored@gmail.com>
Date: Mon, 6 Jul 2020 21:56:23 +0200
Subject: [PATCH] Replaced modulo formatting with .format calls

Modulo formatting is py2 (and C printf) style, its arcane and incredibly
hard to read for large formats.

I used keyed .formats where there were more than a few format specifiers
---
 companion.py | 82 +++++++++++++++++++++++++++++++++-------------------
 1 file changed, 52 insertions(+), 30 deletions(-)

diff --git a/companion.py b/companion.py
index 19d191c9..b03e326c 100644
--- a/companion.py
+++ b/companion.py
@@ -33,7 +33,8 @@ auth_timeout = 30  # timeout for initial auth
 
 # Currently the "Elite Dangerous Market Connector (EDCD/Athanasius)" one in
 # Athanasius' Frontier account
-CLIENT_ID   = os.getenv('CLIENT_ID') or 'fb88d428-9110-475f-a3d2-dc151c2b9c7a' 	# Obtain from https://auth.frontierstore.net/client/signup
+# Obtain from https://auth.frontierstore.net/client/signup
+CLIENT_ID   = os.getenv('CLIENT_ID') or 'fb88d428-9110-475f-a3d2-dc151c2b9c7a'
 SERVER_AUTH = 'https://auth.frontierstore.net'
 URL_AUTH    = '/auth'
 URL_TOKEN   = '/token'
@@ -168,7 +169,7 @@ class Auth(object):
     def __init__(self, cmdr):
         self.cmdr = cmdr
         self.session = requests.Session()
-        self.session.headers['User-Agent'] = 'EDCD-%s-%s' % (appname, appversion)
+        self.session.headers['User-Agent'] = 'EDCD-{}-{}'.format(appname, appversion)
         self.verifier = self.state = None
 
     def refresh(self):
@@ -195,15 +196,15 @@ class Auth(object):
                     return data.get('access_token')
 
                 else:
-                    print('Auth\tCan\'t refresh token for %s' % self.cmdr)
+                    print('Auth\tCan\'t refresh token for {}'.format(self.cmdr))
                     self.dump(r)
 
             except:
-                print('Auth\tCan\'t refresh token for %s' % self.cmdr)
+                print('Auth\tCan\'t refresh token for {}'.format(self.cmdr))
                 print_exc()
 
         else:
-            print('Auth\tNo token for %s' % self.cmdr)
+            print('Auth\tNo token for {}'.format(self.cmdr))
 
         # New request
         print('Auth\tNew authorization request')
@@ -212,29 +213,43 @@ class Auth(object):
         s = random.SystemRandom().getrandbits(8 * 32)
         self.state = self.base64URLEncode(s.to_bytes(32, byteorder='big'))
         # Won't work under IE: https://blogs.msdn.microsoft.com/ieinternals/2011/07/13/understanding-protocols/
-        webbrowser.open('%s%s?response_type=code&audience=frontier&scope=capi&client_id=%s&code_challenge=%s&code_challenge_method=S256&state=%s&redirect_uri=%s' % (SERVER_AUTH, URL_AUTH, CLIENT_ID, self.base64URLEncode(hashlib.sha256(self.verifier).digest()), self.state, protocolhandler.redirect))
+        webbrowser.open(
+            
+            '{server_auth}{url_auth}?response_type=code&audience=frontier&scope=capi&client_id={client_id}&code_challenge={challenge}&code_challenge_method=S256&state={state}&redirect_uri={redirect}'.format(  # noqa: E501
+                server_auth=SERVER_AUTH,
+                url_auth=URL_AUTH,
+                client_id=CLIENT_ID,
+                challenge=self.base64URLEncode(hashlib.sha256(self.verifier).digest()),
+                state=self.state,
+                redirect=protocolhandler.redirect
+            )
+        )
 
     def authorize(self, payload):
-        # Handle OAuth authorization code callback. Returns access token if successful, otherwise raises CredentialsError
+        # Handle OAuth authorization code callback.
+        # Returns access token if successful, otherwise raises CredentialsError
         if '?' not in payload:
-            print('Auth\tMalformed response "%s"' % payload)
+            print('Auth\tMalformed response {!r}'.format(payload))
             raise CredentialsError()  # Not well formed
 
-        data = urllib.parse.parse_qs(payload[payload.index('?')+1:])
+        data = urllib.parse.parse_qs(payload[payload.index('?') + 1:])
         if not self.state or not data.get('state') or data['state'][0] != self.state:
-            print('Auth\tUnexpected response "%s"' % payload)
+            print('Auth\tUnexpected response {!r}'.format(payload))
             raise CredentialsError()  # Unexpected reply
 
         if not data.get('code'):
-            print('Auth\tNegative response "%s"' % payload)
+            print('Auth\tNegative response {!r}'.format(payload))
+
+            # TODO(A_D): there should be a cleaner way to do this rather than raising in every if
+            #            Additionally, this is basically the same code as seen below, helper method perhaps?
             if data.get('error_description'):
-                raise CredentialsError('Error: %s' % data['error_description'][0])
+                raise CredentialsError('Error: {!r}'.format(data['error_description'][0]))
 
             elif data.get('error'):
-                raise CredentialsError('Error: %s' % data['error'][0])
+                raise CredentialsError('Error: {!r}'.format(data['error'][0]))
 
             elif data.get('message'):
-                raise CredentialsError('Error: %s' % data['message'][0])
+                raise CredentialsError('Error: {!r}'.format(data['message'][0]))
 
             else:
                 raise CredentialsError()
@@ -252,7 +267,7 @@ class Auth(object):
             r = self.session.post(SERVER_AUTH + URL_TOKEN, data=data, timeout=auth_timeout)
             data = r.json()
             if r.status_code == requests.codes.ok:
-                print('Auth\tNew token for %s' % self.cmdr)
+                print('Auth\tNew token for {}'.format(self.cmdr))
                 cmdrs = config.get('cmdrs')
                 idx = cmdrs.index(self.cmdr)
                 tokens = config.get('fdev_apikeys') or []
@@ -264,30 +279,30 @@ class Auth(object):
                 return data.get('access_token')
 
         except:
-            print('Auth\tCan\'t get token for %s' % self.cmdr)
+            print('Auth\tCan\'t get token for {}'.format(self.cmdr))
             print_exc()
             if r:
                 self.dump(r)
 
-            raise CredentialsError()
+            raise CredentialsError()  # TODO(A_D): Probably give more info about the error here
 
-        print('Auth\tCan\'t get token for %s' % self.cmdr)
+        print('Auth\tCan\'t get token for {}'.format(self.cmdr))
         self.dump(r)
         if data.get('error_description'):
-            raise CredentialsError('Error: %s' % data['error_description'])
+            raise CredentialsError('Error: {!r}'.format(data['error_description']))
 
         elif data.get('error'):
-            raise CredentialsError('Error: %s' % data['error'])
+            raise CredentialsError('Error: {!r}'.format(data['error']))
 
         elif data.get('message'):
-            raise CredentialsError('Error: %s' % data['message'])
+            raise CredentialsError('Error: {!r}'.format(data['message']))
 
         else:
             raise CredentialsError()
 
     @staticmethod
     def invalidate(cmdr):
-        print('Auth\tInvalidated token for %s' % cmdr)
+        print('Auth\tInvalidated token for {}'.format(cmdr))
         cmdrs = config.get('cmdrs')
         idx = cmdrs.index(cmdr)
         tokens = config.get('fdev_apikeys') or []
@@ -297,7 +312,7 @@ class Auth(object):
         config.save()  # Save settings now for use by command-line app
 
     def dump(self, r):
-        print('Auth\t' + r.url, r.status_code, r.reason and r.reason or 'None', r.text)
+        print('Auth\t' + r.url, r.status_code, r.reason if r.reason else 'None', r.text)
 
     def base64URLEncode(self, text):
         return base64.urlsafe_b64encode(text).decode().replace('=', '')
@@ -372,8 +387,8 @@ class Session(object):
 
     def start(self, access_token):
         self.session = requests.Session()
-        self.session.headers['Authorization'] = 'Bearer %s' % access_token
-        self.session.headers['User-Agent'] = 'EDCD-%s-%s' % (appname, appversion)
+        self.session.headers['Authorization'] = 'Bearer {}'.format(access_token)
+        self.session.headers['User-Agent'] = 'EDCD-{appname}-{version}'.format(appname=appname, version=appversion)
         self.state = Session.STATE_OK
 
     def query(self, endpoint):
@@ -504,7 +519,14 @@ def fixup(data):
         for thing in ['buyPrice', 'sellPrice', 'demand', 'demandBracket', 'stock', 'stockBracket']:
             if not isinstance(commodity.get(thing), numbers.Number):
                 if __debug__:
-                    print('Invalid "%s":"%s" (%s) for "%s"' % (thing, commodity.get(thing), type(commodity.get(thing)), commodity.get('name', '')))
+                    print(
+                        'Invalid {!r}:{!r} ({}) for {!r}'.format(
+                            thing,
+                            commodity.get(thing),
+                            type(commodity.get(thing)),
+                            commodity.get('name', '')
+                        )
+                    )
                 break
 
         else:
@@ -520,19 +542,19 @@ def fixup(data):
 
             elif not commodity.get('categoryname'):
                 if __debug__:
-                    print('Missing "categoryname" for "%s"' % commodity.get('name', ''))
+                    print('Missing "categoryname" for {!r}'.format(commodity.get('name', '')))
 
             elif not commodity.get('name'):
                 if __debug__:
-                    print('Missing "name" for a commodity in "%s"' % commodity.get('categoryname', ''))
+                    print('Missing "name" for a commodity in {!r}'.format(commodity.get('categoryname', '')))
 
             elif not commodity['demandBracket'] in range(4):
                 if __debug__:
-                    print('Invalid "demandBracket":"%s" for "%s"' % (commodity['demandBracket'], commodity['name']))
+                    print('Invalid "demandBracket":{!r} for {!r}'.format(commodity['demandBracket'], commodity['name']))
 
             elif not commodity['stockBracket'] in range(4):
                 if __debug__:
-                    print('Invalid "stockBracket":"%s" for "%s"' % (commodity['stockBracket'], commodity['name']))
+                    print('Invalid "stockBracket":{!r} for {!r}'.format(commodity['stockBracket'], commodity['name']))
 
             else:
                 # Rewrite text fields