From ce9dc56048f588c90c69035c634830704b420ae5 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 7 Oct 2024 10:44:18 +0200 Subject: [PATCH] modernize --- Examples/Announce.py | 14 +- Examples/Broadcast.py | 6 +- Examples/Buffer.py | 16 +- Examples/Channel.py | 23 +- Examples/Echo.py | 45 ++-- Examples/Filetransfer.py | 38 ++-- Examples/Identify.py | 25 +-- Examples/Link.py | 20 +- Examples/Minimal.py | 6 +- Examples/Ratchets.py | 45 ++-- Examples/Request.py | 18 +- Examples/Speedtest.py | 28 ++- RNS/Buffer.py | 8 +- RNS/Channel.py | 28 +-- RNS/Cryptography/Fernet.py | 4 +- RNS/Cryptography/HMAC.py | 8 +- RNS/Cryptography/PKCS7.py | 2 +- RNS/Cryptography/Provider.py | 2 +- RNS/Cryptography/SHA256.py | 6 +- RNS/Cryptography/SHA512.py | 6 +- RNS/Cryptography/__init__.py | 2 +- RNS/Cryptography/aes/aes.py | 6 +- RNS/Cryptography/pure25519/basic.py | 4 +- RNS/Cryptography/pure25519/ed25519_oop.py | 6 +- RNS/Cryptography/pure25519/eddsa.py | 6 +- RNS/Destination.py | 30 +-- RNS/Identity.py | 66 +++--- RNS/Interfaces/AX25KISSInterface.py | 42 ++-- RNS/Interfaces/Android/KISSInterface.py | 46 ++-- RNS/Interfaces/Android/RNodeInterface.py | 186 +++++++-------- RNS/Interfaces/Android/SerialInterface.py | 30 +-- RNS/Interfaces/Android/__init__.py | 2 +- RNS/Interfaces/AutoInterface.py | 72 +++--- RNS/Interfaces/I2PInterface.py | 126 +++++------ RNS/Interfaces/Interface.py | 8 +- RNS/Interfaces/KISSInterface.py | 38 ++-- RNS/Interfaces/LocalInterface.py | 28 +-- RNS/Interfaces/PipeInterface.py | 24 +- RNS/Interfaces/RNodeInterface.py | 128 +++++------ RNS/Interfaces/RNodeMultiInterface.py | 138 ++++++------ RNS/Interfaces/SerialInterface.py | 22 +- RNS/Interfaces/TCPInterface.py | 48 ++-- RNS/Interfaces/UDPInterface.py | 4 +- RNS/Interfaces/__init__.py | 2 +- RNS/Link.py | 74 +++--- RNS/Packet.py | 20 +- RNS/Resource.py | 50 ++--- RNS/Reticulum.py | 70 +++--- RNS/Transport.py | 262 +++++++++++----------- RNS/Utilities/__init__.py | 2 +- RNS/Utilities/rncp.py | 128 +++++------ RNS/Utilities/rnid.py | 132 +++++------ RNS/Utilities/rnir.py | 2 +- RNS/Utilities/rnodeconf.py | 58 ++--- RNS/Utilities/rnpath.py | 58 ++--- RNS/Utilities/rnprobe.py | 38 ++-- RNS/Utilities/rnsd.py | 6 +- RNS/Utilities/rnstatus.py | 16 +- RNS/Utilities/rnx.py | 86 +++---- RNS/__init__.py | 20 +- RNS/vendor/__init__.py | 2 +- RNS/vendor/configobj.py | 120 +++++----- RNS/vendor/i2plib/aiosam.py | 12 +- RNS/vendor/i2plib/sam.py | 28 +-- RNS/vendor/i2plib/tunnel.py | 9 +- RNS/vendor/i2plib/utils.py | 2 +- RNS/vendor/ifaddr/__init__.py | 2 +- RNS/vendor/ifaddr/_posix.py | 2 +- RNS/vendor/ifaddr/_shared.py | 12 +- RNS/vendor/ifaddr/niwrapper.py | 2 +- RNS/vendor/six.py | 55 +++-- RNS/vendor/umsgpack.py | 70 +++--- docs/source/conf.py | 4 +- setup.py | 6 +- tests/channel.py | 6 +- tests/hashes.py | 24 +- tests/identity.py | 30 +-- tests/link.py | 80 +++---- 78 files changed, 1414 insertions(+), 1486 deletions(-) diff --git a/Examples/Announce.py b/Examples/Announce.py index 69c94cb..5b0a3af 100644 --- a/Examples/Announce.py +++ b/Examples/Announce.py @@ -93,9 +93,7 @@ def announceLoop(destination_1, destination_2): # Send the announce including the app data destination_1.announce(app_data=fruit.encode("utf-8")) RNS.log( - "Sent announce from "+ - RNS.prettyhexrep(destination_1.hash)+ - " ("+destination_1.name+")" + f"Sent announce from {RNS.prettyhexrep(destination_1.hash)} ({destination_1.name})" ) # Randomly select a noble gas @@ -104,9 +102,7 @@ def announceLoop(destination_1, destination_2): # Send the announce including the app data destination_2.announce(app_data=noble_gas.encode("utf-8")) RNS.log( - "Sent announce from "+ - RNS.prettyhexrep(destination_2.hash)+ - " ("+destination_2.name+")" + f"Sent announce from {RNS.prettyhexrep(destination_2.hash)} ({destination_2.name})" ) # We will need to define an announce handler class that @@ -126,14 +122,12 @@ class ExampleAnnounceHandler: # and cannot use wildcards. def received_announce(self, destination_hash, announced_identity, app_data): RNS.log( - "Received an announce from "+ - RNS.prettyhexrep(destination_hash) + f"Received an announce from {RNS.prettyhexrep(destination_hash)}" ) if app_data: RNS.log( - "The announce contained the following app data: "+ - app_data.decode("utf-8") + f"The announce contained the following app data: {app_data.decode('utf-8')}" ) ########################################################## diff --git a/Examples/Broadcast.py b/Examples/Broadcast.py index 76acc70..423d759 100644 --- a/Examples/Broadcast.py +++ b/Examples/Broadcast.py @@ -48,15 +48,13 @@ def program_setup(configpath, channel=None): def packet_callback(data, packet): # Simply print out the received data print("") - print("Received data: "+data.decode("utf-8")+"\r\n> ", end="") + print(f"Received data: {data.decode('utf-8')}\r\n> ", end="") sys.stdout.flush() def broadcastLoop(destination): # Let the user know that everything is ready RNS.log( - "Broadcast example "+ - RNS.prettyhexrep(destination.hash)+ - " running, enter text and hit enter to broadcast (Ctrl-C to quit)" + f"Broadcast example {RNS.prettyhexrep(destination.hash)} running, enter text and hit enter to broadcast (Ctrl-C to quit)" ) # We enter a loop that runs until the users exits. diff --git a/Examples/Buffer.py b/Examples/Buffer.py index 6805184..7d26ce1 100644 --- a/Examples/Buffer.py +++ b/Examples/Buffer.py @@ -61,9 +61,7 @@ def server(configpath): def server_loop(destination): # Let the user know that everything is ready RNS.log( - "Link buffer example "+ - RNS.prettyhexrep(destination.hash)+ - " running, waiting for a connection." + f"Link buffer example {RNS.prettyhexrep(destination.hash)} running, waiting for a connection." ) RNS.log("Hit enter to manually send an announce (Ctrl-C to quit)") @@ -75,7 +73,7 @@ def server_loop(destination): while True: entered = input() destination.announce() - RNS.log("Sent announce from "+RNS.prettyhexrep(destination.hash)) + RNS.log(f"Sent announce from {RNS.prettyhexrep(destination.hash)}") # When a client establishes a link to our server # destination, this function will be called with @@ -120,9 +118,9 @@ def server_buffer_ready(ready_bytes: int): data = latest_buffer.read(ready_bytes) data = data.decode("utf-8") - RNS.log("Received data over the buffer: " + data) + RNS.log(f"Received data over the buffer: {data}") - reply_message = "I received \""+data+"\" over the buffer" + reply_message = f"I received \"{data}\" over the buffer" reply_message = reply_message.encode("utf-8") latest_buffer.write(reply_message) latest_buffer.flush() @@ -151,7 +149,7 @@ def client(destination_hexhash, configpath): dest_len = (RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2 if len(destination_hexhash) != dest_len: raise ValueError( - "Destination length is invalid, must be {hex} hexadecimal characters ({byte} bytes).".format(hex=dest_len, byte=dest_len//2) + f"Destination length is invalid, must be {dest_len} hexadecimal characters ({dest_len // 2} bytes)." ) destination_hash = bytes.fromhex(destination_hexhash) @@ -223,7 +221,7 @@ def client_loop(): except Exception as e: - RNS.log("Error while sending data over the link buffer: "+str(e)) + RNS.log(f"Error while sending data over the link buffer: {e}") should_quit = True server_link.teardown() @@ -262,7 +260,7 @@ def link_closed(link): def client_buffer_ready(ready_bytes: int): global buffer data = buffer.read(ready_bytes) - RNS.log("Received data over the link buffer: " + data.decode("utf-8")) + RNS.log(f"Received data over the link buffer: {data.decode('utf-8')}") print("> ", end=" ") sys.stdout.flush() diff --git a/Examples/Channel.py b/Examples/Channel.py index c4ce315..b1c6b39 100644 --- a/Examples/Channel.py +++ b/Examples/Channel.py @@ -124,9 +124,7 @@ def server(configpath): def server_loop(destination): # Let the user know that everything is ready RNS.log( - "Link example "+ - RNS.prettyhexrep(destination.hash)+ - " running, waiting for a connection." + f"Link example {RNS.prettyhexrep(destination.hash)} running, waiting for a connection." ) RNS.log("Hit enter to manually send an announce (Ctrl-C to quit)") @@ -138,7 +136,7 @@ def server_loop(destination): while True: entered = input() destination.announce() - RNS.log("Sent announce from "+RNS.prettyhexrep(destination.hash)) + RNS.log(f"Sent announce from {RNS.prettyhexrep(destination.hash)}") # When a client establishes a link to our server # destination, this function will be called with @@ -176,9 +174,9 @@ def server_message_received(message): # # if isinstance(message, StringMessage): - RNS.log("Received data on the link: " + message.data + " (message created at " + str(message.timestamp) + ")") + RNS.log(f"Received data on the link: {message.data} (message created at {message.timestamp})") - reply_message = StringMessage("I received \""+message.data+"\" over the link") + reply_message = StringMessage(f"I received \"{message.data}\" over the link") latest_client_link.get_channel().send(reply_message) # Incoming messages are sent to each message @@ -206,7 +204,7 @@ def client(destination_hexhash, configpath): dest_len = (RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2 if len(destination_hexhash) != dest_len: raise ValueError( - "Destination length is invalid, must be {hex} hexadecimal characters ({byte} bytes).".format(hex=dest_len, byte=dest_len//2) + f"Destination length is invalid, must be {dest_len} hexadecimal characters ({dest_len // 2} bytes)." ) destination_hash = bytes.fromhex(destination_hexhash) @@ -280,17 +278,14 @@ def client_loop(): channel.send(message) else: RNS.log( - "Cannot send this packet, the data size of "+ - str(packed_size)+" bytes exceeds the link packet MDU of "+ - str(channel.MDU)+" bytes", + f"Cannot send this packet, the data size of {packed_size} bytes exceeds the link packet MDU of {channel.MDU} bytes", RNS.LOG_ERROR ) else: - RNS.log("Channel is not ready to send, please wait for " + - "pending messages to complete.", RNS.LOG_ERROR) + RNS.log(f"Channel is not ready to send, please wait for pending messages to complete.", RNS.LOG_ERROR) except Exception as e: - RNS.log("Error while sending data over the link: "+str(e)) + RNS.log(f"Error while sending data over the link: {e}") should_quit = True server_link.teardown() @@ -329,7 +324,7 @@ def link_closed(link): # simply print out the data. def client_message_received(message): if isinstance(message, StringMessage): - RNS.log("Received data on the link: " + message.data + " (message created at " + str(message.timestamp) + ")") + RNS.log(f"Received data on the link: {message.data} (message created at {message.timestamp})") print("> ", end=" ") sys.stdout.flush() diff --git a/Examples/Echo.py b/Examples/Echo.py index e5b3930..ed377b2 100644 --- a/Examples/Echo.py +++ b/Examples/Echo.py @@ -64,9 +64,7 @@ def server(configpath): def announceLoop(destination): # Let the user know that everything is ready RNS.log( - "Echo server "+ - RNS.prettyhexrep(destination.hash)+ - " running, hit enter to manually send an announce (Ctrl-C to quit)" + f"Echo server {RNS.prettyhexrep(destination.hash)} running, hit enter to manually send an announce (Ctrl-C to quit)" ) # We enter a loop that runs until the users exits. @@ -76,7 +74,7 @@ def announceLoop(destination): while True: entered = input() destination.announce() - RNS.log("Sent announce from "+RNS.prettyhexrep(destination.hash)) + RNS.log(f"Sent announce from {RNS.prettyhexrep(destination.hash)}") def server_callback(message, packet): @@ -93,19 +91,19 @@ def server_callback(message, packet): reception_snr = reticulum.get_packet_snr(packet.packet_hash) if reception_rssi != None: - reception_stats += " [RSSI "+str(reception_rssi)+" dBm]" + reception_stats += f" [RSSI {reception_rssi} dBm]" if reception_snr != None: - reception_stats += " [SNR "+str(reception_snr)+" dBm]" + reception_stats += f" [SNR {reception_snr} dBm]" else: if packet.rssi != None: - reception_stats += " [RSSI "+str(packet.rssi)+" dBm]" + reception_stats += f" [RSSI {packet.rssi} dBm]" if packet.snr != None: - reception_stats += " [SNR "+str(packet.snr)+" dB]" + reception_stats += f" [SNR {packet.snr} dB]" - RNS.log("Received packet from echo client, proof sent"+reception_stats) + RNS.log(f"Received packet from echo client, proof sent{reception_stats}") ########################################################## @@ -123,13 +121,13 @@ def client(destination_hexhash, configpath, timeout=None): dest_len = (RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2 if len(destination_hexhash) != dest_len: raise ValueError( - "Destination length is invalid, must be {hex} hexadecimal characters ({byte} bytes).".format(hex=dest_len, byte=dest_len//2) + f"Destination length is invalid, must be {dest_len} hexadecimal characters ({dest_len // 2} bytes)." ) destination_hash = bytes.fromhex(destination_hexhash) except Exception as e: RNS.log("Invalid destination entered. Check your input!") - RNS.log(str(e)+"\n") + RNS.log(f"{e}\n") exit() # We must first initialise Reticulum @@ -142,9 +140,7 @@ def client(destination_hexhash, configpath, timeout=None): # Tell the user that the client is ready! RNS.log( - "Echo client ready, hit enter to send echo request to "+ - destination_hexhash+ - " (Ctrl-C to quit)" + f"Echo client ready, hit enter to send echo request to {destination_hexhash} (Ctrl-C to quit)" ) # We enter a loop that runs until the user exits. @@ -205,7 +201,7 @@ def client(destination_hexhash, configpath, timeout=None): packet_receipt.set_delivery_callback(packet_delivered) # Tell the user that the echo request was sent - RNS.log("Sent echo request to "+RNS.prettyhexrep(request_destination.hash)) + RNS.log(f"Sent echo request to {RNS.prettyhexrep(request_destination.hash)}") else: # If we do not know this destination, tell the # user to wait for an announce to arrive. @@ -222,10 +218,10 @@ def packet_delivered(receipt): rtt = receipt.get_rtt() if (rtt >= 1): rtt = round(rtt, 3) - rttstring = str(rtt)+" seconds" + rttstring = f"{rtt} seconds" else: rtt = round(rtt*1000, 3) - rttstring = str(rtt)+" milliseconds" + rttstring = f"{rtt} milliseconds" reception_stats = "" if reticulum.is_connected_to_shared_instance: @@ -233,30 +229,27 @@ def packet_delivered(receipt): reception_snr = reticulum.get_packet_snr(receipt.proof_packet.packet_hash) if reception_rssi != None: - reception_stats += " [RSSI "+str(reception_rssi)+" dBm]" + reception_stats += f" [RSSI {reception_rssi} dBm]" if reception_snr != None: - reception_stats += " [SNR "+str(reception_snr)+" dB]" + reception_stats += f" [SNR {reception_snr} dB]" else: if receipt.proof_packet != None: if receipt.proof_packet.rssi != None: - reception_stats += " [RSSI "+str(receipt.proof_packet.rssi)+" dBm]" + reception_stats += f" [RSSI {receipt.proof_packet.rssi} dBm]" if receipt.proof_packet.snr != None: - reception_stats += " [SNR "+str(receipt.proof_packet.snr)+" dB]" + reception_stats += f" [SNR {receipt.proof_packet.snr} dB]" RNS.log( - "Valid reply received from "+ - RNS.prettyhexrep(receipt.destination.hash)+ - ", round-trip time is "+rttstring+ - reception_stats + f"Valid reply received from {RNS.prettyhexrep(receipt.destination.hash)}, round-trip time is {rttstring}{reception_stats}" ) # This function is called if a packet times out. def packet_timed_out(receipt): if receipt.status == RNS.PacketReceipt.FAILED: - RNS.log("Packet "+RNS.prettyhexrep(receipt.hash)+" timed out") + RNS.log(f"Packet {RNS.prettyhexrep(receipt.hash)} timed out") ########################################################## diff --git a/Examples/Filetransfer.py b/Examples/Filetransfer.py index 98c4c7a..79081d1 100644 --- a/Examples/Filetransfer.py +++ b/Examples/Filetransfer.py @@ -73,7 +73,7 @@ def server(configpath, path): def announceLoop(destination): # Let the user know that everything is ready - RNS.log("File server "+RNS.prettyhexrep(destination.hash)+" running") + RNS.log(f"File server {RNS.prettyhexrep(destination.hash)} running") RNS.log("Hit enter to manually send an announce (Ctrl-C to quit)") # We enter a loop that runs until the users exits. @@ -83,7 +83,7 @@ def announceLoop(destination): while True: entered = input() destination.announce() - RNS.log("Sent announce from "+RNS.prettyhexrep(destination.hash)) + RNS.log(f"Sent announce from {RNS.prettyhexrep(destination.hash)}") # Here's a convenience function for listing all files # in our served directory @@ -145,7 +145,7 @@ def client_request(message, packet): try: # If we have the requested file, we'll # read it and pack it as a resource - RNS.log("Client requested \""+filename+"\"") + RNS.log(f"Client requested \"{filename}\"") file = open(os.path.join(serve_path, filename), "rb") file_resource = RNS.Resource( @@ -158,7 +158,7 @@ def client_request(message, packet): except Exception as e: # If somethign went wrong, we close # the link - RNS.log("Error while reading file \""+filename+"\"", RNS.LOG_ERROR) + RNS.log(f"Error while reading file \"{filename}\"", RNS.LOG_ERROR) packet.link.teardown() raise e else: @@ -175,9 +175,9 @@ def resource_sending_concluded(resource): name = "resource" if resource.status == RNS.Resource.COMPLETE: - RNS.log("Done sending \""+name+"\" to client") + RNS.log(f"Done sending \"{name}\" to client") elif resource.status == RNS.Resource.FAILED: - RNS.log("Sending \""+name+"\" to client failed") + RNS.log(f"Sending \"{name}\" to client failed") def list_delivered(receipt): RNS.log("The file list was received by the client") @@ -218,7 +218,7 @@ def client(destination_hexhash, configpath): dest_len = (RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2 if len(destination_hexhash) != dest_len: raise ValueError( - "Destination length is invalid, must be {hex} hexadecimal characters ({byte} bytes).".format(hex=dest_len, byte=dest_len//2) + f"Destination length is invalid, must be {dest_len} hexadecimal characters ({dest_len // 2} bytes)." ) destination_hash = bytes.fromhex(destination_hexhash) @@ -293,7 +293,7 @@ def download(filename): request_packet.send() print("") - print(("Requested \""+filename+"\" from server, waiting for download to begin...")) + print(f"Requested \"{filename}\" from server, waiting for download to begin...") menu_mode = "download_started" # This function runs a simple menu for the user @@ -363,7 +363,7 @@ def print_menu(): while menu_mode == "downloading": global current_download percent = round(current_download.get_progress() * 100.0, 1) - print(("\rProgress: "+str(percent)+" % "), end=' ') + print(f'\rProgress: {percent} % ', end=' ') sys.stdout.flush() time.sleep(0.1) @@ -383,15 +383,15 @@ def print_menu(): # Print statistics hours, rem = divmod(download_time, 3600) minutes, seconds = divmod(rem, 60) - timestring = "{:0>2}:{:0>2}:{:05.2f}".format(int(hours),int(minutes),seconds) + timestring = f"{int(hours):0>2}:{int(minutes):0>2}:{seconds:05.2f}" print("") print("") print("--- Statistics -----") - print("\tTime taken : "+timestring) - print("\tFile size : "+size_str(file_size)) - print("\tData transferred : "+size_str(transfer_size)) - print("\tEffective rate : "+size_str(file_size/download_time, suffix='b')+"/s") - print("\tTransfer rate : "+size_str(transfer_size/download_time, suffix='b')+"/s") + print(f"\tTime taken : {timestring}") + print(f"\tFile size : {size_str(file_size)}") + print(f"\tData transferred : {size_str(transfer_size)}") + print(f"\tEffective rate : {size_str(file_size / download_time, suffix='b')}/s") + print(f"\tTransfer rate : {size_str(transfer_size / download_time, suffix='b')}/s") print("") print("The download completed! Press enter to return to the menu.") print("") @@ -412,7 +412,7 @@ def print_filelist(): global server_files print("Files on server:") for index,file in enumerate(server_files): - print("\t("+str(index)+")\t"+file) + print(f"\t({index})\t{file}") def filelist_received(filelist_data, packet): global server_files, menu_mode @@ -509,7 +509,7 @@ def download_concluded(resource): counter = 0 while os.path.isfile(saved_filename): counter += 1 - saved_filename = current_filename+"."+str(counter) + saved_filename = f"{current_filename}.{counter}" try: file = open(saved_filename, "wb") @@ -534,9 +534,9 @@ def size_str(num, suffix='B'): for unit in units: if abs(num) < 1024.0: - return "%3.2f %s%s" % (num, unit, suffix) + return f"{num:3.2f} {unit}{suffix}" num /= 1024.0 - return "%.2f %s%s" % (num, last_unit, suffix) + return f"{num:.2f} {last_unit}{suffix}" # A convenience function for clearing the screen def clear_screen(): diff --git a/Examples/Identify.py b/Examples/Identify.py index 45ba18e..6bfa49d 100644 --- a/Examples/Identify.py +++ b/Examples/Identify.py @@ -53,9 +53,7 @@ def server(configpath): def server_loop(destination): # Let the user know that everything is ready RNS.log( - "Link identification example "+ - RNS.prettyhexrep(destination.hash)+ - " running, waiting for a connection." + f"Link identification example {RNS.prettyhexrep(destination.hash)} running, waiting for a connection." ) RNS.log("Hit enter to manually send an announce (Ctrl-C to quit)") @@ -67,7 +65,7 @@ def server_loop(destination): while True: entered = input() destination.announce() - RNS.log("Sent announce from "+RNS.prettyhexrep(destination.hash)) + RNS.log(f"Sent announce from {RNS.prettyhexrep(destination.hash)}") # When a client establishes a link to our server # destination, this function will be called with @@ -85,7 +83,7 @@ def client_disconnected(link): RNS.log("Client disconnected") def remote_identified(link, identity): - RNS.log("Remote identified as: "+str(identity)) + RNS.log(f"Remote identified as: {identity}") def server_packet_received(message, packet): global latest_client_link @@ -100,9 +98,9 @@ def server_packet_received(message, packet): # that connected. text = message.decode("utf-8") - RNS.log("Received data from "+remote_peer+": "+text) + RNS.log(f"Received data from {remote_peer}: {text}") - reply_text = "I received \""+text+"\" over the link from "+remote_peer + reply_text = f"I received \"{text}\" over the link from {remote_peer}" reply_data = reply_text.encode("utf-8") RNS.Packet(latest_client_link, reply_data).send() @@ -127,7 +125,7 @@ def client(destination_hexhash, configpath): dest_len = (RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2 if len(destination_hexhash) != dest_len: raise ValueError( - "Destination length is invalid, must be {hex} hexadecimal characters ({byte} bytes).".format(hex=dest_len, byte=dest_len//2) + f"Destination length is invalid, must be {dest_len} hexadecimal characters ({dest_len // 2} bytes)." ) destination_hash = bytes.fromhex(destination_hexhash) @@ -141,8 +139,7 @@ def client(destination_hexhash, configpath): # Create a new client identity client_identity = RNS.Identity() RNS.log( - "Client created new identity "+ - str(client_identity) + f"Client created new identity {client_identity}" ) # Check if we know a path to the destination @@ -210,14 +207,12 @@ def client_loop(): RNS.Packet(server_link, data).send() else: RNS.log( - "Cannot send this packet, the data size of "+ - str(len(data))+" bytes exceeds the link packet MDU of "+ - str(RNS.Link.MDU)+" bytes", + f"Cannot send this packet, the data size of {len(data)} bytes exceeds the link packet MDU of {RNS.Link.MDU} bytes", RNS.LOG_ERROR ) except Exception as e: - RNS.log("Error while sending data over the link: "+str(e)) + RNS.log(f"Error while sending data over the link: {e}") should_quit = True server_link.teardown() @@ -253,7 +248,7 @@ def link_closed(link): # simply print out the data. def client_packet_received(message, packet): text = message.decode("utf-8") - RNS.log("Received data on the link: "+text) + RNS.log(f"Received data on the link: {text}") print("> ", end=" ") sys.stdout.flush() diff --git a/Examples/Link.py b/Examples/Link.py index 6b3210c..6df8f3e 100644 --- a/Examples/Link.py +++ b/Examples/Link.py @@ -53,9 +53,7 @@ def server(configpath): def server_loop(destination): # Let the user know that everything is ready RNS.log( - "Link example "+ - RNS.prettyhexrep(destination.hash)+ - " running, waiting for a connection." + f"Link example {RNS.prettyhexrep(destination.hash)} running, waiting for a connection." ) RNS.log("Hit enter to manually send an announce (Ctrl-C to quit)") @@ -67,7 +65,7 @@ def server_loop(destination): while True: entered = input() destination.announce() - RNS.log("Sent announce from "+RNS.prettyhexrep(destination.hash)) + RNS.log(f"Sent announce from {RNS.prettyhexrep(destination.hash)}") # When a client establishes a link to our server # destination, this function will be called with @@ -90,9 +88,9 @@ def server_packet_received(message, packet): # it will all be directed to the last client # that connected. text = message.decode("utf-8") - RNS.log("Received data on the link: "+text) + RNS.log(f"Received data on the link: {text}") - reply_text = "I received \""+text+"\" over the link" + reply_text = f"I received \"{text}\" over the link" reply_data = reply_text.encode("utf-8") RNS.Packet(latest_client_link, reply_data).send() @@ -113,7 +111,7 @@ def client(destination_hexhash, configpath): dest_len = (RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2 if len(destination_hexhash) != dest_len: raise ValueError( - "Destination length is invalid, must be {hex} hexadecimal characters ({byte} bytes).".format(hex=dest_len, byte=dest_len//2) + f"Destination length is invalid, must be {dest_len} hexadecimal characters ({dest_len // 2} bytes)." ) destination_hash = bytes.fromhex(destination_hexhash) @@ -189,14 +187,12 @@ def client_loop(): RNS.Packet(server_link, data).send() else: RNS.log( - "Cannot send this packet, the data size of "+ - str(len(data))+" bytes exceeds the link packet MDU of "+ - str(RNS.Link.MDU)+" bytes", + f"Cannot send this packet, the data size of {len(data)} bytes exceeds the link packet MDU of {RNS.Link.MDU} bytes", RNS.LOG_ERROR ) except Exception as e: - RNS.log("Error while sending data over the link: "+str(e)) + RNS.log(f"Error while sending data over the link: {e}") should_quit = True server_link.teardown() @@ -230,7 +226,7 @@ def link_closed(link): # simply print out the data. def client_packet_received(message, packet): text = message.decode("utf-8") - RNS.log("Received data on the link: "+text) + RNS.log(f"Received data on the link: {text}") print("> ", end=" ") sys.stdout.flush() diff --git a/Examples/Minimal.py b/Examples/Minimal.py index 76f78c6..6f33893 100644 --- a/Examples/Minimal.py +++ b/Examples/Minimal.py @@ -51,9 +51,7 @@ def program_setup(configpath): def announceLoop(destination): # Let the user know that everything is ready RNS.log( - "Minimal example "+ - RNS.prettyhexrep(destination.hash)+ - " running, hit enter to manually send an announce (Ctrl-C to quit)" + f"Minimal example {RNS.prettyhexrep(destination.hash)} running, hit enter to manually send an announce (Ctrl-C to quit)" ) # We enter a loop that runs until the users exits. @@ -63,7 +61,7 @@ def announceLoop(destination): while True: entered = input() destination.announce() - RNS.log("Sent announce from "+RNS.prettyhexrep(destination.hash)) + RNS.log(f"Sent announce from {RNS.prettyhexrep(destination.hash)}") ########################################################## diff --git a/Examples/Ratchets.py b/Examples/Ratchets.py index 9c71c90..b690de4 100644 --- a/Examples/Ratchets.py +++ b/Examples/Ratchets.py @@ -75,9 +75,7 @@ def server(configpath): def announceLoop(destination): # Let the user know that everything is ready RNS.log( - "Ratcheted echo server "+ - RNS.prettyhexrep(destination.hash)+ - " running, hit enter to manually send an announce (Ctrl-C to quit)" + f"Ratcheted echo server {RNS.prettyhexrep(destination.hash)} running, hit enter to manually send an announce (Ctrl-C to quit)" ) # We enter a loop that runs until the users exits. @@ -87,7 +85,7 @@ def announceLoop(destination): while True: entered = input() destination.announce() - RNS.log("Sent announce from "+RNS.prettyhexrep(destination.hash)) + RNS.log(f"Sent announce from {RNS.prettyhexrep(destination.hash)}") def server_callback(message, packet): @@ -104,19 +102,19 @@ def server_callback(message, packet): reception_snr = reticulum.get_packet_snr(packet.packet_hash) if reception_rssi != None: - reception_stats += " [RSSI "+str(reception_rssi)+" dBm]" + reception_stats += f" [RSSI {reception_rssi} dBm]" if reception_snr != None: - reception_stats += " [SNR "+str(reception_snr)+" dBm]" + reception_stats += f" [SNR {reception_snr} dBm]" else: if packet.rssi != None: - reception_stats += " [RSSI "+str(packet.rssi)+" dBm]" + reception_stats += f" [RSSI {packet.rssi} dBm]" if packet.snr != None: - reception_stats += " [SNR "+str(packet.snr)+" dB]" + reception_stats += f" [SNR {packet.snr} dB]" - RNS.log("Received packet from echo client, proof sent"+reception_stats) + RNS.log(f"Received packet from echo client, proof sent{reception_stats}") ########################################################## @@ -134,13 +132,13 @@ def client(destination_hexhash, configpath, timeout=None): dest_len = (RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2 if len(destination_hexhash) != dest_len: raise ValueError( - "Destination length is invalid, must be {hex} hexadecimal characters ({byte} bytes).".format(hex=dest_len, byte=dest_len//2) + f"Destination length is invalid, must be {dest_len} hexadecimal characters ({dest_len // 2} bytes)." ) destination_hash = bytes.fromhex(destination_hexhash) except Exception as e: RNS.log("Invalid destination entered. Check your input!") - RNS.log(str(e)+"\n") + RNS.log(f"{e}\n") exit() # We must first initialise Reticulum @@ -153,9 +151,7 @@ def client(destination_hexhash, configpath, timeout=None): # Tell the user that the client is ready! RNS.log( - "Echo client ready, hit enter to send echo request to "+ - destination_hexhash+ - " (Ctrl-C to quit)" + f"Echo client ready, hit enter to send echo request to {destination_hexhash} (Ctrl-C to quit)" ) # We enter a loop that runs until the user exits. @@ -217,7 +213,7 @@ def client(destination_hexhash, configpath, timeout=None): packet_receipt.set_delivery_callback(packet_delivered) # Tell the user that the echo request was sent - RNS.log("Sent echo request to "+RNS.prettyhexrep(request_destination.hash)) + RNS.log(f"Sent echo request to {RNS.prettyhexrep(request_destination.hash)}") else: # If we do not know this destination, tell the # user to wait for an announce to arrive. @@ -234,10 +230,10 @@ def packet_delivered(receipt): rtt = receipt.get_rtt() if (rtt >= 1): rtt = round(rtt, 3) - rttstring = str(rtt)+" seconds" + rttstring = f"{rtt} seconds" else: rtt = round(rtt*1000, 3) - rttstring = str(rtt)+" milliseconds" + rttstring = f"{rtt} milliseconds" reception_stats = "" if reticulum.is_connected_to_shared_instance: @@ -245,30 +241,27 @@ def packet_delivered(receipt): reception_snr = reticulum.get_packet_snr(receipt.proof_packet.packet_hash) if reception_rssi != None: - reception_stats += " [RSSI "+str(reception_rssi)+" dBm]" + reception_stats += f" [RSSI {reception_rssi} dBm]" if reception_snr != None: - reception_stats += " [SNR "+str(reception_snr)+" dB]" + reception_stats += f" [SNR {reception_snr} dB]" else: if receipt.proof_packet != None: if receipt.proof_packet.rssi != None: - reception_stats += " [RSSI "+str(receipt.proof_packet.rssi)+" dBm]" + reception_stats += f" [RSSI {receipt.proof_packet.rssi} dBm]" if receipt.proof_packet.snr != None: - reception_stats += " [SNR "+str(receipt.proof_packet.snr)+" dB]" + reception_stats += f" [SNR {receipt.proof_packet.snr} dB]" RNS.log( - "Valid reply received from "+ - RNS.prettyhexrep(receipt.destination.hash)+ - ", round-trip time is "+rttstring+ - reception_stats + f"Valid reply received from {RNS.prettyhexrep(receipt.destination.hash)}, round-trip time is {rttstring}{reception_stats}" ) # This function is called if a packet times out. def packet_timed_out(receipt): if receipt.status == RNS.PacketReceipt.FAILED: - RNS.log("Packet "+RNS.prettyhexrep(receipt.hash)+" timed out") + RNS.log(f"Packet {RNS.prettyhexrep(receipt.hash)} timed out") ########################################################## diff --git a/Examples/Request.py b/Examples/Request.py index ca8a993..774fe2e 100644 --- a/Examples/Request.py +++ b/Examples/Request.py @@ -24,7 +24,7 @@ APP_NAME = "example_utilities" latest_client_link = None def random_text_generator(path, data, request_id, link_id, remote_identity, requested_at): - RNS.log("Generating response to request "+RNS.prettyhexrep(request_id)+" on link "+RNS.prettyhexrep(link_id)) + RNS.log(f"Generating response to request {RNS.prettyhexrep(request_id)} on link {RNS.prettyhexrep(link_id)}") texts = ["They looked up", "On each full moon", "Becky was upset", "I’ll stay away from it", "The pet shop stocks everything"] return texts[random.randint(0, len(texts)-1)] @@ -67,9 +67,7 @@ def server(configpath): def server_loop(destination): # Let the user know that everything is ready RNS.log( - "Request example "+ - RNS.prettyhexrep(destination.hash)+ - " running, waiting for a connection." + f"Request example {RNS.prettyhexrep(destination.hash)} running, waiting for a connection." ) RNS.log("Hit enter to manually send an announce (Ctrl-C to quit)") @@ -81,7 +79,7 @@ def server_loop(destination): while True: entered = input() destination.announce() - RNS.log("Sent announce from "+RNS.prettyhexrep(destination.hash)) + RNS.log(f"Sent announce from {RNS.prettyhexrep(destination.hash)}") # When a client establishes a link to our server # destination, this function will be called with @@ -113,7 +111,7 @@ def client(destination_hexhash, configpath): dest_len = (RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2 if len(destination_hexhash) != dest_len: raise ValueError( - "Destination length is invalid, must be {hex} hexadecimal characters ({byte} bytes).".format(hex=dest_len, byte=dest_len//2) + f"Destination length is invalid, must be {dest_len} hexadecimal characters ({dest_len // 2} bytes)." ) destination_hash = bytes.fromhex(destination_hexhash) @@ -187,7 +185,7 @@ def client_loop(): except Exception as e: - RNS.log("Error while sending request over the link: "+str(e)) + RNS.log(f"Error while sending request over the link: {e}") should_quit = True server_link.teardown() @@ -195,13 +193,13 @@ def got_response(request_receipt): request_id = request_receipt.request_id response = request_receipt.response - RNS.log("Got response for request "+RNS.prettyhexrep(request_id)+": "+str(response)) + RNS.log(f"Got response for request {RNS.prettyhexrep(request_id)}: {response}") def request_received(request_receipt): - RNS.log("The request "+RNS.prettyhexrep(request_receipt.request_id)+" was received by the remote peer.") + RNS.log(f"The request {RNS.prettyhexrep(request_receipt.request_id)} was received by the remote peer.") def request_failed(request_receipt): - RNS.log("The request "+RNS.prettyhexrep(request_receipt.request_id)+" failed.") + RNS.log(f"The request {RNS.prettyhexrep(request_receipt.request_id)} failed.") # This function is called when a link diff --git a/Examples/Speedtest.py b/Examples/Speedtest.py index b66a556..4e564f0 100644 --- a/Examples/Speedtest.py +++ b/Examples/Speedtest.py @@ -62,9 +62,7 @@ def server(configpath): def server_loop(destination): # Let the user know that everything is ready RNS.log( - "Speedtest "+ - RNS.prettyhexrep(destination.hash)+ - " running, waiting for a connection." + f"Speedtest {RNS.prettyhexrep(destination.hash)} running, waiting for a connection." ) RNS.log("Hit enter to manually send an announce (Ctrl-C to quit)") @@ -76,7 +74,7 @@ def server_loop(destination): while True: entered = input() destination.announce() - RNS.log("Sent announce from "+RNS.prettyhexrep(destination.hash)) + RNS.log(f"Sent announce from {RNS.prettyhexrep(destination.hash)}") # When a client establishes a link to our server # destination, this function will be called with @@ -108,9 +106,9 @@ def size_str(num, suffix='B'): for unit in units: if abs(num) < 1024.0: - return "%3.2f %s%s" % (num, unit, suffix) + return f"{num:3.2f} {unit}{suffix}" num /= 1024.0 - return "%.2f %s%s" % (num, last_unit, suffix) + return f"{num:.2f} {last_unit}{suffix}" def server_packet_received(message, packet): @@ -134,14 +132,14 @@ def server_packet_received(message, packet): download_time = last_packet_at-first_packet_at hours, rem = divmod(download_time, 3600) minutes, seconds = divmod(rem, 60) - timestring = "{:0>2}:{:0>2}:{:05.2f}".format(int(hours),int(minutes),seconds) + timestring = f"{int(hours):0>2}:{int(minutes):0>2}:{seconds:05.2f}" print("") print("") print("--- Statistics -----") - print("\tTime taken : "+timestring) - print("\tData transferred : "+size_str(rcv_d)) - print("\tTransfer rate : "+size_str(rcv_d/download_time, suffix='b')+"/s") + print(f"\tTime taken : {timestring}") + print(f"\tData transferred : {size_str(rcv_d)}") + print(f"\tTransfer rate : {size_str(rcv_d / download_time, suffix='b')}/s") print("") sys.stdout.flush() @@ -169,7 +167,7 @@ def client(destination_hexhash, configpath): dest_len = (RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2 if len(destination_hexhash) != dest_len: raise ValueError( - "Destination length is invalid, must be {hex} hexadecimal characters ({byte} bytes).".format(hex=dest_len, byte=dest_len//2) + f"Destination length is invalid, must be {dest_len} hexadecimal characters ({dest_len // 2} bytes)." ) destination_hash = bytes.fromhex(destination_hexhash) @@ -260,13 +258,13 @@ def link_established(link): download_time = ended-started hours, rem = divmod(download_time, 3600) minutes, seconds = divmod(rem, 60) - timestring = "{:0>2}:{:0>2}:{:05.2f}".format(int(hours),int(minutes),seconds) + timestring = f"{int(hours):0>2}:{int(minutes):0>2}:{seconds:05.2f}" print("") print("") print("--- Statistics -----") - print("\tTime taken : "+timestring) - print("\tData transferred : "+size_str(data_sent)) - print("\tTransfer rate : "+size_str(data_sent/download_time, suffix='b')+"/s") + print(f"\tTime taken : {timestring}") + print(f"\tData transferred : {size_str(data_sent)}") + print(f"\tTransfer rate : {size_str(data_sent / download_time, suffix='b')}/s") print("") sys.stdout.flush() diff --git a/RNS/Buffer.py b/RNS/Buffer.py index c9a89a9..f260c16 100644 --- a/RNS/Buffer.py +++ b/RNS/Buffer.py @@ -65,7 +65,7 @@ class StreamDataMessage(MessageBase): raise ValueError("stream_id must be 0-16383") self.stream_id = stream_id self.compressed = compressed - self.data = data or bytes() + self.data = data or b'' self.eof = eof def pack(self) -> bytes: @@ -73,7 +73,7 @@ class StreamDataMessage(MessageBase): raise ValueError("stream_id") header_val = (0x3fff & self.stream_id) | (0x8000 if self.eof else 0x0000) | (0x4000 if self.compressed > 0 else 0x0000) - return bytes(struct.pack(">H", header_val) + (self.data if self.data else bytes())) + return bytes(struct.pack(">H", header_val) + (self.data if self.data else b'')) def unpack(self, raw): self.stream_id = struct.unpack(">H", raw[:2])[0] @@ -148,7 +148,7 @@ class RawChannelReader(RawIOBase, AbstractContextManager): try: threading.Thread(target=listener, name="Message Callback", args=[len(self._buffer)], daemon=True).start() except Exception as ex: - RNS.log("Error calling RawChannelReader(" + str(self._stream_id) + ") callback: " + str(ex), RNS.LOG_ERROR) + RNS.log(f"Error calling RawChannelReader({self._stream_id}) callback: {ex}", RNS.LOG_ERROR) return True return False @@ -264,7 +264,7 @@ class RawChannelWriter(RawIOBase, AbstractContextManager): time.sleep(0.05) self._eof = True - self.write(bytes()) + self.write(b'') def __enter__(self): return self diff --git a/RNS/Channel.py b/RNS/Channel.py index 47c11f6..5634471 100644 --- a/RNS/Channel.py +++ b/RNS/Channel.py @@ -168,7 +168,7 @@ class Envelope: Internal wrapper used to transport messages over a channel and track its state within the channel framework. """ - def unpack(self, message_factories: dict[int, Type]) -> MessageBase: + def unpack(self, message_factories: dict[int, type]) -> MessageBase: msgtype, self.sequence, length = struct.unpack(">HHH", self.raw[:6]) raw = self.raw[6:] ctor = message_factories.get(msgtype, None) @@ -282,7 +282,7 @@ class Channel(contextlib.AbstractContextManager): self._message_callbacks: [MessageCallbackType] = [] self._next_sequence = 0 self._next_rx_sequence = 0 - self._message_factories: dict[int, Type[MessageBase]] = {} + self._message_factories: dict[int, type[MessageBase]] = {} self._max_tries = 5 self.fast_rate_rounds = 0 self.medium_rate_rounds = 0 @@ -301,12 +301,12 @@ class Channel(contextlib.AbstractContextManager): def __enter__(self) -> Channel: return self - def __exit__(self, __exc_type: Type[BaseException] | None, __exc_value: BaseException | None, + def __exit__(self, __exc_type: type[BaseException] | None, __exc_value: BaseException | None, __traceback: TracebackType | None) -> bool | None: self._shutdown() return False - def register_message_type(self, message_class: Type[MessageBase]): + def register_message_type(self, message_class: type[MessageBase]): """ Register a message class for reception over a ``Channel``. @@ -316,7 +316,7 @@ class Channel(contextlib.AbstractContextManager): """ self._register_message_type(message_class, is_system_type=False) - def _register_message_type(self, message_class: Type[MessageBase], *, is_system_type: bool = False): + def _register_message_type(self, message_class: type[MessageBase], *, is_system_type: bool = False): with self._lock: if not issubclass(message_class, MessageBase): raise ChannelException(CEType.ME_INVALID_MSG_TYPE, @@ -384,7 +384,7 @@ class Channel(contextlib.AbstractContextManager): for existing in ring: if envelope.sequence == existing.sequence: - RNS.log(f"Envelope: Emplacement of duplicate envelope with sequence "+str(envelope.sequence), RNS.LOG_EXTREME) + RNS.log(f"Envelope: Emplacement of duplicate envelope with sequence {envelope.sequence}", RNS.LOG_EXTREME) return False if envelope.sequence < existing.sequence and not (self._next_rx_sequence - envelope.sequence) > (Channel.SEQ_MAX//2): @@ -408,7 +408,7 @@ class Channel(contextlib.AbstractContextManager): if cb(message): return except Exception as e: - RNS.log("Channel "+str(self)+" experienced an error while running a message callback. The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Channel {self} experienced an error while running a message callback. The contained exception was: {e}", RNS.LOG_ERROR) def _receive(self, raw: bytes): try: @@ -420,16 +420,16 @@ class Channel(contextlib.AbstractContextManager): window_overflow = (self._next_rx_sequence+Channel.WINDOW_MAX) % Channel.SEQ_MODULUS if window_overflow < self._next_rx_sequence: if envelope.sequence > window_overflow: - RNS.log("Invalid packet sequence ("+str(envelope.sequence)+") received on channel "+str(self), RNS.LOG_EXTREME) + RNS.log(f"Invalid packet sequence ({envelope.sequence}) received on channel {self}", RNS.LOG_EXTREME) return else: - RNS.log("Invalid packet sequence ("+str(envelope.sequence)+") received on channel "+str(self), RNS.LOG_EXTREME) + RNS.log(f"Invalid packet sequence ({envelope.sequence}) received on channel {self}", RNS.LOG_EXTREME) return is_new = self._emplace_envelope(envelope, self._rx_ring) if not is_new: - RNS.log("Duplicate message received on channel "+str(self), RNS.LOG_EXTREME) + RNS.log(f"Duplicate message received on channel {self}", RNS.LOG_EXTREME) return else: with self._lock: @@ -454,7 +454,7 @@ class Channel(contextlib.AbstractContextManager): self._run_callbacks(m) except Exception as e: - RNS.log("An error ocurred while receiving data on "+str(self)+". The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"An error ocurred while receiving data on {self}. The contained exception was: {e}", RNS.LOG_ERROR) def is_ready_to_send(self) -> bool: """ @@ -520,9 +520,9 @@ class Channel(contextlib.AbstractContextManager): else: - RNS.log("Envelope not found in TX ring for "+str(self), RNS.LOG_EXTREME) + RNS.log(f"Envelope not found in TX ring for {self}", RNS.LOG_EXTREME) if not envelope: - RNS.log("Spurious message received on "+str(self), RNS.LOG_EXTREME) + RNS.log(f"Spurious message received on {self}", RNS.LOG_EXTREME) def _packet_delivered(self, packet: TPacket): self._packet_tx_op(packet, lambda env: True) @@ -541,7 +541,7 @@ class Channel(contextlib.AbstractContextManager): def _packet_timeout(self, packet: TPacket): def retry_envelope(envelope: Envelope) -> bool: if envelope.tries >= self._max_tries: - RNS.log("Retry count exceeded on "+str(self)+", tearing down Link.", RNS.LOG_ERROR) + RNS.log(f"Retry count exceeded on {self}, tearing down Link.", RNS.LOG_ERROR) self._shutdown() # start on separate thread? self._outlet.timed_out() return True diff --git a/RNS/Cryptography/Fernet.py b/RNS/Cryptography/Fernet.py index 245d86c..0ce843c 100644 --- a/RNS/Cryptography/Fernet.py +++ b/RNS/Cryptography/Fernet.py @@ -48,7 +48,7 @@ class Fernet(): raise ValueError("Token key cannot be None") if len(key) != 32: - raise ValueError("Token key must be 32 bytes, not "+str(len(key))) + raise ValueError(f"Token key must be 32 bytes, not {len(key)}") self._signing_key = key[:16] self._encryption_key = key[16:] @@ -56,7 +56,7 @@ class Fernet(): def verify_hmac(self, token): if len(token) <= 32: - raise ValueError("Cannot verify HMAC on token of only "+str(len(token))+" bytes") + raise ValueError(f"Cannot verify HMAC on token of only {len(token)} bytes") else: received_hmac = token[-32:] expected_hmac = HMAC.new(self._signing_key, token[:-32]).digest() diff --git a/RNS/Cryptography/HMAC.py b/RNS/Cryptography/HMAC.py index 848a231..2f7460b 100644 --- a/RNS/Cryptography/HMAC.py +++ b/RNS/Cryptography/HMAC.py @@ -37,7 +37,7 @@ class HMAC: """ if not isinstance(key, (bytes, bytearray)): - raise TypeError("key: expected bytes or bytearray, but got %r" % type(key).__name__) + raise TypeError(f"key: expected bytes or bytearray, but got {type(key).__name__!r}") if not digestmod: raise TypeError("Missing required parameter 'digestmod'.") @@ -60,13 +60,11 @@ class HMAC: if hasattr(self._inner, 'block_size'): blocksize = self._inner.block_size if blocksize < 16: - _warnings.warn('block_size of %d seems too small; using our ' - 'default of %d.' % (blocksize, self.blocksize), + _warnings.warn(f'block_size of {int(blocksize)} seems too small; using our default of {int(self.blocksize)}.', RuntimeWarning, 2) blocksize = self.blocksize else: - _warnings.warn('No block_size attribute on given digest object; ' - 'Assuming %d.' % (self.blocksize), + _warnings.warn(f'No block_size attribute on given digest object; Assuming {int(self.blocksize)}.', RuntimeWarning, 2) blocksize = self.blocksize diff --git a/RNS/Cryptography/PKCS7.py b/RNS/Cryptography/PKCS7.py index aa3bef0..d508bab 100644 --- a/RNS/Cryptography/PKCS7.py +++ b/RNS/Cryptography/PKCS7.py @@ -35,6 +35,6 @@ class PKCS7: l = len(data) n = data[-1] if n > bs: - raise ValueError("Cannot unpad, invalid padding length of "+str(n)+" bytes") + raise ValueError(f"Cannot unpad, invalid padding length of {n} bytes") else: return data[:l-n] \ No newline at end of file diff --git a/RNS/Cryptography/Provider.py b/RNS/Cryptography/Provider.py index 80a3f9e..016dc37 100644 --- a/RNS/Cryptography/Provider.py +++ b/RNS/Cryptography/Provider.py @@ -35,4 +35,4 @@ def backend(): elif PROVIDER == PROVIDER_INTERNAL: return "internal" elif PROVIDER == PROVIDER_PYCA: - return "openssl, PyCA "+str(pyca_v) \ No newline at end of file + return f"openssl, PyCA {pyca_v}" \ No newline at end of file diff --git a/RNS/Cryptography/SHA256.py b/RNS/Cryptography/SHA256.py index 5fc8395..03f22a4 100644 --- a/RNS/Cryptography/SHA256.py +++ b/RNS/Cryptography/SHA256.py @@ -28,7 +28,7 @@ import sys def new(m=None): return sha256(m) -class sha256(object): +class sha256: _k = (0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, @@ -59,7 +59,7 @@ class sha256(object): if m is not None: if type(m) is not bytes: - raise TypeError('%s() argument 1 must be bytes, not %s' % (self.__class__.__name__, type(m).__name__)) + raise TypeError(f'{self.__class__.__name__}() argument 1 must be bytes, not {type(m).__name__}') self.update(m) def _rotr(self, x, y): @@ -100,7 +100,7 @@ class sha256(object): return if type(m) is not bytes: - raise TypeError('%s() argument 1 must be bytes, not %s' % (sys._getframe().f_code.co_name, type(m).__name__)) + raise TypeError(f'{sys._getframe().f_code.co_name}() argument 1 must be bytes, not {type(m).__name__}') self._buffer += m self._counter += len(m) diff --git a/RNS/Cryptography/SHA512.py b/RNS/Cryptography/SHA512.py index 4e5c3f6..7dbcb76 100644 --- a/RNS/Cryptography/SHA512.py +++ b/RNS/Cryptography/SHA512.py @@ -25,7 +25,7 @@ import copy, struct, sys def new(m=None): return sha512(m) -class sha512(object): +class sha512: _k = (0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc, 0x3956c25bf348b538, 0x59f111f1b605d019, 0x923f82a4af194f9b, 0xab1c5ed5da6d8118, 0xd807aa98a3030242, 0x12835b0145706fbe, 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2, @@ -60,7 +60,7 @@ class sha512(object): if m is not None: if type(m) is not bytes: - raise TypeError('%s() argument 1 must be bytes, not %s' % (self.__class__.__name__, type(m).__name__)) + raise TypeError(f'{self.__class__.__name__}() argument 1 must be bytes, not {type(m).__name__}') self.update(m) def _rotr(self, x, y): @@ -100,7 +100,7 @@ class sha512(object): if not m: return if type(m) is not bytes: - raise TypeError('%s() argument 1 must be bytes, not %s' % (sys._getframe().f_code.co_name, type(m).__name__)) + raise TypeError(f'{sys._getframe().f_code.co_name}() argument 1 must be bytes, not {type(m).__name__}') self._buffer += m self._counter += len(m) diff --git a/RNS/Cryptography/__init__.py b/RNS/Cryptography/__init__.py index 78c04df..9c3289e 100644 --- a/RNS/Cryptography/__init__.py +++ b/RNS/Cryptography/__init__.py @@ -20,5 +20,5 @@ elif cp.PROVIDER == cp.PROVIDER_PYCA: from RNS.Cryptography.Proxies import Ed25519PrivateKeyProxy as Ed25519PrivateKey from RNS.Cryptography.Proxies import Ed25519PublicKeyProxy as Ed25519PublicKey -modules = glob.glob(os.path.dirname(__file__)+"/*.py") +modules = glob.glob(f"{os.path.dirname(__file__)}/*.py") __all__ = [ os.path.basename(f)[:-3] for f in modules if not f.endswith('__init__.py')] diff --git a/RNS/Cryptography/aes/aes.py b/RNS/Cryptography/aes/aes.py index eabb20b..4b8e45e 100644 --- a/RNS/Cryptography/aes/aes.py +++ b/RNS/Cryptography/aes/aes.py @@ -230,7 +230,7 @@ def test(): print(f"Ciphertext Hex: {ciphertext_block.hex()}") print(f"Plaintext: {plaintext_block.decode()}") assert plaintext_block == single_block_text - print(bcolors.OK + "Single Block Test Passed Successfully" + bcolors.RESET) + print(f"{bcolors.OK}Single Block Test Passed Successfully{bcolors.RESET}") print() # test a less than a block length phrase @@ -246,7 +246,7 @@ def test(): print(f"Ciphertext Hex: {ciphertext_short.hex()}") print(f"Plaintext: {plaintext_short.decode()}") assert short_text == plaintext_short - print(bcolors.OK + "Short Text Test Passed Successfully" + bcolors.RESET) + print(f"{bcolors.OK}Short Text Test Passed Successfully{bcolors.RESET}") print() # test an arbitrary length phrase @@ -262,7 +262,7 @@ def test(): print(f"Ciphertext Hex: {ciphertext.hex()}") print(f"Plaintext: {plaintext.decode()}") assert text == plaintext - print(bcolors.OK + "Arbitrary Length Text Test Passed Successfully" + bcolors.RESET) + print(f"{bcolors.OK}Arbitrary Length Text Test Passed Successfully{bcolors.RESET}") print() diff --git a/RNS/Cryptography/pure25519/basic.py b/RNS/Cryptography/pure25519/basic.py index e18c759..2450851 100644 --- a/RNS/Cryptography/pure25519/basic.py +++ b/RNS/Cryptography/pure25519/basic.py @@ -141,7 +141,7 @@ def encodepoint(P): assert 0 <= y < (1<<255) # always < 0x7fff..ff if x & 1: y += 1<<255 - return binascii.unhexlify("%064x" % y)[::-1] + return binascii.unhexlify(f"{y:064x}")[::-1] def isoncurve(P): x = P[0] @@ -192,7 +192,7 @@ def password_to_scalar(pw): def scalar_to_bytes(y): y = y % L assert 0 <= y < 2**256 - return binascii.unhexlify("%064x" % y)[::-1] + return binascii.unhexlify(f"{y:064x}")[::-1] # Elements, of various orders diff --git a/RNS/Cryptography/pure25519/ed25519_oop.py b/RNS/Cryptography/pure25519/ed25519_oop.py index 0edfa5a..fa5e6a4 100644 --- a/RNS/Cryptography/pure25519/ed25519_oop.py +++ b/RNS/Cryptography/pure25519/ed25519_oop.py @@ -39,7 +39,7 @@ class BadPrefixError(Exception): def remove_prefix(s_bytes, prefix): assert(type(s_bytes) == type(prefix)) if s_bytes[:len(prefix)] != prefix: - raise BadPrefixError("did not see expected '%s' prefix" % (prefix,)) + raise BadPrefixError(f"did not see expected '{prefix}' prefix") return s_bytes[len(prefix):] def to_ascii(s_bytes, prefix="", encoding="base64"): @@ -93,7 +93,7 @@ def from_ascii(s_ascii, prefix="", encoding="base64"): raise NotImplementedError return s_bytes -class SigningKey(object): +class SigningKey: # this can only be used to reconstruct a key created by create_keypair(). def __init__(self, sk_s, prefix="", encoding=None): assert isinstance(sk_s, bytes) @@ -150,7 +150,7 @@ class SigningKey(object): return to_ascii(sig_out, prefix, encoding) return prefix+sig_out -class VerifyingKey(object): +class VerifyingKey: def __init__(self, vk_s, prefix="", encoding=None): if not isinstance(prefix, bytes): prefix = prefix.encode('ascii') diff --git a/RNS/Cryptography/pure25519/eddsa.py b/RNS/Cryptography/pure25519/eddsa.py index f6a89dc..ce01cca 100644 --- a/RNS/Cryptography/pure25519/eddsa.py +++ b/RNS/Cryptography/pure25519/eddsa.py @@ -78,16 +78,16 @@ def sign(skbytes, msg): """Return just the signature, given the message and just the secret key.""" if len(skbytes) != 32: - raise ValueError("Bad signing key length %d" % len(skbytes)) + raise ValueError(f"Bad signing key length {len(skbytes)}") vkbytes = create_verifying_key(skbytes) sig = signature(msg, skbytes, vkbytes) return sig def verify(vkbytes, sig, msg): if len(vkbytes) != 32: - raise ValueError("Bad verifying key length %d" % len(vkbytes)) + raise ValueError(f"Bad verifying key length {len(vkbytes)}") if len(sig) != 64: - raise ValueError("Bad signature length %d" % len(sig)) + raise ValueError(f"Bad signature length {len(sig)}") rc = checkvalid(sig, msg, vkbytes) if not rc: raise ValueError("rc != 0", rc) diff --git a/RNS/Destination.py b/RNS/Destination.py index bca8f35..68d854c 100755 --- a/RNS/Destination.py +++ b/RNS/Destination.py @@ -96,10 +96,10 @@ class Destination: name = app_name for aspect in aspects: if "." in aspect: raise ValueError("Dots can't be used in aspects") - name += "." + aspect + name += f".{aspect}" if identity != None: - name += "." + identity.hexhash + name += f".{identity.hexhash}" return name @@ -192,7 +192,7 @@ class Destination: """ :returns: A human-readable representation of the destination including addressable hash and full name. """ - return "<"+self.name+"/"+self.hexhash+">" + return f"<{self.name}/{self.hexhash}>" def _clean_ratchets(self): if self.ratchets != None: @@ -210,13 +210,13 @@ class Destination: except Exception as e: self.ratchets = None self.ratchets_path = None - raise OSError("Could not write ratchet file contents for "+str(self)+". The contained exception was: "+str(e), RNS.LOG_ERROR) + raise OSError(f"Could not write ratchet file contents for {self}. The contained exception was: {e}", RNS.LOG_ERROR) def rotate_ratchets(self): if self.ratchets != None: now = time.time() if now > self.latest_ratchet_time+self.ratchet_interval: - RNS.log("Rotating ratchets for "+str(self), RNS.LOG_DEBUG) + RNS.log(f"Rotating ratchets for {self}", RNS.LOG_DEBUG) new_ratchet = RNS.Identity._generate_ratchet() self.ratchets.insert(0, new_ratchet) self.latest_ratchet_time = now @@ -224,7 +224,7 @@ class Destination: self._persist_ratchets() return True else: - raise SystemError("Cannot rotate ratchet on "+str(self)+", ratchets are not enabled") + raise SystemError(f"Cannot rotate ratchet on {self}, ratchets are not enabled") return False @@ -262,7 +262,7 @@ class Destination: # received via multiple paths. The difference in reception time will # potentially also be useful in determining characteristics of the # multiple available paths, and to choose the best one. - RNS.log("Using cached announce data for answering path request with tag "+RNS.prettyhexrep(tag), RNS.LOG_EXTREME) + RNS.log(f"Using cached announce data for answering path request with tag {RNS.prettyhexrep(tag)}", RNS.LOG_EXTREME) announce_data = self.path_responses[tag][1] else: @@ -413,7 +413,7 @@ class Destination: try: self.callbacks.packet(plaintext, packet) except Exception as e: - RNS.log("Error while executing receive callback from "+str(self)+". The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Error while executing receive callback from {self}. The contained exception was: {e}", RNS.LOG_ERROR) def incoming_link_request(self, data, packet): if self.accept_link_requests: @@ -437,9 +437,9 @@ class Destination: except Exception as e: self.ratchets = None self.ratchets_path = None - raise OSError("Could not read ratchet file contents for "+str(self)+". The contained exception was: "+str(e), RNS.LOG_ERROR) + raise OSError(f"Could not read ratchet file contents for {self}. The contained exception was: {e}", RNS.LOG_ERROR) else: - RNS.log("No existing ratchet data found, initialising new ratchet file for "+str(self), RNS.LOG_DEBUG) + RNS.log(f"No existing ratchet data found, initialising new ratchet file for {self}", RNS.LOG_DEBUG) self.ratchets = [] self.ratchets_path = ratchets_path self._persist_ratchets() @@ -464,11 +464,11 @@ class Destination: self._reload_ratchets(ratchets_path) # TODO: Remove at some point - RNS.log("Ratchets enabled on "+str(self), RNS.LOG_DEBUG) + RNS.log(f"Ratchets enabled on {self}", RNS.LOG_DEBUG) return True else: - raise ValueError("No ratchet file path specified for "+str(self)) + raise ValueError(f"No ratchet file path specified for {self}") def enforce_ratchets(self): """ @@ -478,7 +478,7 @@ class Destination: """ if self.ratchets != None: self.__enforce_ratchets = True - RNS.log("Ratchets enforced on "+str(self), RNS.LOG_DEBUG) + RNS.log(f"Ratchets enforced on {self}", RNS.LOG_DEBUG) return True else: return False @@ -586,7 +586,7 @@ class Destination: return self.prv.encrypt(plaintext) except Exception as e: RNS.log("The GROUP destination could not encrypt data", RNS.LOG_ERROR) - RNS.log("The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"The contained exception was: {e}", RNS.LOG_ERROR) else: raise ValueError("No private key held by GROUP destination. Did you create or load one?") @@ -630,7 +630,7 @@ class Destination: return self.prv.decrypt(ciphertext) except Exception as e: RNS.log("The GROUP destination could not decrypt data", RNS.LOG_ERROR) - RNS.log("The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"The contained exception was: {e}", RNS.LOG_ERROR) else: raise ValueError("No private key held by GROUP destination. Did you create or load one?") diff --git a/RNS/Identity.py b/RNS/Identity.py index b2de82a..a1cc638 100644 --- a/RNS/Identity.py +++ b/RNS/Identity.py @@ -87,7 +87,7 @@ class Identity: @staticmethod def remember(packet_hash, destination_hash, public_key, app_data = None): if len(public_key) != Identity.KEYSIZE//8: - raise TypeError("Can't remember "+RNS.prettyhexrep(destination_hash)+", the public key size of "+str(len(public_key))+" is not valid.", RNS.LOG_ERROR) + raise TypeError(f"Can't remember {RNS.prettyhexrep(destination_hash)}, the public key size of {len(public_key)} is not valid.", RNS.LOG_ERROR) else: Identity.known_destinations[destination_hash] = [time.time(), packet_hash, public_key, app_data] @@ -153,9 +153,9 @@ class Identity: save_start = time.time() storage_known_destinations = {} - if os.path.isfile(RNS.Reticulum.storagepath+"/known_destinations"): + if os.path.isfile(f"{RNS.Reticulum.storagepath}/known_destinations"): try: - file = open(RNS.Reticulum.storagepath+"/known_destinations","rb") + file = open(f"{RNS.Reticulum.storagepath}/known_destinations","rb") storage_known_destinations = umsgpack.load(file) file.close() except: @@ -166,32 +166,32 @@ class Identity: if not destination_hash in Identity.known_destinations: Identity.known_destinations[destination_hash] = storage_known_destinations[destination_hash] except Exception as e: - RNS.log("Skipped recombining known destinations from disk, since an error occurred: "+str(e), RNS.LOG_WARNING) + RNS.log(f"Skipped recombining known destinations from disk, since an error occurred: {e}", RNS.LOG_WARNING) - RNS.log("Saving "+str(len(Identity.known_destinations))+" known destinations to storage...", RNS.LOG_DEBUG) - file = open(RNS.Reticulum.storagepath+"/known_destinations","wb") + RNS.log(f"Saving {len(Identity.known_destinations)} known destinations to storage...", RNS.LOG_DEBUG) + file = open(f"{RNS.Reticulum.storagepath}/known_destinations","wb") umsgpack.dump(Identity.known_destinations, file) file.close() save_time = time.time() - save_start if save_time < 1: - time_str = str(round(save_time*1000,2))+"ms" + time_str = f"{round(save_time * 1000, 2)}ms" else: - time_str = str(round(save_time,2))+"s" + time_str = f"{round(save_time, 2)}s" - RNS.log("Saved known destinations to storage in "+time_str, RNS.LOG_DEBUG) + RNS.log(f"Saved known destinations to storage in {time_str}", RNS.LOG_DEBUG) except Exception as e: - RNS.log("Error while saving known destinations to disk, the contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Error while saving known destinations to disk, the contained exception was: {e}", RNS.LOG_ERROR) RNS.trace_exception(e) Identity.saving_known_destinations = False @staticmethod def load_known_destinations(): - if os.path.isfile(RNS.Reticulum.storagepath+"/known_destinations"): + if os.path.isfile(f"{RNS.Reticulum.storagepath}/known_destinations"): try: - file = open(RNS.Reticulum.storagepath+"/known_destinations","rb") + file = open(f"{RNS.Reticulum.storagepath}/known_destinations","rb") loaded_known_destinations = umsgpack.load(file) file.close() @@ -200,7 +200,7 @@ class Identity: if len(known_destination) == RNS.Reticulum.TRUNCATED_HASHLENGTH//8: Identity.known_destinations[known_destination] = loaded_known_destinations[known_destination] - RNS.log("Loaded "+str(len(Identity.known_destinations))+" known destination from storage", RNS.LOG_VERBOSE) + RNS.log(f"Loaded {len(Identity.known_destinations)} known destination from storage", RNS.LOG_VERBOSE) except Exception as e: RNS.log("Error loading known destinations from disk, file will be recreated on exit", RNS.LOG_ERROR) @@ -278,7 +278,7 @@ class Identity: hexhash = RNS.hexrep(destination_hash, delimit=False) ratchet_data = {"ratchet": ratchet, "received": time.time()} - ratchetdir = RNS.Reticulum.storagepath+"/ratchets" + ratchetdir = f"{RNS.Reticulum.storagepath}/ratchets" if not os.path.isdir(ratchetdir): os.makedirs(ratchetdir) @@ -303,7 +303,7 @@ class Identity: RNS.log("Cleaning ratchets...", RNS.LOG_DEBUG) try: now = time.time() - ratchetdir = RNS.Reticulum.storagepath+"/ratchets" + ratchetdir = f"{RNS.Reticulum.storagepath}/ratchets" if os.path.isdir(ratchetdir): for filename in os.listdir(ratchetdir): try: @@ -326,7 +326,7 @@ class Identity: @staticmethod def get_ratchet(destination_hash): if not destination_hash in Identity.known_ratchets: - ratchetdir = RNS.Reticulum.storagepath+"/ratchets" + ratchetdir = f"{RNS.Reticulum.storagepath}/ratchets" hexhash = RNS.hexrep(destination_hash, delimit=False) ratchet_path = f"{ratchetdir}/{hexhash}" if os.path.isfile(ratchet_path): @@ -417,19 +417,19 @@ class Identity: if packet.rssi != None or packet.snr != None: signal_str = " [" if packet.rssi != None: - signal_str += "RSSI "+str(packet.rssi)+"dBm" + signal_str += f"RSSI {packet.rssi}dBm" if packet.snr != None: signal_str += ", " if packet.snr != None: - signal_str += "SNR "+str(packet.snr)+"dB" + signal_str += f"SNR {packet.snr}dB" signal_str += "]" else: signal_str = "" if hasattr(packet, "transport_id") and packet.transport_id != None: - RNS.log("Valid announce for "+RNS.prettyhexrep(destination_hash)+" "+str(packet.hops)+" hops away, received via "+RNS.prettyhexrep(packet.transport_id)+" on "+str(packet.receiving_interface)+signal_str, RNS.LOG_EXTREME) + RNS.log(f"Valid announce for {RNS.prettyhexrep(destination_hash)} {packet.hops} hops away, received via {RNS.prettyhexrep(packet.transport_id)} on {packet.receiving_interface}{signal_str}", RNS.LOG_EXTREME) else: - RNS.log("Valid announce for "+RNS.prettyhexrep(destination_hash)+" "+str(packet.hops)+" hops away, received on "+str(packet.receiving_interface)+signal_str, RNS.LOG_EXTREME) + RNS.log(f"Valid announce for {RNS.prettyhexrep(destination_hash)} {packet.hops} hops away, received on {packet.receiving_interface}{signal_str}", RNS.LOG_EXTREME) if ratchet: Identity._remember_ratchet(destination_hash, ratchet) @@ -437,16 +437,16 @@ class Identity: return True else: - RNS.log("Received invalid announce for "+RNS.prettyhexrep(destination_hash)+": Destination mismatch.", RNS.LOG_DEBUG) + RNS.log(f"Received invalid announce for {RNS.prettyhexrep(destination_hash)}: Destination mismatch.", RNS.LOG_DEBUG) return False else: - RNS.log("Received invalid announce for "+RNS.prettyhexrep(destination_hash)+": Invalid signature.", RNS.LOG_DEBUG) + RNS.log(f"Received invalid announce for {RNS.prettyhexrep(destination_hash)}: Invalid signature.", RNS.LOG_DEBUG) del announced_identity return False except Exception as e: - RNS.log("Error occurred while validating announce. The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Error occurred while validating announce. The contained exception was: {e}", RNS.LOG_ERROR) return False @staticmethod @@ -505,8 +505,8 @@ class Identity: return True return False except Exception as e: - RNS.log("Error while saving identity to "+str(path), RNS.LOG_ERROR) - RNS.log("The contained exception was: "+str(e)) + RNS.log(f"Error while saving identity to {path}", RNS.LOG_ERROR) + RNS.log(f"The contained exception was: {e}") def __init__(self,create_keys=True): # Initialize keys to none @@ -541,7 +541,7 @@ class Identity: self.update_hashes() - RNS.log("Identity keys created for "+RNS.prettyhexrep(self.hash), RNS.LOG_VERBOSE) + RNS.log(f"Identity keys created for {RNS.prettyhexrep(self.hash)}", RNS.LOG_VERBOSE) def get_private_key(self): """ @@ -581,7 +581,7 @@ class Identity: except Exception as e: raise e RNS.log("Failed to load identity key", RNS.LOG_ERROR) - RNS.log("The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"The contained exception was: {e}", RNS.LOG_ERROR) return False def load_public_key(self, pub_bytes): @@ -600,7 +600,7 @@ class Identity: self.update_hashes() except Exception as e: - RNS.log("Error while loading public key, the contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Error while loading public key, the contained exception was: {e}", RNS.LOG_ERROR) def update_hashes(self): self.hash = Identity.truncated_hash(self.get_public_key()) @@ -613,8 +613,8 @@ class Identity: return self.load_private_key(prv_bytes) return False except Exception as e: - RNS.log("Error while loading identity from "+str(path), RNS.LOG_ERROR) - RNS.log("The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Error while loading identity from {path}", RNS.LOG_ERROR) + RNS.log(f"The contained exception was: {e}", RNS.LOG_ERROR) def get_salt(self): return self.hash @@ -697,7 +697,7 @@ class Identity: pass if enforce_ratchets and plaintext == None: - RNS.log("Decryption with ratchet enforcement by "+RNS.prettyhexrep(self.hash)+" failed. Dropping packet.", RNS.LOG_DEBUG) + RNS.log(f"Decryption with ratchet enforcement by {RNS.prettyhexrep(self.hash)} failed. Dropping packet.", RNS.LOG_DEBUG) if ratchet_id_receiver: ratchet_id_receiver.latest_ratchet_id = None return None @@ -717,7 +717,7 @@ class Identity: ratchet_id_receiver.latest_ratchet_id = None except Exception as e: - RNS.log("Decryption by "+RNS.prettyhexrep(self.hash)+" failed: "+str(e), RNS.LOG_DEBUG) + RNS.log(f"Decryption by {RNS.prettyhexrep(self.hash)} failed: {e}", RNS.LOG_DEBUG) if ratchet_id_receiver: ratchet_id_receiver.latest_ratchet_id = None @@ -741,7 +741,7 @@ class Identity: try: return self.sig_prv.sign(message) except Exception as e: - RNS.log("The identity "+str(self)+" could not sign the requested message. The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"The identity {self} could not sign the requested message. The contained exception was: {e}", RNS.LOG_ERROR) raise e else: raise KeyError("Signing failed because identity does not hold a private key") diff --git a/RNS/Interfaces/AX25KISSInterface.py b/RNS/Interfaces/AX25KISSInterface.py index 483c562..cf99a0b 100644 --- a/RNS/Interfaces/AX25KISSInterface.py +++ b/RNS/Interfaces/AX25KISSInterface.py @@ -87,7 +87,7 @@ class AX25KISSInterface(Interface): self.name = name self.src_call = callsign.upper().encode("ascii") self.src_ssid = ssid - self.dst_call = "APZRNS".encode("ascii") + self.dst_call = b"APZRNS" self.dst_ssid = 0 self.port = port self.speed = speed @@ -105,10 +105,10 @@ class AX25KISSInterface(Interface): self.flow_control_locked = time.time() if (len(self.src_call) < 3 or len(self.src_call) > 6): - raise ValueError("Invalid callsign for "+str(self)) + raise ValueError(f"Invalid callsign for {self}") if (self.src_ssid < 0 or self.src_ssid > 15): - raise ValueError("Invalid SSID for "+str(self)) + raise ValueError(f"Invalid SSID for {self}") self.preamble = preamble if preamble != None else 350; self.txtail = txtail if txtail != None else 20; @@ -124,16 +124,16 @@ class AX25KISSInterface(Interface): try: self.open_port() except Exception as e: - RNS.log("Could not open serial port for interface "+str(self), RNS.LOG_ERROR) + RNS.log(f"Could not open serial port for interface {self}", RNS.LOG_ERROR) raise e if self.serial.is_open: self.configure_device() else: - raise IOError("Could not open serial port") + raise OSError("Could not open serial port") def open_port(self): - RNS.log("Opening serial port "+self.port+"...", RNS.LOG_VERBOSE) + RNS.log(f"Opening serial port {self.port}...", RNS.LOG_VERBOSE) self.serial = self.pyserial.Serial( port = self.port, baudrate = self.speed, @@ -155,7 +155,7 @@ class AX25KISSInterface(Interface): thread.daemon = True thread.start() self.online = True - RNS.log("Serial port "+self.port+" is now open") + RNS.log(f"Serial port {self.port} is now open") RNS.log("Configuring AX.25 KISS interface parameters...") self.setPreamble(self.preamble) self.setTxTail(self.txtail) @@ -176,7 +176,7 @@ class AX25KISSInterface(Interface): kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_TXDELAY])+bytes([preamble])+bytes([KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("Could not configure AX.25 KISS interface preamble to "+str(preamble_ms)+" (command value "+str(preamble)+")") + raise OSError(f"Could not configure AX.25 KISS interface preamble to {preamble_ms} (command value {preamble})") def setTxTail(self, txtail): txtail_ms = txtail @@ -189,7 +189,7 @@ class AX25KISSInterface(Interface): kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_TXTAIL])+bytes([txtail])+bytes([KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("Could not configure AX.25 KISS interface TX tail to "+str(txtail_ms)+" (command value "+str(txtail)+")") + raise OSError(f"Could not configure AX.25 KISS interface TX tail to {txtail_ms} (command value {txtail})") def setPersistence(self, persistence): if persistence < 0: @@ -200,7 +200,7 @@ class AX25KISSInterface(Interface): kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_P])+bytes([persistence])+bytes([KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("Could not configure AX.25 KISS interface persistence to "+str(persistence)) + raise OSError(f"Could not configure AX.25 KISS interface persistence to {persistence}") def setSlotTime(self, slottime): slottime_ms = slottime @@ -213,16 +213,16 @@ class AX25KISSInterface(Interface): kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_SLOTTIME])+bytes([slottime])+bytes([KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("Could not configure AX.25 KISS interface slot time to "+str(slottime_ms)+" (command value "+str(slottime)+")") + raise OSError(f"Could not configure AX.25 KISS interface slot time to {slottime_ms} (command value {slottime})") def setFlowControl(self, flow_control): kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_READY])+bytes([0x01])+bytes([KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): if (flow_control): - raise IOError("Could not enable AX.25 KISS interface flow control") + raise OSError("Could not enable AX.25 KISS interface flow control") else: - raise IOError("Could not enable AX.25 KISS interface flow control") + raise OSError("Could not enable AX.25 KISS interface flow control") def processIncoming(self, data): @@ -270,7 +270,7 @@ class AX25KISSInterface(Interface): if written != len(kiss_frame): if self.flow_control: self.interface_ready = True - raise IOError("AX.25 interface only wrote "+str(written)+" bytes of "+str(len(kiss_frame))) + raise OSError(f"AX.25 interface only wrote {written} bytes of {len(kiss_frame)}") else: self.queue(data) @@ -336,13 +336,13 @@ class AX25KISSInterface(Interface): if self.flow_control: if not self.interface_ready: if time.time() > self.flow_control_locked + self.flow_control_timeout: - RNS.log("Interface "+str(self)+" is unlocking flow control due to time-out. This should not happen. Your hardware might have missed a flow-control READY command, or maybe it does not support flow-control.", RNS.LOG_WARNING) + RNS.log(f"Interface {self} is unlocking flow control due to time-out. This should not happen. Your hardware might have missed a flow-control READY command, or maybe it does not support flow-control.", RNS.LOG_WARNING) self.process_queue() except Exception as e: self.online = False - RNS.log("A serial port error occurred, the contained exception was: "+str(e), RNS.LOG_ERROR) - RNS.log("The interface "+str(self)+" experienced an unrecoverable error and is now offline.", RNS.LOG_ERROR) + RNS.log(f"A serial port error occurred, the contained exception was: {e}", RNS.LOG_ERROR) + RNS.log(f"The interface {self} experienced an unrecoverable error and is now offline.", RNS.LOG_ERROR) if RNS.Reticulum.panic_on_interface_error: RNS.panic() @@ -357,17 +357,17 @@ class AX25KISSInterface(Interface): while not self.online: try: time.sleep(5) - RNS.log("Attempting to reconnect serial port "+str(self.port)+" for "+str(self)+"...", RNS.LOG_VERBOSE) + RNS.log(f"Attempting to reconnect serial port {self.port} for {self}...", RNS.LOG_VERBOSE) self.open_port() if self.serial.is_open: self.configure_device() except Exception as e: - RNS.log("Error while reconnecting port, the contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Error while reconnecting port, the contained exception was: {e}", RNS.LOG_ERROR) - RNS.log("Reconnected serial port for "+str(self)) + RNS.log(f"Reconnected serial port for {self}") def should_ingress_limit(self): return False def __str__(self): - return "AX25KISSInterface["+self.name+"]" \ No newline at end of file + return f"AX25KISSInterface[{self.name}]" \ No newline at end of file diff --git a/RNS/Interfaces/Android/KISSInterface.py b/RNS/Interfaces/Android/KISSInterface.py index 88514b5..4c3c8cb 100644 --- a/RNS/Interfaces/Android/KISSInterface.py +++ b/RNS/Interfaces/Android/KISSInterface.py @@ -125,17 +125,17 @@ class KISSInterface(Interface): try: self.open_port() except Exception as e: - RNS.log("Could not open serial port "+self.port, RNS.LOG_ERROR) + RNS.log(f"Could not open serial port {self.port}", RNS.LOG_ERROR) raise e if self.serial.is_open: self.configure_device() else: - raise IOError("Could not open serial port") + raise OSError("Could not open serial port") def open_port(self): - RNS.log("Opening serial port "+self.port+"...") + RNS.log(f"Opening serial port {self.port}...") # Get device parameters from usb4a import usb device = usb.get_usb_device(self.port) @@ -147,7 +147,7 @@ class KISSInterface(Interface): proxy = self.pyserial.get_serial_port if vid == 0x1A86 and pid == 0x55D4: # Force CDC driver for Qinheng CH34x - RNS.log(str(self)+" using CDC driver for "+RNS.hexrep(vid)+":"+RNS.hexrep(pid), RNS.LOG_DEBUG) + RNS.log(f"{self} using CDC driver for {RNS.hexrep(vid)}:{RNS.hexrep(pid)}", RNS.LOG_DEBUG) from usbserial4a.cdcacmserial4a import CdcAcmSerial proxy = CdcAcmSerial @@ -186,9 +186,9 @@ class KISSInterface(Interface): self.serial.USB_READ_TIMEOUT_MILLIS = 100 self.serial.timeout = 0.1 - RNS.log(str(self)+" USB read buffer size set to "+RNS.prettysize(self.serial.DEFAULT_READ_BUFFER_SIZE), RNS.LOG_DEBUG) - RNS.log(str(self)+" USB read timeout set to "+str(self.serial.USB_READ_TIMEOUT_MILLIS)+"ms", RNS.LOG_DEBUG) - RNS.log(str(self)+" USB write timeout set to "+str(self.serial.USB_WRITE_TIMEOUT_MILLIS)+"ms", RNS.LOG_DEBUG) + RNS.log(f"{self} USB read buffer size set to {RNS.prettysize(self.serial.DEFAULT_READ_BUFFER_SIZE)}", RNS.LOG_DEBUG) + RNS.log(f"{self} USB read timeout set to {self.serial.USB_READ_TIMEOUT_MILLIS}ms", RNS.LOG_DEBUG) + RNS.log(f"{self} USB write timeout set to {self.serial.USB_WRITE_TIMEOUT_MILLIS}ms", RNS.LOG_DEBUG) def configure_device(self): # Allow time for interface to initialise before config @@ -197,7 +197,7 @@ class KISSInterface(Interface): thread.daemon = True thread.start() self.online = True - RNS.log("Serial port "+self.port+" is now open") + RNS.log(f"Serial port {self.port} is now open") RNS.log("Configuring KISS interface parameters...") self.setPreamble(self.preamble) self.setTxTail(self.txtail) @@ -218,7 +218,7 @@ class KISSInterface(Interface): kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_TXDELAY])+bytes([preamble])+bytes([KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("Could not configure KISS interface preamble to "+str(preamble_ms)+" (command value "+str(preamble)+")") + raise OSError(f"Could not configure KISS interface preamble to {preamble_ms} (command value {preamble})") def setTxTail(self, txtail): txtail_ms = txtail @@ -231,7 +231,7 @@ class KISSInterface(Interface): kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_TXTAIL])+bytes([txtail])+bytes([KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("Could not configure KISS interface TX tail to "+str(txtail_ms)+" (command value "+str(txtail)+")") + raise OSError(f"Could not configure KISS interface TX tail to {txtail_ms} (command value {txtail})") def setPersistence(self, persistence): if persistence < 0: @@ -242,7 +242,7 @@ class KISSInterface(Interface): kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_P])+bytes([persistence])+bytes([KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("Could not configure KISS interface persistence to "+str(persistence)) + raise OSError(f"Could not configure KISS interface persistence to {persistence}") def setSlotTime(self, slottime): slottime_ms = slottime @@ -255,16 +255,16 @@ class KISSInterface(Interface): kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_SLOTTIME])+bytes([slottime])+bytes([KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("Could not configure KISS interface slot time to "+str(slottime_ms)+" (command value "+str(slottime)+")") + raise OSError(f"Could not configure KISS interface slot time to {slottime_ms} (command value {slottime})") def setFlowControl(self, flow_control): kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_READY])+bytes([0x01])+bytes([KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): if (flow_control): - raise IOError("Could not enable KISS interface flow control") + raise OSError("Could not enable KISS interface flow control") else: - raise IOError("Could not enable KISS interface flow control") + raise OSError("Could not enable KISS interface flow control") def processIncoming(self, data): @@ -295,7 +295,7 @@ class KISSInterface(Interface): self.first_tx = time.time() if written != len(frame): - raise IOError("Serial interface only wrote "+str(written)+" bytes of "+str(len(data))) + raise OSError(f"Serial interface only wrote {written} bytes of {len(data)}") else: self.queue(data) @@ -365,20 +365,20 @@ class KISSInterface(Interface): if self.flow_control: if not self.interface_ready: if time.time() > self.flow_control_locked + self.flow_control_timeout: - RNS.log("Interface "+str(self)+" is unlocking flow control due to time-out. This should not happen. Your hardware might have missed a flow-control READY command, or maybe it does not support flow-control.", RNS.LOG_WARNING) + RNS.log(f"Interface {self} is unlocking flow control due to time-out. This should not happen. Your hardware might have missed a flow-control READY command, or maybe it does not support flow-control.", RNS.LOG_WARNING) self.process_queue() if self.beacon_i != None and self.beacon_d != None: if self.first_tx != None: if time.time() > self.first_tx + self.beacon_i: - RNS.log("Interface "+str(self)+" is transmitting beacon data: "+str(self.beacon_d.decode("utf-8")), RNS.LOG_DEBUG) + RNS.log(f"Interface {self} is transmitting beacon data: {self.beacon_d.decode('utf-8')}", RNS.LOG_DEBUG) self.first_tx = None self.processOutgoing(self.beacon_d) except Exception as e: self.online = False - RNS.log("A serial port error occurred, the contained exception was: "+str(e), RNS.LOG_ERROR) - RNS.log("The interface "+str(self)+" experienced an unrecoverable error and is now offline.", RNS.LOG_ERROR) + RNS.log(f"A serial port error occurred, the contained exception was: {e}", RNS.LOG_ERROR) + RNS.log(f"The interface {self} experienced an unrecoverable error and is now offline.", RNS.LOG_ERROR) if RNS.Reticulum.panic_on_interface_error: RNS.panic() @@ -393,17 +393,17 @@ class KISSInterface(Interface): while not self.online: try: time.sleep(5) - RNS.log("Attempting to reconnect serial port "+str(self.port)+" for "+str(self)+"...", RNS.LOG_VERBOSE) + RNS.log(f"Attempting to reconnect serial port {self.port} for {self}...", RNS.LOG_VERBOSE) self.open_port() if self.serial.is_open: self.configure_device() except Exception as e: - RNS.log("Error while reconnecting port, the contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Error while reconnecting port, the contained exception was: {e}", RNS.LOG_ERROR) - RNS.log("Reconnected serial port for "+str(self)) + RNS.log(f"Reconnected serial port for {self}") def should_ingress_limit(self): return False def __str__(self): - return "KISSInterface["+self.name+"]" \ No newline at end of file + return f"KISSInterface[{self.name}]" \ No newline at end of file diff --git a/RNS/Interfaces/Android/RNodeInterface.py b/RNS/Interfaces/Android/RNodeInterface.py index 9594acc..d600bd5 100644 --- a/RNS/Interfaces/Android/RNodeInterface.py +++ b/RNS/Interfaces/Android/RNodeInterface.py @@ -172,7 +172,7 @@ class AndroidBluetoothManager(): try: self.rfcomm_socket = device.createRfcommSocketToServiceRecord(self.bt_rfcomm_service_record) if self.rfcomm_socket == None: - raise IOError("Bluetooth stack returned no socket object") + raise OSError("Bluetooth stack returned no socket object") else: if not self.rfcomm_socket.isConnected(): try: @@ -181,13 +181,13 @@ class AndroidBluetoothManager(): self.rfcomm_writer = self.rfcomm_socket.getOutputStream() self.connected = True self.connected_device = device - RNS.log("Bluetooth device "+str(self.connected_device.getName())+" "+str(self.connected_device.getAddress())+" connected.") + RNS.log(f"Bluetooth device {self.connected_device.getName()} {self.connected_device.getAddress()} connected.") except Exception as e: - raise IOError("The Bluetooth RFcomm socket could not be connected: "+str(e)) + raise OSError(f"The Bluetooth RFcomm socket could not be connected: {e}") except Exception as e: - RNS.log("Could not create and connect Bluetooth RFcomm socket for "+str(device.getName())+" "+str(device.getAddress()), RNS.LOG_EXTREME) - RNS.log("The contained exception was: "+str(e), RNS.LOG_EXTREME) + RNS.log(f"Could not create and connect Bluetooth RFcomm socket for {device.getName()} {device.getAddress()}", RNS.LOG_EXTREME) + RNS.log(f"The contained exception was: {e}", RNS.LOG_EXTREME) def close(self): if self.connected: @@ -209,7 +209,7 @@ class AndroidBluetoothManager(): def read(self, len = None): if self.connection_failed: - raise IOError("Bluetooth connection failed") + raise OSError("Bluetooth connection failed") else: if self.connected and self.rfcomm_reader != None: available = self.rfcomm_reader.available() @@ -223,7 +223,7 @@ class AndroidBluetoothManager(): else: return bytes([]) else: - raise IOError("No RFcomm socket available") + raise OSError("No RFcomm socket available") def write(self, data): try: @@ -231,7 +231,7 @@ class AndroidBluetoothManager(): self.rfcomm_writer.flush() return len(data) except Exception as e: - RNS.log("Bluetooth connection failed for "+str(self), RNS.LOG_ERROR) + RNS.log(f"Bluetooth connection failed for {self}", RNS.LOG_ERROR) self.connection_failed = True return 0 @@ -274,7 +274,7 @@ class RNodeInterface(Interface): bluetooth_state = 0x00 if port != None: - RNS.log("Opening serial port "+port+"...") + RNS.log(f"Opening serial port {port}...") # Get device parameters from usb4a import usb device = usb.get_usb_device(port) @@ -287,7 +287,7 @@ class RNodeInterface(Interface): proxy = pyserial.get_serial_port if vid == 0x1A86 and pid == 0x55D4: # Force CDC driver for Qinheng CH34x - RNS.log("Using CDC driver for "+RNS.hexrep(vid)+":"+RNS.hexrep(pid), RNS.LOG_DEBUG) + RNS.log(f"Using CDC driver for {RNS.hexrep(vid)}:{RNS.hexrep(pid)}", RNS.LOG_DEBUG) from usbserial4a.cdcacmserial4a import CdcAcmSerial proxy = CdcAcmSerial @@ -466,31 +466,31 @@ class RNodeInterface(Interface): self.validcfg = True if (self.frequency < RNodeInterface.FREQ_MIN or self.frequency > RNodeInterface.FREQ_MAX): - RNS.log("Invalid frequency configured for "+str(self), RNS.LOG_ERROR) + RNS.log(f"Invalid frequency configured for {self}", RNS.LOG_ERROR) self.validcfg = False if (self.txpower < 0 or self.txpower > 22): - RNS.log("Invalid TX power configured for "+str(self), RNS.LOG_ERROR) + RNS.log(f"Invalid TX power configured for {self}", RNS.LOG_ERROR) self.validcfg = False if (self.bandwidth < 7800 or self.bandwidth > 500000): - RNS.log("Invalid bandwidth configured for "+str(self), RNS.LOG_ERROR) + RNS.log(f"Invalid bandwidth configured for {self}", RNS.LOG_ERROR) self.validcfg = False if (self.sf < 5 or self.sf > 12): - RNS.log("Invalid spreading factor configured for "+str(self), RNS.LOG_ERROR) + RNS.log(f"Invalid spreading factor configured for {self}", RNS.LOG_ERROR) self.validcfg = False if (self.cr < 5 or self.cr > 8): - RNS.log("Invalid coding rate configured for "+str(self), RNS.LOG_ERROR) + RNS.log(f"Invalid coding rate configured for {self}", RNS.LOG_ERROR) self.validcfg = False if (self.st_alock and (self.st_alock < 0.0 or self.st_alock > 100.0)): - RNS.log("Invalid short-term airtime limit configured for "+str(self), RNS.LOG_ERROR) + RNS.log(f"Invalid short-term airtime limit configured for {self}", RNS.LOG_ERROR) self.validcfg = False if (self.lt_alock and (self.lt_alock < 0.0 or self.lt_alock > 100.0)): - RNS.log("Invalid long-term airtime limit configured for "+str(self), RNS.LOG_ERROR) + RNS.log(f"Invalid long-term airtime limit configured for {self}", RNS.LOG_ERROR) self.validcfg = False if id_interval != None and id_callsign != None: @@ -499,14 +499,14 @@ class RNodeInterface(Interface): self.id_callsign = id_callsign.encode("utf-8") self.id_interval = id_interval else: - RNS.log("The encoded ID callsign for "+str(self)+" exceeds the max length of "+str(RNodeInterface.CALLSIGN_MAX_LEN)+" bytes.", RNS.LOG_ERROR) + RNS.log(f"The encoded ID callsign for {self} exceeds the max length of {RNodeInterface.CALLSIGN_MAX_LEN} bytes.", RNS.LOG_ERROR) self.validcfg = False else: self.id_interval = None self.id_callsign = None if (not self.validcfg): - raise ValueError("The configuration for "+str(self)+" contains errors, interface is offline") + raise ValueError(f"The configuration for {self} contains errors, interface is offline") try: self.open_port() @@ -515,18 +515,18 @@ class RNodeInterface(Interface): if self.serial.is_open: self.configure_device() else: - raise IOError("Could not open serial port") + raise OSError("Could not open serial port") elif self.bt_manager != None: if self.bt_manager.connected: self.configure_device() else: - raise IOError("Could not connect to any Bluetooth devices") + raise OSError("Could not connect to any Bluetooth devices") else: - raise IOError("Neither serial port nor Bluetooth devices available") + raise OSError("Neither serial port nor Bluetooth devices available") except Exception as e: - RNS.log("Could not open serial port for interface "+str(self), RNS.LOG_ERROR) - RNS.log("The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Could not open serial port for interface {self}", RNS.LOG_ERROR) + RNS.log(f"The contained exception was: {e}", RNS.LOG_ERROR) if len(self.hw_errors) == 0: RNS.log("Reticulum will attempt to bring up this interface periodically", RNS.LOG_ERROR) thread = threading.Thread(target=self.reconnect_port, daemon=True).start() @@ -538,7 +538,7 @@ class RNodeInterface(Interface): elif self.bt_manager != None: return self.bt_manager.read() else: - raise IOError("No ports available for reading") + raise OSError("No ports available for reading") def write_mux(self, data): if self.serial != None: @@ -551,7 +551,7 @@ class RNodeInterface(Interface): self.last_port_io = time.time() return written else: - raise IOError("No ports available for writing") + raise OSError("No ports available for writing") # def reset_ble(self): # RNS.log(f"Clearing previous connection instance: "+str(self.ble)) @@ -565,7 +565,7 @@ class RNodeInterface(Interface): def open_port(self): if not self.use_ble: if self.port != None: - RNS.log("Opening serial port "+self.port+"...") + RNS.log(f"Opening serial port {self.port}...") # Get device parameters from usb4a import usb device = usb.get_usb_device(self.port) @@ -577,7 +577,7 @@ class RNodeInterface(Interface): proxy = self.pyserial.get_serial_port if vid == 0x1A86 and pid == 0x55D4: # Force CDC driver for Qinheng CH34x - RNS.log(str(self)+" using CDC driver for "+RNS.hexrep(vid)+":"+RNS.hexrep(pid), RNS.LOG_DEBUG) + RNS.log(f"{self} using CDC driver for {RNS.hexrep(vid)}:{RNS.hexrep(pid)}", RNS.LOG_DEBUG) from usbserial4a.cdcacmserial4a import CdcAcmSerial proxy = CdcAcmSerial @@ -616,9 +616,9 @@ class RNodeInterface(Interface): self.serial.USB_READ_TIMEOUT_MILLIS = 100 self.serial.timeout = 0.1 - RNS.log(str(self)+" USB read buffer size set to "+RNS.prettysize(self.serial.DEFAULT_READ_BUFFER_SIZE), RNS.LOG_DEBUG) - RNS.log(str(self)+" USB read timeout set to "+str(self.serial.USB_READ_TIMEOUT_MILLIS)+"ms", RNS.LOG_DEBUG) - RNS.log(str(self)+" USB write timeout set to "+str(self.serial.USB_WRITE_TIMEOUT_MILLIS)+"ms", RNS.LOG_DEBUG) + RNS.log(f"{self} USB read buffer size set to {RNS.prettysize(self.serial.DEFAULT_READ_BUFFER_SIZE)}", RNS.LOG_DEBUG) + RNS.log(f"{self} USB read timeout set to {self.serial.USB_READ_TIMEOUT_MILLIS}ms", RNS.LOG_DEBUG) + RNS.log(f"{self} USB write timeout set to {self.serial.USB_WRITE_TIMEOUT_MILLIS}ms", RNS.LOG_DEBUG) elif self.allow_bluetooth: if self.bt_manager == None: @@ -660,17 +660,17 @@ class RNodeInterface(Interface): RNS.log(f"RNode detect timed out over {self.port}", RNS.LOG_ERROR) if not self.detected: - raise IOError("Could not detect device") + raise OSError("Could not detect device") else: if self.platform == KISS.PLATFORM_ESP32 or self.platform == KISS.PLATFORM_NRF52: self.display = True if not self.firmware_ok: - raise IOError("Invalid device firmware") + raise OSError("Invalid device firmware") if self.serial != None and self.port != None: self.timeout = 200 - RNS.log("Serial port "+self.port+" is now open") + RNS.log(f"Serial port {self.port} is now open") if self.bt_manager != None and self.bt_manager.connected: self.timeout = 1500 @@ -680,11 +680,11 @@ class RNodeInterface(Interface): self.initRadio() if (self.validateRadioState()): self.interface_ready = True - RNS.log(str(self)+" is configured and powered up") + RNS.log(f"{self} is configured and powered up") sleep(0.3) self.online = True else: - RNS.log("After configuring "+str(self)+", the reported radio parameters did not match your configuration.", RNS.LOG_ERROR) + RNS.log(f"After configuring {self}, the reported radio parameters did not match your configuration.", RNS.LOG_ERROR) RNS.log("Make sure that your hardware actually supports the parameters specified in the configuration", RNS.LOG_ERROR) RNS.log("Aborting RNode startup", RNS.LOG_ERROR) @@ -693,7 +693,7 @@ class RNodeInterface(Interface): if self.bt_manager != None: self.bt_manager.close() - raise IOError("RNode interface did not pass configuration validation") + raise OSError("RNode interface did not pass configuration validation") def initRadio(self): @@ -728,45 +728,45 @@ class RNodeInterface(Interface): kiss_command = bytes([KISS.FEND, KISS.CMD_DETECT, KISS.DETECT_REQ, KISS.FEND, KISS.CMD_FW_VERSION, 0x00, KISS.FEND, KISS.CMD_PLATFORM, 0x00, KISS.FEND, KISS.CMD_MCU, 0x00, KISS.FEND]) written = self.write_mux(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while detecting hardware for "+str(self)) + raise OSError(f"An IO error occurred while detecting hardware for {self}") def leave(self): kiss_command = bytes([KISS.FEND, KISS.CMD_LEAVE, 0xFF, KISS.FEND]) written = self.write_mux(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while sending host left command to device") + raise OSError("An IO error occurred while sending host left command to device") def enable_bluetooth(self): kiss_command = bytes([KISS.FEND, KISS.CMD_BT_CTRL, 0x01, KISS.FEND]) written = self.write_mux(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while sending bluetooth enable command to device") + raise OSError("An IO error occurred while sending bluetooth enable command to device") def disable_bluetooth(self): kiss_command = bytes([KISS.FEND, KISS.CMD_BT_CTRL, 0x00, KISS.FEND]) written = self.write_mux(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while sending bluetooth disable command to device") + raise OSError("An IO error occurred while sending bluetooth disable command to device") def bluetooth_pair(self): kiss_command = bytes([KISS.FEND, KISS.CMD_BT_CTRL, 0x02, KISS.FEND]) written = self.write_mux(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while sending bluetooth pair command to device") + raise OSError("An IO error occurred while sending bluetooth pair command to device") def enable_external_framebuffer(self): if self.display != None: kiss_command = bytes([KISS.FEND, KISS.CMD_FB_EXT, 0x01, KISS.FEND]) written = self.write_mux(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while enabling external framebuffer on device") + raise OSError("An IO error occurred while enabling external framebuffer on device") def disable_external_framebuffer(self): if self.display != None: kiss_command = bytes([KISS.FEND, KISS.CMD_FB_EXT, 0x00, KISS.FEND]) written = self.write_mux(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while disabling external framebuffer on device") + raise OSError("An IO error occurred while disabling external framebuffer on device") FB_PIXEL_WIDTH = 64 FB_BITS_PER_PIXEL = 1 @@ -791,13 +791,13 @@ class RNodeInterface(Interface): written = self.write_mux(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while writing framebuffer data device") + raise OSError("An IO error occurred while writing framebuffer data device") def hard_reset(self): kiss_command = bytes([KISS.FEND, KISS.CMD_RESET, 0xf8, KISS.FEND]) written = self.write_mux(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while restarting device") + raise OSError("An IO error occurred while restarting device") sleep(4.0); def setFrequency(self): @@ -810,7 +810,7 @@ class RNodeInterface(Interface): kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_FREQUENCY])+data+bytes([KISS.FEND]) written = self.write_mux(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while configuring frequency for "+str(self)) + raise OSError(f"An IO error occurred while configuring frequency for {self}") def setBandwidth(self): c1 = self.bandwidth >> 24 @@ -822,28 +822,28 @@ class RNodeInterface(Interface): kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_BANDWIDTH])+data+bytes([KISS.FEND]) written = self.write_mux(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while configuring bandwidth for "+str(self)) + raise OSError(f"An IO error occurred while configuring bandwidth for {self}") def setTXPower(self): txp = bytes([self.txpower]) kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_TXPOWER])+txp+bytes([KISS.FEND]) written = self.write_mux(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while configuring TX power for "+str(self)) + raise OSError(f"An IO error occurred while configuring TX power for {self}") def setSpreadingFactor(self): sf = bytes([self.sf]) kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_SF])+sf+bytes([KISS.FEND]) written = self.write_mux(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while configuring spreading factor for "+str(self)) + raise OSError(f"An IO error occurred while configuring spreading factor for {self}") def setCodingRate(self): cr = bytes([self.cr]) kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_CR])+cr+bytes([KISS.FEND]) written = self.write_mux(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while configuring coding rate for "+str(self)) + raise OSError(f"An IO error occurred while configuring coding rate for {self}") def setSTALock(self): if self.st_alock != None: @@ -855,7 +855,7 @@ class RNodeInterface(Interface): kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_ST_ALOCK])+data+bytes([KISS.FEND]) written = self.write_mux(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while configuring short-term airtime limit for "+str(self)) + raise OSError(f"An IO error occurred while configuring short-term airtime limit for {self}") def setLTALock(self): if self.lt_alock != None: @@ -867,14 +867,14 @@ class RNodeInterface(Interface): kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_LT_ALOCK])+data+bytes([KISS.FEND]) written = self.write_mux(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while configuring long-term airtime limit for "+str(self)) + raise OSError(f"An IO error occurred while configuring long-term airtime limit for {self}") def setRadioState(self, state): self.state = state kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_RADIO_STATE])+bytes([state])+bytes([KISS.FEND]) written = self.write_mux(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while configuring radio state for "+str(self)) + raise OSError(f"An IO error occurred while configuring radio state for {self}") def validate_firmware(self): if (self.maj_version > RNodeInterface.REQUIRED_FW_VER_MAJ): @@ -887,17 +887,17 @@ class RNodeInterface(Interface): if self.firmware_ok: return - RNS.log("The firmware version of the connected RNode is "+str(self.maj_version)+"."+str(self.min_version), RNS.LOG_ERROR) - RNS.log("This version of Reticulum requires at least version "+str(RNodeInterface.REQUIRED_FW_VER_MAJ)+"."+str(RNodeInterface.REQUIRED_FW_VER_MIN), RNS.LOG_ERROR) + RNS.log(f"The firmware version of the connected RNode is {self.maj_version}.{self.min_version}", RNS.LOG_ERROR) + RNS.log(f"This version of Reticulum requires at least version {RNodeInterface.REQUIRED_FW_VER_MAJ}.{RNodeInterface.REQUIRED_FW_VER_MIN}", RNS.LOG_ERROR) RNS.log("Please update your RNode firmware with rnodeconf from https://github.com/markqvist/reticulum/") - error_description = "The firmware version of the connected RNode is "+str(self.maj_version)+"."+str(self.min_version)+". " - error_description += "This version of Reticulum requires at least version "+str(RNodeInterface.REQUIRED_FW_VER_MAJ)+"."+str(RNodeInterface.REQUIRED_FW_VER_MIN)+". " + error_description = f"The firmware version of the connected RNode is {self.maj_version}.{self.min_version}. " + error_description += f"This version of Reticulum requires at least version {RNodeInterface.REQUIRED_FW_VER_MAJ}.{RNodeInterface.REQUIRED_FW_VER_MIN}. " error_description += "Please update your RNode firmware with rnodeconf from: https://github.com/markqvist/rnodeconfigutil/" self.hw_errors.append({"error": KISS.ERROR_INVALID_FIRMWARE, "description": error_description}) def validateRadioState(self): - RNS.log("Waiting for radio configuration validation for "+str(self)+"...", RNS.LOG_VERBOSE) + RNS.log(f"Waiting for radio configuration validation for {self}...", RNS.LOG_VERBOSE) if not self.platform == KISS.PLATFORM_ESP32: sleep(1.00); else: @@ -937,7 +937,7 @@ class RNodeInterface(Interface): try: self.bitrate = self.r_sf * ( (4.0/self.r_cr) / (math.pow(2,self.r_sf)/(self.r_bandwidth/1000)) ) * 1000 self.bitrate_kbps = round(self.bitrate/1000.0, 2) - RNS.log(str(self)+" On-air bitrate is now "+str(self.bitrate_kbps)+ " kbps", RNS.LOG_VERBOSE) + RNS.log(f"{self} On-air bitrate is now {self.bitrate_kbps} kbps", RNS.LOG_VERBOSE) except: self.bitrate = 0 @@ -969,7 +969,7 @@ class RNodeInterface(Interface): self.txb += datalen if written != len(frame): - raise IOError("Serial interface only wrote "+str(written)+" bytes of "+str(len(data))) + raise OSError(f"Serial interface only wrote {written} bytes of {len(data)}") else: self.queue(data) @@ -1042,7 +1042,7 @@ class RNodeInterface(Interface): command_buffer = command_buffer+bytes([byte]) if (len(command_buffer) == 4): self.r_frequency = command_buffer[0] << 24 | command_buffer[1] << 16 | command_buffer[2] << 8 | command_buffer[3] - RNS.log(str(self)+" Radio reporting frequency is "+str(self.r_frequency/1000000.0)+" MHz", RNS.LOG_DEBUG) + RNS.log(f"{self} Radio reporting frequency is {self.r_frequency / 1000000.0} MHz", RNS.LOG_DEBUG) self.updateBitrate() elif (command == KISS.CMD_BANDWIDTH): @@ -1058,26 +1058,26 @@ class RNodeInterface(Interface): command_buffer = command_buffer+bytes([byte]) if (len(command_buffer) == 4): self.r_bandwidth = command_buffer[0] << 24 | command_buffer[1] << 16 | command_buffer[2] << 8 | command_buffer[3] - RNS.log(str(self)+" Radio reporting bandwidth is "+str(self.r_bandwidth/1000.0)+" KHz", RNS.LOG_DEBUG) + RNS.log(f"{self} Radio reporting bandwidth is {self.r_bandwidth / 1000.0} KHz", RNS.LOG_DEBUG) self.updateBitrate() elif (command == KISS.CMD_TXPOWER): self.r_txpower = byte - RNS.log(str(self)+" Radio reporting TX power is "+str(self.r_txpower)+" dBm", RNS.LOG_DEBUG) + RNS.log(f"{self} Radio reporting TX power is {self.r_txpower} dBm", RNS.LOG_DEBUG) elif (command == KISS.CMD_SF): self.r_sf = byte - RNS.log(str(self)+" Radio reporting spreading factor is "+str(self.r_sf), RNS.LOG_DEBUG) + RNS.log(f"{self} Radio reporting spreading factor is {self.r_sf}", RNS.LOG_DEBUG) self.updateBitrate() elif (command == KISS.CMD_CR): self.r_cr = byte - RNS.log(str(self)+" Radio reporting coding rate is "+str(self.r_cr), RNS.LOG_DEBUG) + RNS.log(f"{self} Radio reporting coding rate is {self.r_cr}", RNS.LOG_DEBUG) self.updateBitrate() elif (command == KISS.CMD_RADIO_STATE): self.r_state = byte if self.r_state: - RNS.log(str(self)+" Radio reporting state is online", RNS.LOG_DEBUG) + RNS.log(f"{self} Radio reporting state is online", RNS.LOG_DEBUG) else: - RNS.log(str(self)+" Radio reporting state is offline", RNS.LOG_DEBUG) + RNS.log(f"{self} Radio reporting state is offline", RNS.LOG_DEBUG) elif (command == KISS.CMD_RADIO_LOCK): self.r_lock = byte @@ -1156,7 +1156,7 @@ class RNodeInterface(Interface): if (len(command_buffer) == 2): at = command_buffer[0] << 8 | command_buffer[1] self.r_st_alock = at/100.0 - RNS.log(str(self)+" Radio reporting short-term airtime limit is "+str(self.r_st_alock)+"%", RNS.LOG_DEBUG) + RNS.log(f"{self} Radio reporting short-term airtime limit is {self.r_st_alock}%", RNS.LOG_DEBUG) elif (command == KISS.CMD_LT_ALOCK): if (byte == KISS.FESC): escape = True @@ -1171,7 +1171,7 @@ class RNodeInterface(Interface): if (len(command_buffer) == 2): at = command_buffer[0] << 8 | command_buffer[1] self.r_lt_alock = at/100.0 - RNS.log(str(self)+" Radio reporting long-term airtime limit is "+str(self.r_lt_alock)+"%", RNS.LOG_DEBUG) + RNS.log(f"{self} Radio reporting long-term airtime limit is {self.r_lt_alock}%", RNS.LOG_DEBUG) elif (command == KISS.CMD_STAT_CHTM): if (byte == KISS.FESC): escape = True @@ -1217,9 +1217,9 @@ class RNodeInterface(Interface): self.r_preamble_symbols = prs self.r_premable_time_ms = prt self.r_csma_slot_time_ms = cst - RNS.log(str(self)+" Radio reporting symbol time is "+str(round(self.r_symbol_time_ms,2))+"ms (at "+str(self.r_symbol_rate)+" baud)", RNS.LOG_DEBUG) - RNS.log(str(self)+" Radio reporting preamble is "+str(self.r_preamble_symbols)+" symbols ("+str(self.r_premable_time_ms)+"ms)", RNS.LOG_DEBUG) - RNS.log(str(self)+" Radio reporting CSMA slot time is "+str(self.r_csma_slot_time_ms)+"ms", RNS.LOG_DEBUG) + RNS.log(f"{self} Radio reporting symbol time is {round(self.r_symbol_time_ms, 2)}ms (at {self.r_symbol_rate} baud)", RNS.LOG_DEBUG) + RNS.log(f"{self} Radio reporting preamble is {self.r_preamble_symbols} symbols ({self.r_premable_time_ms}ms)", RNS.LOG_DEBUG) + RNS.log(f"{self} Radio reporting CSMA slot time is {self.r_csma_slot_time_ms}ms", RNS.LOG_DEBUG) elif (command == KISS.CMD_STAT_BAT): if (byte == KISS.FESC): escape = True @@ -1247,26 +1247,26 @@ class RNodeInterface(Interface): self.mcu = byte elif (command == KISS.CMD_ERROR): if (byte == KISS.ERROR_INITRADIO): - RNS.log(str(self)+" hardware initialisation error (code "+RNS.hexrep(byte)+")", RNS.LOG_ERROR) - raise IOError("Radio initialisation failure") + RNS.log(f"{self} hardware initialisation error (code {RNS.hexrep(byte)})", RNS.LOG_ERROR) + raise OSError("Radio initialisation failure") elif (byte == KISS.ERROR_TXFAILED): - RNS.log(str(self)+" hardware TX error (code "+RNS.hexrep(byte)+")", RNS.LOG_ERROR) - raise IOError("Hardware transmit failure") + RNS.log(f"{self} hardware TX error (code {RNS.hexrep(byte)})", RNS.LOG_ERROR) + raise OSError("Hardware transmit failure") elif (byte == KISS.ERROR_MEMORY_LOW): - RNS.log(str(self)+" hardware error (code "+RNS.hexrep(byte)+"): Memory exhausted", RNS.LOG_ERROR) + RNS.log(f"{self} hardware error (code {RNS.hexrep(byte)}): Memory exhausted", RNS.LOG_ERROR) self.hw_errors.append({"error": KISS.ERROR_MEMORY_LOW, "description": "Memory exhausted on connected device"}) elif (byte == KISS.ERROR_MODEM_TIMEOUT): - RNS.log(str(self)+" hardware error (code "+RNS.hexrep(byte)+"): Modem communication timed out", RNS.LOG_ERROR) + RNS.log(f"{self} hardware error (code {RNS.hexrep(byte)}): Modem communication timed out", RNS.LOG_ERROR) self.hw_errors.append({"error": KISS.ERROR_MODEM_TIMEOUT, "description": "Modem communication timed out on connected device"}) else: - RNS.log(str(self)+" hardware error (code "+RNS.hexrep(byte)+")", RNS.LOG_ERROR) - raise IOError("Unknown hardware failure") + RNS.log(f"{self} hardware error (code {RNS.hexrep(byte)})", RNS.LOG_ERROR) + raise OSError("Unknown hardware failure") elif (command == KISS.CMD_RESET): if (byte == 0xF8): if self.platform == KISS.PLATFORM_ESP32: if self.online: RNS.log("Detected reset while device was online, reinitialising device...", RNS.LOG_ERROR) - raise IOError("ESP32 reset") + raise OSError("ESP32 reset") elif (command == KISS.CMD_READY): self.process_queue() elif (command == KISS.CMD_DETECT): @@ -1278,7 +1278,7 @@ class RNodeInterface(Interface): if got == 0: time_since_last = int(time.time()*1000) - last_read_ms if len(data_buffer) > 0 and time_since_last > self.timeout: - RNS.log(str(self)+" serial read timeout in command "+str(command), RNS.LOG_WARNING) + RNS.log(f"{self} serial read timeout in command {command}", RNS.LOG_WARNING) data_buffer = b"" in_frame = False command = KISS.CMD_UNKNOWN @@ -1287,22 +1287,22 @@ class RNodeInterface(Interface): if self.id_interval != None and self.id_callsign != None: if self.first_tx != None: if time.time() > self.first_tx + self.id_interval: - RNS.log("Interface "+str(self)+" is transmitting beacon data: "+str(self.id_callsign.decode("utf-8")), RNS.LOG_DEBUG) + RNS.log(f"Interface {self} is transmitting beacon data: {self.id_callsign.decode('utf-8')}", RNS.LOG_DEBUG) self.processOutgoing(self.id_callsign) if (time.time() - self.last_port_io > self.port_io_timeout): self.detect() if (time.time() - self.last_port_io > self.port_io_timeout*3): - raise IOError("Connected port for "+str(self)+" became unresponsive") + raise OSError(f"Connected port for {self} became unresponsive") if self.bt_manager != None: sleep(0.08) except Exception as e: self.online = False - RNS.log("A serial port occurred, the contained exception was: "+str(e), RNS.LOG_ERROR) - RNS.log("The interface "+str(self)+" experienced an unrecoverable error and is now offline.", RNS.LOG_ERROR) + RNS.log(f"A serial port occurred, the contained exception was: {e}", RNS.LOG_ERROR) + RNS.log(f"The interface {self} experienced an unrecoverable error and is now offline.", RNS.LOG_ERROR) if RNS.Reticulum.panic_on_interface_error: RNS.panic() @@ -1330,10 +1330,10 @@ class RNodeInterface(Interface): try: time.sleep(self.reconnect_w) if self.serial != None and self.port != None: - RNS.log("Attempting to reconnect serial port "+str(self.port)+" for "+str(self)+"...", RNS.LOG_EXTREME) + RNS.log(f"Attempting to reconnect serial port {self.port} for {self}...", RNS.LOG_EXTREME) if self.bt_manager != None: - RNS.log("Attempting to reconnect Bluetooth device for "+str(self)+"...", RNS.LOG_EXTREME) + RNS.log(f"Attempting to reconnect Bluetooth device for {self}...", RNS.LOG_EXTREME) self.open_port() @@ -1352,10 +1352,10 @@ class RNodeInterface(Interface): self.enable_external_framebuffer() except Exception as e: - RNS.log("Error while reconnecting RNode, the contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Error while reconnecting RNode, the contained exception was: {e}", RNS.LOG_ERROR) if self.online: - RNS.log("Reconnected serial port for "+str(self)) + RNS.log(f"Reconnected serial port for {self}") def detach(self): self.detached = True @@ -1399,7 +1399,7 @@ class RNodeInterface(Interface): return data def __str__(self): - return "RNodeInterface["+str(self.name)+"]" + return f"RNodeInterface[{self.name}]" class BLEConnection(BluetoothDispatcher): UART_SERVICE_UUID = "6e400001-b5a3-f393-e0a9-e50e24dcca9e" @@ -1472,7 +1472,7 @@ class BLEConnection(BluetoothDispatcher): RNS.trace_exception(e) def __init__(self, owner=None, target_name=None, target_bt_addr=None): - super(BLEConnection, self).__init__() + super().__init__() self.owner = owner self.target_name = target_name self.target_bt_addr = target_bt_addr diff --git a/RNS/Interfaces/Android/SerialInterface.py b/RNS/Interfaces/Android/SerialInterface.py index 7d3d905..db7d47a 100644 --- a/RNS/Interfaces/Android/SerialInterface.py +++ b/RNS/Interfaces/Android/SerialInterface.py @@ -98,17 +98,17 @@ class SerialInterface(Interface): try: self.open_port() except Exception as e: - RNS.log("Could not open serial port for interface "+str(self), RNS.LOG_ERROR) + RNS.log(f"Could not open serial port for interface {self}", RNS.LOG_ERROR) raise e if self.serial.is_open: self.configure_device() else: - raise IOError("Could not open serial port") + raise OSError("Could not open serial port") def open_port(self): - RNS.log("Opening serial port "+self.port+"...") + RNS.log(f"Opening serial port {self.port}...") # Get device parameters from usb4a import usb device = usb.get_usb_device(self.port) @@ -120,7 +120,7 @@ class SerialInterface(Interface): proxy = self.pyserial.get_serial_port if vid == 0x1A86 and pid == 0x55D4: # Force CDC driver for Qinheng CH34x - RNS.log(str(self)+" using CDC driver for "+RNS.hexrep(vid)+":"+RNS.hexrep(pid), RNS.LOG_DEBUG) + RNS.log(f"{self} using CDC driver for {RNS.hexrep(vid)}:{RNS.hexrep(pid)}", RNS.LOG_DEBUG) from usbserial4a.cdcacmserial4a import CdcAcmSerial proxy = CdcAcmSerial @@ -159,9 +159,9 @@ class SerialInterface(Interface): self.serial.USB_READ_TIMEOUT_MILLIS = 100 self.serial.timeout = 0.1 - RNS.log(str(self)+" USB read buffer size set to "+RNS.prettysize(self.serial.DEFAULT_READ_BUFFER_SIZE), RNS.LOG_DEBUG) - RNS.log(str(self)+" USB read timeout set to "+str(self.serial.USB_READ_TIMEOUT_MILLIS)+"ms", RNS.LOG_DEBUG) - RNS.log(str(self)+" USB write timeout set to "+str(self.serial.USB_WRITE_TIMEOUT_MILLIS)+"ms", RNS.LOG_DEBUG) + RNS.log(f"{self} USB read buffer size set to {RNS.prettysize(self.serial.DEFAULT_READ_BUFFER_SIZE)}", RNS.LOG_DEBUG) + RNS.log(f"{self} USB read timeout set to {self.serial.USB_READ_TIMEOUT_MILLIS}ms", RNS.LOG_DEBUG) + RNS.log(f"{self} USB write timeout set to {self.serial.USB_WRITE_TIMEOUT_MILLIS}ms", RNS.LOG_DEBUG) def configure_device(self): sleep(0.5) @@ -169,7 +169,7 @@ class SerialInterface(Interface): thread.daemon = True thread.start() self.online = True - RNS.log("Serial port "+self.port+" is now open", RNS.LOG_VERBOSE) + RNS.log(f"Serial port {self.port} is now open", RNS.LOG_VERBOSE) def processIncoming(self, data): @@ -184,7 +184,7 @@ class SerialInterface(Interface): written = self.serial.write(data) self.txb += len(data) if written != len(data): - raise IOError("Serial interface only wrote "+str(written)+" bytes of "+str(len(data))) + raise OSError(f"Serial interface only wrote {written} bytes of {len(data)}") def readLoop(self): try: @@ -228,8 +228,8 @@ class SerialInterface(Interface): except Exception as e: self.online = False - RNS.log("A serial port error occurred, the contained exception was: "+str(e), RNS.LOG_ERROR) - RNS.log("The interface "+str(self)+" experienced an unrecoverable error and is now offline.", RNS.LOG_ERROR) + RNS.log(f"A serial port error occurred, the contained exception was: {e}", RNS.LOG_ERROR) + RNS.log(f"The interface {self} experienced an unrecoverable error and is now offline.", RNS.LOG_ERROR) if RNS.Reticulum.panic_on_interface_error: RNS.panic() @@ -244,17 +244,17 @@ class SerialInterface(Interface): while not self.online: try: time.sleep(5) - RNS.log("Attempting to reconnect serial port "+str(self.port)+" for "+str(self)+"...", RNS.LOG_VERBOSE) + RNS.log(f"Attempting to reconnect serial port {self.port} for {self}...", RNS.LOG_VERBOSE) self.open_port() if self.serial.is_open: self.configure_device() except Exception as e: - RNS.log("Error while reconnecting port, the contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Error while reconnecting port, the contained exception was: {e}", RNS.LOG_ERROR) - RNS.log("Reconnected serial port for "+str(self)) + RNS.log(f"Reconnected serial port for {self}") def should_ingress_limit(self): return False def __str__(self): - return "SerialInterface["+self.name+"]" + return f"SerialInterface[{self.name}]" diff --git a/RNS/Interfaces/Android/__init__.py b/RNS/Interfaces/Android/__init__.py index ba9eae1..b92fa56 100644 --- a/RNS/Interfaces/Android/__init__.py +++ b/RNS/Interfaces/Android/__init__.py @@ -23,5 +23,5 @@ import os import glob -modules = glob.glob(os.path.dirname(__file__)+"/*.py") +modules = glob.glob(f"{os.path.dirname(__file__)}/*.py") __all__ = [ os.path.basename(f)[:-3] for f in modules if not f.endswith('__init__.py')] \ No newline at end of file diff --git a/RNS/Interfaces/AutoInterface.py b/RNS/Interfaces/AutoInterface.py index 75c52d2..06ed77c 100644 --- a/RNS/Interfaces/AutoInterface.py +++ b/RNS/Interfaces/AutoInterface.py @@ -35,7 +35,7 @@ import RNS class AutoInterface(Interface): DEFAULT_DISCOVERY_PORT = 29716 DEFAULT_DATA_PORT = 42671 - DEFAULT_GROUP_ID = "reticulum".encode("utf-8") + DEFAULT_GROUP_ID = b"reticulum" SCOPE_LINK = "2" SCOPE_ADMIN = "4" @@ -169,32 +169,32 @@ class AutoInterface(Interface): self.group_hash = RNS.Identity.full_hash(self.group_id) g = self.group_hash - #gt = "{:02x}".format(g[1]+(g[0]<<8)) + #gt = f"{g[1] + (g[0] << 8):02x}" gt = "0" - gt += ":"+"{:02x}".format(g[3]+(g[2]<<8)) - gt += ":"+"{:02x}".format(g[5]+(g[4]<<8)) - gt += ":"+"{:02x}".format(g[7]+(g[6]<<8)) - gt += ":"+"{:02x}".format(g[9]+(g[8]<<8)) - gt += ":"+"{:02x}".format(g[11]+(g[10]<<8)) - gt += ":"+"{:02x}".format(g[13]+(g[12]<<8)) - self.mcast_discovery_address = "ff"+self.multicast_address_type+self.discovery_scope+":"+gt + gt += f":{g[3] + (g[2] << 8):02x}" + gt += f":{g[5] + (g[4] << 8):02x}" + gt += f":{g[7] + (g[6] << 8):02x}" + gt += f":{g[9] + (g[8] << 8):02x}" + gt += f":{g[11] + (g[10] << 8):02x}" + gt += f":{g[13] + (g[12] << 8):02x}" + self.mcast_discovery_address = f"ff{self.multicast_address_type}{self.discovery_scope}:{gt}" suitable_interfaces = 0 for ifname in self.list_interfaces(): try: if RNS.vendor.platformutils.is_darwin() and ifname in AutoInterface.DARWIN_IGNORE_IFS and not ifname in self.allowed_interfaces: - RNS.log(str(self)+" skipping Darwin AWDL or tethering interface "+str(ifname), RNS.LOG_EXTREME) + RNS.log(f"{self} skipping Darwin AWDL or tethering interface {ifname}", RNS.LOG_EXTREME) elif RNS.vendor.platformutils.is_darwin() and ifname == "lo0": - RNS.log(str(self)+" skipping Darwin loopback interface "+str(ifname), RNS.LOG_EXTREME) + RNS.log(f"{self} skipping Darwin loopback interface {ifname}", RNS.LOG_EXTREME) elif RNS.vendor.platformutils.is_android() and ifname in AutoInterface.ANDROID_IGNORE_IFS and not ifname in self.allowed_interfaces: - RNS.log(str(self)+" skipping Android system interface "+str(ifname), RNS.LOG_EXTREME) + RNS.log(f"{self} skipping Android system interface {ifname}", RNS.LOG_EXTREME) elif ifname in self.ignored_interfaces: - RNS.log(str(self)+" ignoring disallowed interface "+str(ifname), RNS.LOG_EXTREME) + RNS.log(f"{self} ignoring disallowed interface {ifname}", RNS.LOG_EXTREME) elif ifname in AutoInterface.ALL_IGNORE_IFS: - RNS.log(str(self)+" skipping interface "+str(ifname), RNS.LOG_EXTREME) + RNS.log(f"{self} skipping interface {ifname}", RNS.LOG_EXTREME) else: if len(self.allowed_interfaces) > 0 and not ifname in self.allowed_interfaces: - RNS.log(str(self)+" ignoring interface "+str(ifname)+" since it was not allowed", RNS.LOG_EXTREME) + RNS.log(f"{self} ignoring interface {ifname} since it was not allowed", RNS.LOG_EXTREME) else: addresses = self.list_addresses(ifname) if self.netinfo.AF_INET6 in addresses: @@ -213,10 +213,10 @@ class AutoInterface(Interface): RNS.log(f"{self} Selecting link-local address {link_local_addr} for interface {ifname}", RNS.LOG_EXTREME) if link_local_addr == None: - RNS.log(str(self)+" No link-local IPv6 address configured for "+str(ifname)+", skipping interface", RNS.LOG_EXTREME) + RNS.log(f"{self} No link-local IPv6 address configured for {ifname}, skipping interface", RNS.LOG_EXTREME) else: mcast_addr = self.mcast_discovery_address - RNS.log(str(self)+" Creating multicast discovery listener on "+str(ifname)+" with address "+str(mcast_addr), RNS.LOG_EXTREME) + RNS.log(f"{self} Creating multicast discovery listener on {ifname} with address {mcast_addr}", RNS.LOG_EXTREME) # Struct with interface index if_struct = struct.pack("I", self.interface_name_to_index(ifname)) @@ -243,7 +243,7 @@ class AutoInterface(Interface): else: if self.discovery_scope == AutoInterface.SCOPE_LINK: - addr_info = socket.getaddrinfo(mcast_addr+"%"+ifname, self.discovery_port, socket.AF_INET6, socket.SOCK_DGRAM) + addr_info = socket.getaddrinfo(f"{mcast_addr}%{ifname}", self.discovery_port, socket.AF_INET6, socket.SOCK_DGRAM) else: addr_info = socket.getaddrinfo(mcast_addr, self.discovery_port, socket.AF_INET6, socket.SOCK_DGRAM) @@ -267,7 +267,7 @@ class AutoInterface(Interface): RNS.log(f"Could not configure the system interface {ifname} for use with {self}, skipping it. The contained exception was: {e}", RNS.LOG_ERROR) if suitable_interfaces == 0: - RNS.log(str(self)+" could not autoconfigure. This interface currently provides no connectivity.", RNS.LOG_WARNING) + RNS.log(f"{self} could not autoconfigure. This interface currently provides no connectivity.", RNS.LOG_WARNING) else: self.receives = True @@ -277,13 +277,13 @@ class AutoInterface(Interface): self.bitrate = AutoInterface.BITRATE_GUESS peering_wait = self.announce_interval*1.2 - RNS.log(str(self)+" discovering peers for "+str(round(peering_wait, 2))+" seconds...", RNS.LOG_VERBOSE) + RNS.log(f"{self} discovering peers for {round(peering_wait, 2)} seconds...", RNS.LOG_VERBOSE) self.owner = owner socketserver.UDPServer.address_family = socket.AF_INET6 for ifname in self.adopted_interfaces: - local_addr = self.adopted_interfaces[ifname]+"%"+str(self.interface_name_to_index(ifname)) + local_addr = f"{self.adopted_interfaces[ifname]}%{self.interface_name_to_index(ifname)}" addr_info = socket.getaddrinfo(local_addr, self.data_port, socket.AF_INET6, socket.SOCK_DGRAM) address = addr_info[0][4] @@ -317,7 +317,7 @@ class AutoInterface(Interface): if data == expected_hash: self.add_peer(ipv6_src[0], ifname) else: - RNS.log(str(self)+" received peering packet on "+str(ifname)+" from "+str(ipv6_src[0])+", but authentication hash was incorrect.", RNS.LOG_DEBUG) + RNS.log(f"{self} received peering packet on {ifname} from {ipv6_src[0]}, but authentication hash was incorrect.", RNS.LOG_DEBUG) def peer_jobs(self): while True: @@ -335,7 +335,7 @@ class AutoInterface(Interface): # Remove any timed out peers for peer_addr in timed_out_peers: removed_peer = self.peers.pop(peer_addr) - RNS.log(str(self)+" removed peer "+str(peer_addr)+" on "+str(removed_peer[0]), RNS.LOG_DEBUG) + RNS.log(f"{self} removed peer {peer_addr} on {removed_peer[0]}", RNS.LOG_DEBUG) for ifname in self.adopted_interfaces: # Check that the link-local address has not changed @@ -349,25 +349,25 @@ class AutoInterface(Interface): link_local_addr = self.descope_linklocal(address["addr"]) if link_local_addr != self.adopted_interfaces[ifname]: old_link_local_address = self.adopted_interfaces[ifname] - RNS.log("Replacing link-local address "+str(old_link_local_address)+" for "+str(ifname)+" with "+str(link_local_addr), RNS.LOG_DEBUG) + RNS.log(f"Replacing link-local address {old_link_local_address} for {ifname} with {link_local_addr}", RNS.LOG_DEBUG) self.adopted_interfaces[ifname] = link_local_addr self.link_local_addresses.append(link_local_addr) if old_link_local_address in self.link_local_addresses: self.link_local_addresses.remove(old_link_local_address) - local_addr = link_local_addr+"%"+ifname + local_addr = f"{link_local_addr}%{ifname}" addr_info = socket.getaddrinfo(local_addr, self.data_port, socket.AF_INET6, socket.SOCK_DGRAM) listen_address = addr_info[0][4] if ifname in self.interface_servers: - RNS.log("Shutting down previous UDP listener for "+str(self)+" "+str(ifname), RNS.LOG_DEBUG) + RNS.log(f"Shutting down previous UDP listener for {self} {ifname}", RNS.LOG_DEBUG) previous_server = self.interface_servers[ifname] def shutdown_server(): previous_server.shutdown() threading.Thread(target=shutdown_server, daemon=True).start() - RNS.log("Starting new UDP listener for "+str(self)+" "+str(ifname), RNS.LOG_DEBUG) + RNS.log(f"Starting new UDP listener for {self} {ifname}", RNS.LOG_DEBUG) udp_server = socketserver.UDPServer(listen_address, self.handler_factory(self.processIncoming)) self.interface_servers[ifname] = udp_server @@ -379,7 +379,7 @@ class AutoInterface(Interface): self.carrier_changed = True except Exception as e: - RNS.log("Could not get device information while updating link-local addresses for "+str(self)+". The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Could not get device information while updating link-local addresses for {self}. The contained exception was: {e}", RNS.LOG_ERROR) # Check multicast echo timeouts last_multicast_echo = 0 @@ -389,12 +389,12 @@ class AutoInterface(Interface): if now - last_multicast_echo > self.multicast_echo_timeout: if ifname in self.timed_out_interfaces and self.timed_out_interfaces[ifname] == False: self.carrier_changed = True - RNS.log("Multicast echo timeout for "+str(ifname)+". Carrier lost.", RNS.LOG_WARNING) + RNS.log(f"Multicast echo timeout for {ifname}. Carrier lost.", RNS.LOG_WARNING) self.timed_out_interfaces[ifname] = True else: if ifname in self.timed_out_interfaces and self.timed_out_interfaces[ifname] == True: self.carrier_changed = True - RNS.log(str(self)+" Carrier recovered on "+str(ifname), RNS.LOG_WARNING) + RNS.log(f"{self} Carrier recovered on {ifname}", RNS.LOG_WARNING) self.timed_out_interfaces[ifname] = False @@ -417,7 +417,7 @@ class AutoInterface(Interface): except Exception as e: if (ifname in self.timed_out_interfaces and self.timed_out_interfaces[ifname] == False) or not ifname in self.timed_out_interfaces: - RNS.log(str(self)+" Detected possible carrier loss on "+str(ifname)+": "+str(e), RNS.LOG_WARNING) + RNS.log(f"{self} Detected possible carrier loss on {ifname}: {e}", RNS.LOG_WARNING) else: pass @@ -431,12 +431,12 @@ class AutoInterface(Interface): if ifname != None: self.multicast_echoes[ifname] = time.time() else: - RNS.log(str(self)+" received multicast echo on unexpected interface "+str(ifname), RNS.LOG_WARNING) + RNS.log(f"{self} received multicast echo on unexpected interface {ifname}", RNS.LOG_WARNING) else: if not addr in self.peers: self.peers[addr] = [ifname, time.time()] - RNS.log(str(self)+" added peer "+str(addr)+" on "+str(ifname), RNS.LOG_DEBUG) + RNS.log(f"{self} added peer {addr} on {ifname}", RNS.LOG_DEBUG) else: self.refresh_peer(addr) @@ -464,12 +464,12 @@ class AutoInterface(Interface): if self.outbound_udp_socket == None: self.outbound_udp_socket = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM) - peer_addr = str(peer)+"%"+str(self.interface_name_to_index(self.peers[peer][0])) + peer_addr = f"{peer}%{self.interface_name_to_index(self.peers[peer][0])}" addr_info = socket.getaddrinfo(peer_addr, self.data_port, socket.AF_INET6, socket.SOCK_DGRAM) self.outbound_udp_socket.sendto(data, addr_info[0][4]) except Exception as e: - RNS.log("Could not transmit on "+str(self)+". The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Could not transmit on {self}. The contained exception was: {e}", RNS.LOG_ERROR) self.txb += len(data) @@ -481,7 +481,7 @@ class AutoInterface(Interface): return False def __str__(self): - return "AutoInterface["+self.name+"]" + return f"AutoInterface[{self.name}]" class AutoInterfaceHandler(socketserver.BaseRequestHandler): def __init__(self, callback, *args, **keys): diff --git a/RNS/Interfaces/I2PInterface.py b/RNS/Interfaces/I2PInterface.py index 64dee4a..7448bfa 100644 --- a/RNS/Interfaces/I2PInterface.py +++ b/RNS/Interfaces/I2PInterface.py @@ -90,7 +90,7 @@ class I2PController: time.sleep(0.10) if self.loop == None: - RNS.log("Could not get event loop for "+str(self)+", waiting for event loop to appear", RNS.LOG_VERBOSE) + RNS.log(f"Could not get event loop for {self}, waiting for event loop to appear", RNS.LOG_VERBOSE) while self.loop == None: self.loop = asyncio.get_event_loop() @@ -101,7 +101,7 @@ class I2PController: self.loop.run_forever() except Exception as e: self.ready = False - RNS.log("Exception on event loop for "+str(self)+": "+str(e), RNS.LOG_ERROR) + RNS.log(f"Exception on event loop for {self}: {e}", RNS.LOG_ERROR) finally: self.loop.close() @@ -136,7 +136,7 @@ class I2PController: if not self.client_tunnels[i2p_destination]: try: async def tunnel_up(): - RNS.log("Bringing up I2P tunnel to "+str(owner)+", this may take a while...", RNS.LOG_INFO) + RNS.log(f"Bringing up I2P tunnel to {owner}, this may take a while...", RNS.LOG_INFO) tunnel = self.i2plib.ClientTunnel(i2p_destination, owner.local_addr, sam_address=self.sam_address, loop=self.loop) self.i2plib_tunnels[i2p_destination] = tunnel await tunnel.run() @@ -145,7 +145,7 @@ class I2PController: result = asyncio.run_coroutine_threadsafe(tunnel_up(), self.loop).result() if not i2p_destination in self.i2plib_tunnels: - raise IOError("No tunnel control instance was created") + raise OSError("No tunnel control instance was created") else: tn = self.i2plib_tunnels[i2p_destination] @@ -167,19 +167,19 @@ class I2PController: try: owner.socket.shutdown(socket.SHUT_RDWR) except Exception as e: - RNS.log("Error while shutting down socket for "+str(owner)+": "+str(e)) + RNS.log(f"Error while shutting down socket for {owner}: {e}") try: owner.socket.close() except Exception as e: - RNS.log("Error while closing socket for "+str(owner)+": "+str(e)) + RNS.log(f"Error while closing socket for {owner}: {e}") self.client_tunnels[i2p_destination] = True owner.awaiting_i2p_tunnel = False - RNS.log(str(owner)+" tunnel setup complete", RNS.LOG_VERBOSE) + RNS.log(f"{owner} tunnel setup complete", RNS.LOG_VERBOSE) else: - raise IOError("Got no status response from SAM API") + raise OSError("Got no status response from SAM API") except ConnectionRefusedError as e: raise e @@ -188,7 +188,7 @@ class I2PController: raise e except Exception as e: - RNS.log("Unexpected error type from I2P SAM: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Unexpected error type from I2P SAM: {e}", RNS.LOG_ERROR) raise e else: @@ -197,16 +197,16 @@ class I2PController: i2p_exception = i2ptunnel.status["exception"] if i2ptunnel.status["setup_ran"] == False: - RNS.log(str(self)+" I2P tunnel setup did not complete", RNS.LOG_ERROR) + RNS.log(f"{self} I2P tunnel setup did not complete", RNS.LOG_ERROR) self.stop_tunnel(i2ptunnel) return False elif i2p_exception != None: - RNS.log("An error ocurred while setting up I2P tunnel to "+str(i2p_destination), RNS.LOG_ERROR) + RNS.log(f"An error ocurred while setting up I2P tunnel to {i2p_destination}", RNS.LOG_ERROR) if isinstance(i2p_exception, RNS.vendor.i2plib.exceptions.CantReachPeer): - RNS.log("The I2P daemon can't reach peer "+str(i2p_destination), RNS.LOG_ERROR) + RNS.log(f"The I2P daemon can't reach peer {i2p_destination}", RNS.LOG_ERROR) elif isinstance(i2p_exception, RNS.vendor.i2plib.exceptions.DuplicatedDest): RNS.log("The I2P daemon reported that the destination is already in use", RNS.LOG_ERROR) @@ -218,19 +218,19 @@ class I2PController: RNS.log("The I2P daemon reported that the stream session ID doesn't exist", RNS.LOG_ERROR) elif isinstance(i2p_exception, RNS.vendor.i2plib.exceptions.InvalidKey): - RNS.log("The I2P daemon reported that the key for "+str(i2p_destination)+" is invalid", RNS.LOG_ERROR) + RNS.log(f"The I2P daemon reported that the key for {i2p_destination} is invalid", RNS.LOG_ERROR) elif isinstance(i2p_exception, RNS.vendor.i2plib.exceptions.KeyNotFound): - RNS.log("The I2P daemon could not find the key for "+str(i2p_destination), RNS.LOG_ERROR) + RNS.log(f"The I2P daemon could not find the key for {i2p_destination}", RNS.LOG_ERROR) elif isinstance(i2p_exception, RNS.vendor.i2plib.exceptions.PeerNotFound): - RNS.log("The I2P daemon mould not find the peer "+str(i2p_destination), RNS.LOG_ERROR) + RNS.log(f"The I2P daemon mould not find the peer {i2p_destination}", RNS.LOG_ERROR) elif isinstance(i2p_exception, RNS.vendor.i2plib.exceptions.I2PError): RNS.log("The I2P daemon experienced an unspecified error", RNS.LOG_ERROR) elif isinstance(i2p_exception, RNS.vendor.i2plib.exceptions.Timeout): - RNS.log("I2P daemon timed out while setting up client tunnel to "+str(i2p_destination), RNS.LOG_ERROR) + RNS.log(f"I2P daemon timed out while setting up client tunnel to {i2p_destination}", RNS.LOG_ERROR) RNS.log("Resetting I2P tunnel and retrying later", RNS.LOG_ERROR) @@ -238,13 +238,13 @@ class I2PController: return False elif i2ptunnel.status["setup_failed"] == True: - RNS.log(str(self)+" Unspecified I2P tunnel setup error, resetting I2P tunnel", RNS.LOG_ERROR) + RNS.log(f"{self} Unspecified I2P tunnel setup error, resetting I2P tunnel", RNS.LOG_ERROR) self.stop_tunnel(i2ptunnel) return False else: - RNS.log(str(self)+" Got no status from SAM API, resetting I2P tunnel", RNS.LOG_ERROR) + RNS.log(f"{self} Got no status from SAM API, resetting I2P tunnel", RNS.LOG_ERROR) self.stop_tunnel(i2ptunnel) return False @@ -259,11 +259,11 @@ class I2PController: # Old format i2p_dest_hash_of = RNS.Identity.full_hash(RNS.Identity.full_hash(owner.name.encode("utf-8"))) - i2p_keyfile_of = self.storagepath+"/"+RNS.hexrep(i2p_dest_hash_of, delimit=False)+".i2p" + i2p_keyfile_of = f"{self.storagepath}/{RNS.hexrep(i2p_dest_hash_of, delimit=False)}.i2p" # New format i2p_dest_hash_nf = RNS.Identity.full_hash(RNS.Identity.full_hash(owner.name.encode("utf-8"))+RNS.Identity.full_hash(RNS.Transport.identity.hash)) - i2p_keyfile_nf = self.storagepath+"/"+RNS.hexrep(i2p_dest_hash_nf, delimit=False)+".i2p" + i2p_keyfile_nf = f"{self.storagepath}/{RNS.hexrep(i2p_dest_hash_nf, delimit=False)}.i2p" # Use old format if a key is already present if os.path.isfile(i2p_keyfile_of): @@ -279,7 +279,7 @@ class I2PController: key_file.write(i2p_dest.private_key.base64) key_file.close() else: - key_file = open(i2p_keyfile, "r") + key_file = open(i2p_keyfile) prvd = key_file.read() key_file.close() i2p_dest = self.i2plib.Destination(data=prvd, has_private_key=True) @@ -294,12 +294,12 @@ class I2PController: if self.server_tunnels[i2p_b32] == False: try: async def tunnel_up(): - RNS.log(str(owner)+" Bringing up I2P endpoint, this may take a while...", RNS.LOG_INFO) + RNS.log(f"{owner} Bringing up I2P endpoint, this may take a while...", RNS.LOG_INFO) tunnel = self.i2plib.ServerTunnel((owner.bind_ip, owner.bind_port), loop=self.loop, destination=i2p_dest, sam_address=self.sam_address) self.i2plib_tunnels[i2p_b32] = tunnel await tunnel.run() owner.online = True - RNS.log(str(owner)+ " endpoint setup complete. Now reachable at: "+str(i2p_dest.base32)+".b32.i2p", RNS.LOG_VERBOSE) + RNS.log(f"{owner} endpoint setup complete. Now reachable at: {i2p_dest.base32}.b32.i2p", RNS.LOG_VERBOSE) asyncio.run_coroutine_threadsafe(tunnel_up(), self.loop).result() self.server_tunnels[i2p_b32] = True @@ -313,7 +313,7 @@ class I2PController: i2p_exception = i2ptunnel.status["exception"] if i2ptunnel.status["setup_ran"] == False: - RNS.log(str(self)+" I2P tunnel setup did not complete", RNS.LOG_ERROR) + RNS.log(f"{self} I2P tunnel setup did not complete", RNS.LOG_ERROR) self.stop_tunnel(i2ptunnel) return False @@ -322,7 +322,7 @@ class I2PController: RNS.log("An error ocurred while setting up I2P tunnel", RNS.LOG_ERROR) if isinstance(i2p_exception, RNS.vendor.i2plib.exceptions.CantReachPeer): - RNS.log("The I2P daemon can't reach peer "+str(i2p_destination), RNS.LOG_ERROR) + RNS.log(f"The I2P daemon can't reach peer {i2p_destination}", RNS.LOG_ERROR) elif isinstance(i2p_exception, RNS.vendor.i2plib.exceptions.DuplicatedDest): RNS.log("The I2P daemon reported that the destination is already in use", RNS.LOG_ERROR) @@ -334,19 +334,19 @@ class I2PController: RNS.log("The I2P daemon reported that the stream session ID doesn't exist", RNS.LOG_ERROR) elif isinstance(i2p_exception, RNS.vendor.i2plib.exceptions.InvalidKey): - RNS.log("The I2P daemon reported that the key for "+str(i2p_destination)+" is invalid", RNS.LOG_ERROR) + RNS.log(f"The I2P daemon reported that the key for {i2p_destination} is invalid", RNS.LOG_ERROR) elif isinstance(i2p_exception, RNS.vendor.i2plib.exceptions.KeyNotFound): - RNS.log("The I2P daemon could not find the key for "+str(i2p_destination), RNS.LOG_ERROR) + RNS.log(f"The I2P daemon could not find the key for {i2p_destination}", RNS.LOG_ERROR) elif isinstance(i2p_exception, RNS.vendor.i2plib.exceptions.PeerNotFound): - RNS.log("The I2P daemon mould not find the peer "+str(i2p_destination), RNS.LOG_ERROR) + RNS.log(f"The I2P daemon mould not find the peer {i2p_destination}", RNS.LOG_ERROR) elif isinstance(i2p_exception, RNS.vendor.i2plib.exceptions.I2PError): RNS.log("The I2P daemon experienced an unspecified error", RNS.LOG_ERROR) elif isinstance(i2p_exception, RNS.vendor.i2plib.exceptions.Timeout): - RNS.log("I2P daemon timed out while setting up client tunnel to "+str(i2p_destination), RNS.LOG_ERROR) + RNS.log(f"I2P daemon timed out while setting up client tunnel to {i2p_destination}", RNS.LOG_ERROR) RNS.log("Resetting I2P tunnel and retrying later", RNS.LOG_ERROR) @@ -354,13 +354,13 @@ class I2PController: return False elif i2ptunnel.status["setup_failed"] == True: - RNS.log(str(self)+" Unspecified I2P tunnel setup error, resetting I2P tunnel", RNS.LOG_ERROR) + RNS.log(f"{self} Unspecified I2P tunnel setup error, resetting I2P tunnel", RNS.LOG_ERROR) self.stop_tunnel(i2ptunnel) return False else: - RNS.log(str(self)+" Got no status from SAM API, resetting I2P tunnel", RNS.LOG_ERROR) + RNS.log(f"{self} Got no status from SAM API, resetting I2P tunnel", RNS.LOG_ERROR) self.stop_tunnel(i2ptunnel) return False @@ -475,11 +475,11 @@ class I2PInterfacePeer(Interface): self.target_port = self.bind_port if not self.parent_interface.i2p.client_tunnel(self, target_i2p_dest): - RNS.log(str(self)+" I2P control process experienced an error, requesting new tunnel...", RNS.LOG_ERROR) + RNS.log(f"{self} I2P control process experienced an error, requesting new tunnel...", RNS.LOG_ERROR) self.awaiting_i2p_tunnel = True except Exception as e: - RNS.log("Error while while configuring "+str(self)+": "+str(e), RNS.LOG_ERROR) + RNS.log(f"Error while while configuring {self}: {e}", RNS.LOG_ERROR) RNS.log("Check that I2P is installed and running, and that SAM is enabled. Retrying tunnel setup later.", RNS.LOG_ERROR) time.sleep(8) @@ -532,16 +532,16 @@ class I2PInterfacePeer(Interface): if socket != None: target_socket.shutdown(socket.SHUT_RDWR) except Exception as e: - RNS.log("Error while shutting down socket for "+str(self)+": "+str(e)) + RNS.log(f"Error while shutting down socket for {self}: {e}") try: if socket != None: target_socket.close() except Exception as e: - RNS.log("Error while closing socket for "+str(self)+": "+str(e)) + RNS.log(f"Error while closing socket for {self}: {e}") def detach(self): - RNS.log("Detaching "+str(self), RNS.LOG_DEBUG) + RNS.log(f"Detaching {self}", RNS.LOG_DEBUG) if self.socket != None: if hasattr(self.socket, "close"): if callable(self.socket.close): @@ -550,12 +550,12 @@ class I2PInterfacePeer(Interface): try: self.socket.shutdown(socket.SHUT_RDWR) except Exception as e: - RNS.log("Error while shutting down socket for "+str(self)+": "+str(e)) + RNS.log(f"Error while shutting down socket for {self}: {e}") try: self.socket.close() except Exception as e: - RNS.log("Error while closing socket for "+str(self)+": "+str(e)) + RNS.log(f"Error while closing socket for {self}: {e}") self.socket = None @@ -568,8 +568,8 @@ class I2PInterfacePeer(Interface): except Exception as e: if initial: if not self.awaiting_i2p_tunnel: - RNS.log("Initial connection for "+str(self)+" could not be established: "+str(e), RNS.LOG_ERROR) - RNS.log("Leaving unconnected and retrying connection in "+str(I2PInterfacePeer.RECONNECT_WAIT)+" seconds.", RNS.LOG_ERROR) + RNS.log(f"Initial connection for {self} could not be established: {e}", RNS.LOG_ERROR) + RNS.log(f"Leaving unconnected and retrying connection in {I2PInterfacePeer.RECONNECT_WAIT} seconds.", RNS.LOG_ERROR) return False @@ -600,7 +600,7 @@ class I2PInterfacePeer(Interface): attempts += 1 if self.max_reconnect_tries != None and attempts > self.max_reconnect_tries: - RNS.log("Max reconnection attempts reached for "+str(self), RNS.LOG_ERROR) + RNS.log(f"Max reconnection attempts reached for {self}", RNS.LOG_ERROR) self.teardown() break @@ -609,12 +609,12 @@ class I2PInterfacePeer(Interface): except Exception as e: if not self.awaiting_i2p_tunnel: - RNS.log("Connection attempt for "+str(self)+" failed: "+str(e), RNS.LOG_DEBUG) + RNS.log(f"Connection attempt for {self} failed: {e}", RNS.LOG_DEBUG) else: - RNS.log(str(self)+" still waiting for I2P tunnel to appear", RNS.LOG_VERBOSE) + RNS.log(f"{self} still waiting for I2P tunnel to appear", RNS.LOG_VERBOSE) if not self.never_connected: - RNS.log(str(self)+" Re-established connection via I2P tunnel", RNS.LOG_INFO) + RNS.log(f"{self} Re-established connection via I2P tunnel", RNS.LOG_INFO) self.reconnecting = False thread = threading.Thread(target=self.read_loop) @@ -625,7 +625,7 @@ class I2PInterfacePeer(Interface): else: RNS.log("Attempt to reconnect on a non-initiator I2P interface. This should not happen.", RNS.LOG_ERROR) - raise IOError("Attempt to reconnect on a non-initiator I2P interface") + raise OSError("Attempt to reconnect on a non-initiator I2P interface") def processIncoming(self, data): self.rxb += len(data) @@ -656,8 +656,8 @@ class I2PInterfacePeer(Interface): self.parent_interface.txb += len(data) except Exception as e: - RNS.log("Exception occurred while transmitting via "+str(self)+", tearing down interface", RNS.LOG_ERROR) - RNS.log("The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Exception occurred while transmitting via {self}, tearing down interface", RNS.LOG_ERROR) + RNS.log(f"The contained exception was: {e}", RNS.LOG_ERROR) self.teardown() @@ -683,7 +683,7 @@ class I2PInterfacePeer(Interface): if self.socket != None: self.socket.sendall(bytes([HDLC.FLAG, HDLC.FLAG])) except Exception as e: - RNS.log("An error ocurred while sending I2P keepalive. The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"An error ocurred while sending I2P keepalive. The contained exception was: {e}", RNS.LOG_ERROR) self.shutdown_socket(self.socket) should_run = False @@ -693,12 +693,12 @@ class I2PInterfacePeer(Interface): try: self.socket.shutdown(socket.SHUT_RDWR) except Exception as e: - RNS.log("Error while shutting down socket for "+str(self)+": "+str(e)) + RNS.log(f"Error while shutting down socket for {self}: {e}") try: self.socket.close() except Exception as e: - RNS.log("Error while closing socket for "+str(self)+": "+str(e)) + RNS.log(f"Error while closing socket for {self}: {e}") should_run = False @@ -782,10 +782,10 @@ class I2PInterfacePeer(Interface): self.wd_reset = False if self.initiator and not self.detached: - RNS.log("Socket for "+str(self)+" was closed, attempting to reconnect...", RNS.LOG_WARNING) + RNS.log(f"Socket for {self} was closed, attempting to reconnect...", RNS.LOG_WARNING) self.reconnect() else: - RNS.log("Socket for remote client "+str(self)+" was closed.", RNS.LOG_VERBOSE) + RNS.log(f"Socket for remote client {self} was closed.", RNS.LOG_VERBOSE) self.teardown() break @@ -793,7 +793,7 @@ class I2PInterfacePeer(Interface): except Exception as e: self.online = False - RNS.log("An interface error occurred for "+str(self)+", the contained exception was: "+str(e), RNS.LOG_WARNING) + RNS.log(f"An interface error occurred for {self}, the contained exception was: {e}", RNS.LOG_WARNING) if self.initiator: RNS.log("Attempting to reconnect...", RNS.LOG_WARNING) @@ -803,12 +803,12 @@ class I2PInterfacePeer(Interface): def teardown(self): if self.initiator and not self.detached: - RNS.log("The interface "+str(self)+" experienced an unrecoverable error and is being torn down. Restart Reticulum to attempt to open this interface again.", RNS.LOG_ERROR) + RNS.log(f"The interface {self} experienced an unrecoverable error and is being torn down. Restart Reticulum to attempt to open this interface again.", RNS.LOG_ERROR) if RNS.Reticulum.panic_on_interface_error: RNS.panic() else: - RNS.log("The interface "+str(self)+" is being torn down.", RNS.LOG_VERBOSE) + RNS.log(f"The interface {self} is being torn down.", RNS.LOG_VERBOSE) self.online = False self.OUT = False @@ -824,7 +824,7 @@ class I2PInterfacePeer(Interface): def __str__(self): - return "I2PInterfacePeer["+str(self.name)+"]" + return f"I2PInterfacePeer[{self.name}]" class I2PInterface(Interface): @@ -895,11 +895,11 @@ class I2PInterface(Interface): while True: try: if not self.i2p.server_tunnel(self): - RNS.log(str(self)+" I2P control process experienced an error, requesting new tunnel...", RNS.LOG_ERROR) + RNS.log(f"{self} I2P control process experienced an error, requesting new tunnel...", RNS.LOG_ERROR) self.online = False except Exception as e: - RNS.log("Error while while configuring "+str(self)+": "+str(e), RNS.LOG_ERROR) + RNS.log(f"Error while while configuring {self}: {e}", RNS.LOG_ERROR) RNS.log("Check that I2P is installed and running, and that SAM is enabled. Retrying tunnel setup later.", RNS.LOG_ERROR) time.sleep(15) @@ -911,7 +911,7 @@ class I2PInterface(Interface): if peers != None: for peer_addr in peers: - interface_name = self.name+" to "+peer_addr + interface_name = f"{self.name} to {peer_addr}" peer_interface = I2PInterfacePeer(self, self.owner, interface_name, peer_addr) peer_interface.OUT = True peer_interface.IN = True @@ -921,7 +921,7 @@ class I2PInterface(Interface): def incoming_connection(self, handler): RNS.log("Accepting incoming I2P connection", RNS.LOG_VERBOSE) - interface_name = "Connected peer on "+self.name + interface_name = f"Connected peer on {self.name}" spawned_interface = I2PInterfacePeer(self, self.owner, interface_name, connected_socket=handler.request) spawned_interface.OUT = True spawned_interface.IN = True @@ -954,7 +954,7 @@ class I2PInterface(Interface): spawned_interface.announce_rate_penalty = self.announce_rate_penalty spawned_interface.mode = self.mode spawned_interface.HW_MTU = self.HW_MTU - RNS.log("Spawned new I2PInterface Peer: "+str(spawned_interface), RNS.LOG_VERBOSE) + RNS.log(f"Spawned new I2PInterface Peer: {spawned_interface}", RNS.LOG_VERBOSE) RNS.Transport.interfaces.append(spawned_interface) self.clients += 1 spawned_interface.read_loop() @@ -969,11 +969,11 @@ class I2PInterface(Interface): if from_spawned: self.oa_freq_deque.append(time.time()) def detach(self): - RNS.log("Detaching "+str(self), RNS.LOG_DEBUG) + RNS.log(f"Detaching {self}", RNS.LOG_DEBUG) self.i2p.stop() def __str__(self): - return "I2PInterface["+self.name+"]" + return f"I2PInterface[{self.name}]" class I2PInterfaceHandler(socketserver.BaseRequestHandler): def __init__(self, callback, *args, **keys): diff --git a/RNS/Interfaces/Interface.py b/RNS/Interfaces/Interface.py index eb987a2..e72e9c8 100755 --- a/RNS/Interfaces/Interface.py +++ b/RNS/Interfaces/Interface.py @@ -140,7 +140,7 @@ class Interface: selected_announce_packet = announce_packet if selected_announce_packet != None: - RNS.log("Releasing held announce packet "+str(selected_announce_packet)+" from "+str(self), RNS.LOG_EXTREME) + RNS.log(f"Releasing held announce packet {selected_announce_packet} from {self}", RNS.LOG_EXTREME) self.ic_held_release = time.time() + self.ic_held_release_interval self.held_announces.pop(selected_announce_packet.destination_hash) def release(): @@ -148,8 +148,8 @@ class Interface: threading.Thread(target=release, daemon=True).start() except Exception as e: - RNS.log("An error occurred while processing held announces for "+str(self), RNS.LOG_ERROR) - RNS.log("The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"An error occurred while processing held announces for {self}", RNS.LOG_ERROR) + RNS.log(f"The contained exception was: {e}", RNS.LOG_ERROR) def received_announce(self): self.ia_freq_deque.append(time.time()) @@ -234,7 +234,7 @@ class Interface: except Exception as e: self.announce_queue = [] - RNS.log("Error while processing announce queue on "+str(self)+". The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Error while processing announce queue on {self}. The contained exception was: {e}", RNS.LOG_ERROR) RNS.log("The announce queue for this interface has been cleared.", RNS.LOG_ERROR) def detach(self): diff --git a/RNS/Interfaces/KISSInterface.py b/RNS/Interfaces/KISSInterface.py index 4dad095..13c9197 100644 --- a/RNS/Interfaces/KISSInterface.py +++ b/RNS/Interfaces/KISSInterface.py @@ -113,17 +113,17 @@ class KISSInterface(Interface): try: self.open_port() except Exception as e: - RNS.log("Could not open serial port "+self.port, RNS.LOG_ERROR) + RNS.log(f"Could not open serial port {self.port}", RNS.LOG_ERROR) raise e if self.serial.is_open: self.configure_device() else: - raise IOError("Could not open serial port") + raise OSError("Could not open serial port") def open_port(self): - RNS.log("Opening serial port "+self.port+"...", RNS.LOG_VERBOSE) + RNS.log(f"Opening serial port {self.port}...", RNS.LOG_VERBOSE) self.serial = self.pyserial.Serial( port = self.port, baudrate = self.speed, @@ -146,7 +146,7 @@ class KISSInterface(Interface): thread.daemon = True thread.start() self.online = True - RNS.log("Serial port "+self.port+" is now open") + RNS.log(f"Serial port {self.port} is now open") RNS.log("Configuring KISS interface parameters...") self.setPreamble(self.preamble) self.setTxTail(self.txtail) @@ -168,7 +168,7 @@ class KISSInterface(Interface): kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_TXDELAY])+bytes([preamble])+bytes([KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("Could not configure KISS interface preamble to "+str(preamble_ms)+" (command value "+str(preamble)+")") + raise OSError(f"Could not configure KISS interface preamble to {preamble_ms} (command value {preamble})") def setTxTail(self, txtail): txtail_ms = txtail @@ -181,7 +181,7 @@ class KISSInterface(Interface): kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_TXTAIL])+bytes([txtail])+bytes([KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("Could not configure KISS interface TX tail to "+str(txtail_ms)+" (command value "+str(txtail)+")") + raise OSError(f"Could not configure KISS interface TX tail to {txtail_ms} (command value {txtail})") def setPersistence(self, persistence): if persistence < 0: @@ -192,7 +192,7 @@ class KISSInterface(Interface): kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_P])+bytes([persistence])+bytes([KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("Could not configure KISS interface persistence to "+str(persistence)) + raise OSError(f"Could not configure KISS interface persistence to {persistence}") def setSlotTime(self, slottime): slottime_ms = slottime @@ -205,16 +205,16 @@ class KISSInterface(Interface): kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_SLOTTIME])+bytes([slottime])+bytes([KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("Could not configure KISS interface slot time to "+str(slottime_ms)+" (command value "+str(slottime)+")") + raise OSError(f"Could not configure KISS interface slot time to {slottime_ms} (command value {slottime})") def setFlowControl(self, flow_control): kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_READY])+bytes([0x01])+bytes([KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): if (flow_control): - raise IOError("Could not enable KISS interface flow control") + raise OSError("Could not enable KISS interface flow control") else: - raise IOError("Could not enable KISS interface flow control") + raise OSError("Could not enable KISS interface flow control") def processIncoming(self, data): @@ -244,7 +244,7 @@ class KISSInterface(Interface): self.first_tx = time.time() if written != len(frame): - raise IOError("Serial interface only wrote "+str(written)+" bytes of "+str(len(data))) + raise OSError(f"Serial interface only wrote {written} bytes of {len(data)}") else: self.queue(data) @@ -311,20 +311,20 @@ class KISSInterface(Interface): if self.flow_control: if not self.interface_ready: if time.time() > self.flow_control_locked + self.flow_control_timeout: - RNS.log("Interface "+str(self)+" is unlocking flow control due to time-out. This should not happen. Your hardware might have missed a flow-control READY command, or maybe it does not support flow-control.", RNS.LOG_WARNING) + RNS.log(f"Interface {self} is unlocking flow control due to time-out. This should not happen. Your hardware might have missed a flow-control READY command, or maybe it does not support flow-control.", RNS.LOG_WARNING) self.process_queue() if self.beacon_i != None and self.beacon_d != None: if self.first_tx != None: if time.time() > self.first_tx + self.beacon_i: - RNS.log("Interface "+str(self)+" is transmitting beacon data: "+str(self.beacon_d.decode("utf-8")), RNS.LOG_DEBUG) + RNS.log(f"Interface {self} is transmitting beacon data: {self.beacon_d.decode('utf-8')}", RNS.LOG_DEBUG) self.first_tx = None self.processOutgoing(self.beacon_d) except Exception as e: self.online = False - RNS.log("A serial port error occurred, the contained exception was: "+str(e), RNS.LOG_ERROR) - RNS.log("The interface "+str(self)+" experienced an unrecoverable error and is now offline.", RNS.LOG_ERROR) + RNS.log(f"A serial port error occurred, the contained exception was: {e}", RNS.LOG_ERROR) + RNS.log(f"The interface {self} experienced an unrecoverable error and is now offline.", RNS.LOG_ERROR) if RNS.Reticulum.panic_on_interface_error: RNS.panic() @@ -339,17 +339,17 @@ class KISSInterface(Interface): while not self.online: try: time.sleep(5) - RNS.log("Attempting to reconnect serial port "+str(self.port)+" for "+str(self)+"...", RNS.LOG_VERBOSE) + RNS.log(f"Attempting to reconnect serial port {self.port} for {self}...", RNS.LOG_VERBOSE) self.open_port() if self.serial.is_open: self.configure_device() except Exception as e: - RNS.log("Error while reconnecting port, the contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Error while reconnecting port, the contained exception was: {e}", RNS.LOG_ERROR) - RNS.log("Reconnected serial port for "+str(self)) + RNS.log(f"Reconnected serial port for {self}") def should_ingress_limit(self): return False def __str__(self): - return "KISSInterface["+self.name+"]" \ No newline at end of file + return f"KISSInterface[{self.name}]" \ No newline at end of file diff --git a/RNS/Interfaces/LocalInterface.py b/RNS/Interfaces/LocalInterface.py index c256b2c..3cef987 100644 --- a/RNS/Interfaces/LocalInterface.py +++ b/RNS/Interfaces/LocalInterface.py @@ -133,10 +133,10 @@ class LocalClientInterface(Interface): self.connect() except Exception as e: - RNS.log("Connection attempt for "+str(self)+" failed: "+str(e), RNS.LOG_DEBUG) + RNS.log(f"Connection attempt for {self} failed: {e}", RNS.LOG_DEBUG) if not self.never_connected: - RNS.log("Reconnected socket for "+str(self)+".", RNS.LOG_INFO) + RNS.log(f"Reconnected socket for {self}.", RNS.LOG_INFO) self.reconnecting = False thread = threading.Thread(target=self.read_loop) @@ -149,7 +149,7 @@ class LocalClientInterface(Interface): else: RNS.log("Attempt to reconnect on a non-initiator shared local interface. This should not happen.", RNS.LOG_ERROR) - raise IOError("Attempt to reconnect on a non-initiator local interface") + raise OSError("Attempt to reconnect on a non-initiator local interface") def processIncoming(self, data): @@ -188,8 +188,8 @@ class LocalClientInterface(Interface): self.parent_interface.txb += len(data) except Exception as e: - RNS.log("Exception occurred while transmitting via "+str(self)+", tearing down interface", RNS.LOG_ERROR) - RNS.log("The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Exception occurred while transmitting via {self}, tearing down interface", RNS.LOG_ERROR) + RNS.log(f"The contained exception was: {e}", RNS.LOG_ERROR) self.teardown() @@ -226,7 +226,7 @@ class LocalClientInterface(Interface): else: self.online = False if self.is_connected_to_shared_instance and not self.detached: - RNS.log("Socket for "+str(self)+" was closed, attempting to reconnect...", RNS.LOG_WARNING) + RNS.log(f"Socket for {self} was closed, attempting to reconnect...", RNS.LOG_WARNING) RNS.Transport.shared_connection_disappeared() self.reconnect() else: @@ -237,26 +237,26 @@ class LocalClientInterface(Interface): except Exception as e: self.online = False - RNS.log("An interface error occurred, the contained exception was: "+str(e), RNS.LOG_ERROR) - RNS.log("Tearing down "+str(self), RNS.LOG_ERROR) + RNS.log(f"An interface error occurred, the contained exception was: {e}", RNS.LOG_ERROR) + RNS.log(f"Tearing down {self}", RNS.LOG_ERROR) self.teardown() def detach(self): if self.socket != None: if hasattr(self.socket, "close"): if callable(self.socket.close): - RNS.log("Detaching "+str(self), RNS.LOG_DEBUG) + RNS.log(f"Detaching {self}", RNS.LOG_DEBUG) self.detached = True try: self.socket.shutdown(socket.SHUT_RDWR) except Exception as e: - RNS.log("Error while shutting down socket for "+str(self)+": "+str(e)) + RNS.log(f"Error while shutting down socket for {self}: {e}") try: self.socket.close() except Exception as e: - RNS.log("Error while closing socket for "+str(self)+": "+str(e)) + RNS.log(f"Error while closing socket for {self}: {e}") self.socket = None @@ -276,7 +276,7 @@ class LocalClientInterface(Interface): RNS.Transport.owner._should_persist_data() if nowarning == False: - RNS.log("The interface "+str(self)+" experienced an unrecoverable error and is being torn down. Restart Reticulum to attempt to open this interface again.", RNS.LOG_ERROR) + RNS.log(f"The interface {self} experienced an unrecoverable error and is being torn down. Restart Reticulum to attempt to open this interface again.", RNS.LOG_ERROR) if RNS.Reticulum.panic_on_interface_error: RNS.panic() @@ -288,7 +288,7 @@ class LocalClientInterface(Interface): def __str__(self): - return "LocalInterface["+str(self.target_port)+"]" + return f"LocalInterface[{self.target_port}]" class LocalServerInterface(Interface): @@ -360,7 +360,7 @@ class LocalServerInterface(Interface): if from_spawned: self.oa_freq_deque.append(time.time()) def __str__(self): - return "Shared Instance["+str(self.bind_port)+"]" + return f"Shared Instance[{self.bind_port}]" class LocalInterfaceHandler(socketserver.BaseRequestHandler): def __init__(self, callback, *args, **keys): diff --git a/RNS/Interfaces/PipeInterface.py b/RNS/Interfaces/PipeInterface.py index ffe5c9e..87c67f2 100644 --- a/RNS/Interfaces/PipeInterface.py +++ b/RNS/Interfaces/PipeInterface.py @@ -72,17 +72,17 @@ class PipeInterface(Interface): self.open_pipe() except Exception as e: - RNS.log("Could connect pipe for interface "+str(self), RNS.LOG_ERROR) + RNS.log(f"Could connect pipe for interface {self}", RNS.LOG_ERROR) raise e if self.pipe_is_open: self.configure_pipe() else: - raise IOError("Could not connect pipe") + raise OSError("Could not connect pipe") def open_pipe(self): - RNS.log("Connecting subprocess pipe for "+str(self)+"...", RNS.LOG_VERBOSE) + RNS.log(f"Connecting subprocess pipe for {self}...", RNS.LOG_VERBOSE) try: self.process = subprocess.Popen(shlex.split(self.command), stdin=subprocess.PIPE, stdout=subprocess.PIPE) @@ -98,7 +98,7 @@ class PipeInterface(Interface): thread.daemon = True thread.start() self.online = True - RNS.log("Subprocess pipe for "+str(self)+" is now connected", RNS.LOG_VERBOSE) + RNS.log(f"Subprocess pipe for {self} is now connected", RNS.LOG_VERBOSE) def processIncoming(self, data): @@ -113,7 +113,7 @@ class PipeInterface(Interface): self.process.stdin.flush() self.txb += len(data) if written != len(data): - raise IOError("Pipe interface only wrote "+str(written)+" bytes of "+str(len(data))) + raise OSError(f"Pipe interface only wrote {written} bytes of {len(data)}") def readLoop(self): @@ -150,7 +150,7 @@ class PipeInterface(Interface): escape = False data_buffer = data_buffer+bytes([byte]) - RNS.log("Subprocess terminated on "+str(self)) + RNS.log(f"Subprocess terminated on {self}") self.process.kill() except Exception as e: @@ -160,8 +160,8 @@ class PipeInterface(Interface): except Exception as e: pass - RNS.log("A pipe error occurred, the contained exception was: "+str(e), RNS.LOG_ERROR) - RNS.log("The interface "+str(self)+" experienced an unrecoverable error and is now offline.", RNS.LOG_ERROR) + RNS.log(f"A pipe error occurred, the contained exception was: {e}", RNS.LOG_ERROR) + RNS.log(f"The interface {self} experienced an unrecoverable error and is now offline.", RNS.LOG_ERROR) if RNS.Reticulum.panic_on_interface_error: RNS.panic() @@ -175,14 +175,14 @@ class PipeInterface(Interface): while not self.online: try: time.sleep(self.respawn_delay) - RNS.log("Attempting to respawn subprocess for "+str(self)+"...", RNS.LOG_VERBOSE) + RNS.log(f"Attempting to respawn subprocess for {self}...", RNS.LOG_VERBOSE) self.open_pipe() if self.pipe_is_open: self.configure_pipe() except Exception as e: - RNS.log("Error while spawning subprocess, the contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Error while spawning subprocess, the contained exception was: {e}", RNS.LOG_ERROR) - RNS.log("Reconnected pipe for "+str(self)) + RNS.log(f"Reconnected pipe for {self}") def __str__(self): - return "PipeInterface["+self.name+"]" + return f"PipeInterface[{self.name}]" diff --git a/RNS/Interfaces/RNodeInterface.py b/RNS/Interfaces/RNodeInterface.py index 7781163..fb68e1f 100644 --- a/RNS/Interfaces/RNodeInterface.py +++ b/RNS/Interfaces/RNodeInterface.py @@ -211,31 +211,31 @@ class RNodeInterface(Interface): self.validcfg = True if (self.frequency < RNodeInterface.FREQ_MIN or self.frequency > RNodeInterface.FREQ_MAX): - RNS.log("Invalid frequency configured for "+str(self), RNS.LOG_ERROR) + RNS.log(f"Invalid frequency configured for {self}", RNS.LOG_ERROR) self.validcfg = False if (self.txpower < 0 or self.txpower > 22): - RNS.log("Invalid TX power configured for "+str(self), RNS.LOG_ERROR) + RNS.log(f"Invalid TX power configured for {self}", RNS.LOG_ERROR) self.validcfg = False if (self.bandwidth < 7800 or self.bandwidth > 1625000): - RNS.log("Invalid bandwidth configured for "+str(self), RNS.LOG_ERROR) + RNS.log(f"Invalid bandwidth configured for {self}", RNS.LOG_ERROR) self.validcfg = False if (self.sf < 5 or self.sf > 12): - RNS.log("Invalid spreading factor configured for "+str(self), RNS.LOG_ERROR) + RNS.log(f"Invalid spreading factor configured for {self}", RNS.LOG_ERROR) self.validcfg = False if (self.cr < 5 or self.cr > 8): - RNS.log("Invalid coding rate configured for "+str(self), RNS.LOG_ERROR) + RNS.log(f"Invalid coding rate configured for {self}", RNS.LOG_ERROR) self.validcfg = False if (self.st_alock and (self.st_alock < 0.0 or self.st_alock > 100.0)): - RNS.log("Invalid short-term airtime limit configured for "+str(self), RNS.LOG_ERROR) + RNS.log(f"Invalid short-term airtime limit configured for {self}", RNS.LOG_ERROR) self.validcfg = False if (self.lt_alock and (self.lt_alock < 0.0 or self.lt_alock > 100.0)): - RNS.log("Invalid long-term airtime limit configured for "+str(self), RNS.LOG_ERROR) + RNS.log(f"Invalid long-term airtime limit configured for {self}", RNS.LOG_ERROR) self.validcfg = False if id_interval != None and id_callsign != None: @@ -244,14 +244,14 @@ class RNodeInterface(Interface): self.id_callsign = id_callsign.encode("utf-8") self.id_interval = id_interval else: - RNS.log("The encoded ID callsign for "+str(self)+" exceeds the max length of "+str(RNodeInterface.CALLSIGN_MAX_LEN)+" bytes.", RNS.LOG_ERROR) + RNS.log(f"The encoded ID callsign for {self} exceeds the max length of {RNodeInterface.CALLSIGN_MAX_LEN} bytes.", RNS.LOG_ERROR) self.validcfg = False else: self.id_interval = None self.id_callsign = None if (not self.validcfg): - raise ValueError("The configuration for "+str(self)+" contains errors, interface is offline") + raise ValueError(f"The configuration for {self} contains errors, interface is offline") try: self.open_port() @@ -259,11 +259,11 @@ class RNodeInterface(Interface): if self.serial.is_open: self.configure_device() else: - raise IOError("Could not open serial port") + raise OSError("Could not open serial port") except Exception as e: - RNS.log("Could not open serial port for interface "+str(self), RNS.LOG_ERROR) - RNS.log("The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Could not open serial port for interface {self}", RNS.LOG_ERROR) + RNS.log(f"The contained exception was: {e}", RNS.LOG_ERROR) RNS.log("Reticulum will attempt to bring up this interface periodically", RNS.LOG_ERROR) if not self.detached and not self.reconnecting: thread = threading.Thread(target=self.reconnect_port) @@ -273,7 +273,7 @@ class RNodeInterface(Interface): def open_port(self): if not self.use_ble: - RNS.log("Opening serial port "+self.port+"...") + RNS.log(f"Opening serial port {self.port}...") self.serial = self.pyserial.Serial( port = self.port, baudrate = self.speed, @@ -335,22 +335,22 @@ class RNodeInterface(Interface): RNS.log(f"RNode detect timed out over {self.port}", RNS.LOG_ERROR) if not self.detected: - RNS.log("Could not detect device for "+str(self), RNS.LOG_ERROR) + RNS.log(f"Could not detect device for {self}", RNS.LOG_ERROR) self.serial.close() else: if self.platform == KISS.PLATFORM_ESP32 or self.platform == KISS.PLATFORM_NRF52: self.display = True - RNS.log("Serial port "+self.port+" is now open") + RNS.log(f"Serial port {self.port} is now open") RNS.log("Configuring RNode interface...", RNS.LOG_VERBOSE) self.initRadio() if (self.validateRadioState()): self.interface_ready = True - RNS.log(str(self)+" is configured and powered up") + RNS.log(f"{self} is configured and powered up") sleep(0.3) self.online = True else: - RNS.log("After configuring "+str(self)+", the reported radio parameters did not match your configuration.", RNS.LOG_ERROR) + RNS.log(f"After configuring {self}, the reported radio parameters did not match your configuration.", RNS.LOG_ERROR) RNS.log("Make sure that your hardware actually supports the parameters specified in the configuration", RNS.LOG_ERROR) RNS.log("Aborting RNode startup", RNS.LOG_ERROR) self.serial.close() @@ -373,27 +373,27 @@ class RNodeInterface(Interface): kiss_command = bytes([KISS.FEND, KISS.CMD_DETECT, KISS.DETECT_REQ, KISS.FEND, KISS.CMD_FW_VERSION, 0x00, KISS.FEND, KISS.CMD_PLATFORM, 0x00, KISS.FEND, KISS.CMD_MCU, 0x00, KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while detecting hardware for "+str(self)) + raise OSError(f"An IO error occurred while detecting hardware for {self}") def leave(self): kiss_command = bytes([KISS.FEND, KISS.CMD_LEAVE, 0xFF, KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while sending host left command to device") + raise OSError("An IO error occurred while sending host left command to device") def enable_external_framebuffer(self): if self.display != None: kiss_command = bytes([KISS.FEND, KISS.CMD_FB_EXT, 0x01, KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while enabling external framebuffer on device") + raise OSError("An IO error occurred while enabling external framebuffer on device") def disable_external_framebuffer(self): if self.display != None: kiss_command = bytes([KISS.FEND, KISS.CMD_FB_EXT, 0x00, KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while disabling external framebuffer on device") + raise OSError("An IO error occurred while disabling external framebuffer on device") FB_PIXEL_WIDTH = 64 FB_BITS_PER_PIXEL = 1 @@ -417,13 +417,13 @@ class RNodeInterface(Interface): written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while writing framebuffer data device") + raise OSError("An IO error occurred while writing framebuffer data device") def hard_reset(self): kiss_command = bytes([KISS.FEND, KISS.CMD_RESET, 0xf8, KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while restarting device") + raise OSError("An IO error occurred while restarting device") sleep(2.25); def setFrequency(self): @@ -436,7 +436,7 @@ class RNodeInterface(Interface): kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_FREQUENCY])+data+bytes([KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while configuring frequency for "+str(self)) + raise OSError(f"An IO error occurred while configuring frequency for {self}") def setBandwidth(self): c1 = self.bandwidth >> 24 @@ -448,28 +448,28 @@ class RNodeInterface(Interface): kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_BANDWIDTH])+data+bytes([KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while configuring bandwidth for "+str(self)) + raise OSError(f"An IO error occurred while configuring bandwidth for {self}") def setTXPower(self): txp = bytes([self.txpower]) kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_TXPOWER])+txp+bytes([KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while configuring TX power for "+str(self)) + raise OSError(f"An IO error occurred while configuring TX power for {self}") def setSpreadingFactor(self): sf = bytes([self.sf]) kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_SF])+sf+bytes([KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while configuring spreading factor for "+str(self)) + raise OSError(f"An IO error occurred while configuring spreading factor for {self}") def setCodingRate(self): cr = bytes([self.cr]) kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_CR])+cr+bytes([KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while configuring coding rate for "+str(self)) + raise OSError(f"An IO error occurred while configuring coding rate for {self}") def setSTALock(self): if self.st_alock != None: @@ -481,7 +481,7 @@ class RNodeInterface(Interface): kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_ST_ALOCK])+data+bytes([KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while configuring short-term airtime limit for "+str(self)) + raise OSError(f"An IO error occurred while configuring short-term airtime limit for {self}") def setLTALock(self): if self.lt_alock != None: @@ -493,14 +493,14 @@ class RNodeInterface(Interface): kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_LT_ALOCK])+data+bytes([KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while configuring long-term airtime limit for "+str(self)) + raise OSError(f"An IO error occurred while configuring long-term airtime limit for {self}") def setRadioState(self, state): self.state = state kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_RADIO_STATE])+bytes([state])+bytes([KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while configuring radio state for "+str(self)) + raise OSError(f"An IO error occurred while configuring radio state for {self}") def validate_firmware(self): if (self.maj_version > RNodeInterface.REQUIRED_FW_VER_MAJ): @@ -513,14 +513,14 @@ class RNodeInterface(Interface): if self.firmware_ok: return - RNS.log("The firmware version of the connected RNode is "+str(self.maj_version)+"."+str(self.min_version), RNS.LOG_ERROR) - RNS.log("This version of Reticulum requires at least version "+str(RNodeInterface.REQUIRED_FW_VER_MAJ)+"."+str(RNodeInterface.REQUIRED_FW_VER_MIN), RNS.LOG_ERROR) + RNS.log(f"The firmware version of the connected RNode is {self.maj_version}.{self.min_version}", RNS.LOG_ERROR) + RNS.log(f"This version of Reticulum requires at least version {RNodeInterface.REQUIRED_FW_VER_MAJ}.{RNodeInterface.REQUIRED_FW_VER_MIN}", RNS.LOG_ERROR) RNS.log("Please update your RNode firmware with rnodeconf from https://github.com/markqvist/rnodeconfigutil/") RNS.panic() def validateRadioState(self): - RNS.log("Waiting for radio configuration validation for "+str(self)+"...", RNS.LOG_VERBOSE) + RNS.log(f"Waiting for radio configuration validation for {self}...", RNS.LOG_VERBOSE) if self.use_ble: sleep(1.00) else: @@ -557,7 +557,7 @@ class RNodeInterface(Interface): try: self.bitrate = self.r_sf * ( (4.0/self.r_cr) / (math.pow(2,self.r_sf)/(self.r_bandwidth/1000)) ) * 1000 self.bitrate_kbps = round(self.bitrate/1000.0, 2) - RNS.log(str(self)+" On-air bitrate is now "+str(self.bitrate_kbps)+ " kbps", RNS.LOG_VERBOSE) + RNS.log(f"{self} On-air bitrate is now {self.bitrate_kbps} kbps", RNS.LOG_VERBOSE) except: self.bitrate = 0 @@ -588,7 +588,7 @@ class RNodeInterface(Interface): self.txb += datalen if written != len(frame): - raise IOError("Serial interface only wrote "+str(written)+" bytes of "+str(len(data))) + raise OSError(f"Serial interface only wrote {written} bytes of {len(data)}") else: self.queue(data) @@ -654,7 +654,7 @@ class RNodeInterface(Interface): command_buffer = command_buffer+bytes([byte]) if (len(command_buffer) == 4): self.r_frequency = command_buffer[0] << 24 | command_buffer[1] << 16 | command_buffer[2] << 8 | command_buffer[3] - RNS.log(str(self)+" Radio reporting frequency is "+str(self.r_frequency/1000000.0)+" MHz", RNS.LOG_DEBUG) + RNS.log(f"{self} Radio reporting frequency is {self.r_frequency / 1000000.0} MHz", RNS.LOG_DEBUG) self.updateBitrate() elif (command == KISS.CMD_BANDWIDTH): @@ -670,26 +670,26 @@ class RNodeInterface(Interface): command_buffer = command_buffer+bytes([byte]) if (len(command_buffer) == 4): self.r_bandwidth = command_buffer[0] << 24 | command_buffer[1] << 16 | command_buffer[2] << 8 | command_buffer[3] - RNS.log(str(self)+" Radio reporting bandwidth is "+str(self.r_bandwidth/1000.0)+" KHz", RNS.LOG_DEBUG) + RNS.log(f"{self} Radio reporting bandwidth is {self.r_bandwidth / 1000.0} KHz", RNS.LOG_DEBUG) self.updateBitrate() elif (command == KISS.CMD_TXPOWER): self.r_txpower = byte - RNS.log(str(self)+" Radio reporting TX power is "+str(self.r_txpower)+" dBm", RNS.LOG_DEBUG) + RNS.log(f"{self} Radio reporting TX power is {self.r_txpower} dBm", RNS.LOG_DEBUG) elif (command == KISS.CMD_SF): self.r_sf = byte - RNS.log(str(self)+" Radio reporting spreading factor is "+str(self.r_sf), RNS.LOG_DEBUG) + RNS.log(f"{self} Radio reporting spreading factor is {self.r_sf}", RNS.LOG_DEBUG) self.updateBitrate() elif (command == KISS.CMD_CR): self.r_cr = byte - RNS.log(str(self)+" Radio reporting coding rate is "+str(self.r_cr), RNS.LOG_DEBUG) + RNS.log(f"{self} Radio reporting coding rate is {self.r_cr}", RNS.LOG_DEBUG) self.updateBitrate() elif (command == KISS.CMD_RADIO_STATE): self.r_state = byte if self.r_state: pass else: - RNS.log(str(self)+" Radio reporting state is offline", RNS.LOG_DEBUG) + RNS.log(f"{self} Radio reporting state is offline", RNS.LOG_DEBUG) elif (command == KISS.CMD_RADIO_LOCK): self.r_lock = byte @@ -767,7 +767,7 @@ class RNodeInterface(Interface): if (len(command_buffer) == 2): at = command_buffer[0] << 8 | command_buffer[1] self.r_st_alock = at/100.0 - RNS.log(str(self)+" Radio reporting short-term airtime limit is "+str(self.r_st_alock)+"%", RNS.LOG_DEBUG) + RNS.log(f"{self} Radio reporting short-term airtime limit is {self.r_st_alock}%", RNS.LOG_DEBUG) elif (command == KISS.CMD_LT_ALOCK): if (byte == KISS.FESC): escape = True @@ -782,7 +782,7 @@ class RNodeInterface(Interface): if (len(command_buffer) == 2): at = command_buffer[0] << 8 | command_buffer[1] self.r_lt_alock = at/100.0 - RNS.log(str(self)+" Radio reporting long-term airtime limit is "+str(self.r_lt_alock)+"%", RNS.LOG_DEBUG) + RNS.log(f"{self} Radio reporting long-term airtime limit is {self.r_lt_alock}%", RNS.LOG_DEBUG) elif (command == KISS.CMD_STAT_CHTM): if (byte == KISS.FESC): escape = True @@ -828,9 +828,9 @@ class RNodeInterface(Interface): self.r_preamble_symbols = prs self.r_premable_time_ms = prt self.r_csma_slot_time_ms = cst - RNS.log(str(self)+" Radio reporting symbol time is "+str(round(self.r_symbol_time_ms,2))+"ms (at "+str(self.r_symbol_rate)+" baud)", RNS.LOG_DEBUG) - RNS.log(str(self)+" Radio reporting preamble is "+str(self.r_preamble_symbols)+" symbols ("+str(self.r_premable_time_ms)+"ms)", RNS.LOG_DEBUG) - RNS.log(str(self)+" Radio reporting CSMA slot time is "+str(self.r_csma_slot_time_ms)+"ms", RNS.LOG_DEBUG) + RNS.log(f"{self} Radio reporting symbol time is {round(self.r_symbol_time_ms, 2)}ms (at {self.r_symbol_rate} baud)", RNS.LOG_DEBUG) + RNS.log(f"{self} Radio reporting preamble is {self.r_preamble_symbols} symbols ({self.r_premable_time_ms}ms)", RNS.LOG_DEBUG) + RNS.log(f"{self} Radio reporting CSMA slot time is {self.r_csma_slot_time_ms}ms", RNS.LOG_DEBUG) elif (command == KISS.CMD_STAT_BAT): if (byte == KISS.FESC): escape = True @@ -858,26 +858,26 @@ class RNodeInterface(Interface): self.mcu = byte elif (command == KISS.CMD_ERROR): if (byte == KISS.ERROR_INITRADIO): - RNS.log(str(self)+" hardware initialisation error (code "+RNS.hexrep(byte)+")", RNS.LOG_ERROR) - raise IOError("Radio initialisation failure") + RNS.log(f"{self} hardware initialisation error (code {RNS.hexrep(byte)})", RNS.LOG_ERROR) + raise OSError("Radio initialisation failure") elif (byte == KISS.ERROR_TXFAILED): - RNS.log(str(self)+" hardware TX error (code "+RNS.hexrep(byte)+")", RNS.LOG_ERROR) - raise IOError("Hardware transmit failure") + RNS.log(f"{self} hardware TX error (code {RNS.hexrep(byte)})", RNS.LOG_ERROR) + raise OSError("Hardware transmit failure") elif (byte == KISS.ERROR_MEMORY_LOW): - RNS.log(str(self)+" hardware error (code "+RNS.hexrep(byte)+"): Memory exhausted", RNS.LOG_ERROR) + RNS.log(f"{self} hardware error (code {RNS.hexrep(byte)}): Memory exhausted", RNS.LOG_ERROR) self.hw_errors.append({"error": KISS.ERROR_MEMORY_LOW, "description": "Memory exhausted on connected device"}) elif (byte == KISS.ERROR_MODEM_TIMEOUT): - RNS.log(str(self)+" hardware error (code "+RNS.hexrep(byte)+"): Modem communication timed out", RNS.LOG_ERROR) + RNS.log(f"{self} hardware error (code {RNS.hexrep(byte)}): Modem communication timed out", RNS.LOG_ERROR) self.hw_errors.append({"error": KISS.ERROR_MODEM_TIMEOUT, "description": "Modem communication timed out on connected device"}) else: - RNS.log(str(self)+" hardware error (code "+RNS.hexrep(byte)+")", RNS.LOG_ERROR) - raise IOError("Unknown hardware failure") + RNS.log(f"{self} hardware error (code {RNS.hexrep(byte)})", RNS.LOG_ERROR) + raise OSError("Unknown hardware failure") elif (command == KISS.CMD_RESET): if (byte == 0xF8): if self.platform == KISS.PLATFORM_ESP32: if self.online: RNS.log("Detected reset while device was online, reinitialising device...", RNS.LOG_ERROR) - raise IOError("ESP32 reset") + raise OSError("ESP32 reset") elif (command == KISS.CMD_READY): self.process_queue() elif (command == KISS.CMD_DETECT): @@ -889,7 +889,7 @@ class RNodeInterface(Interface): else: time_since_last = int(time.time()*1000) - last_read_ms if len(data_buffer) > 0 and time_since_last > self.timeout: - RNS.log(str(self)+" serial read timeout in command "+str(command), RNS.LOG_WARNING) + RNS.log(f"{self} serial read timeout in command {command}", RNS.LOG_WARNING) data_buffer = b"" in_frame = False command = KISS.CMD_UNKNOWN @@ -898,15 +898,15 @@ class RNodeInterface(Interface): if self.id_interval != None and self.id_callsign != None: if self.first_tx != None: if time.time() > self.first_tx + self.id_interval: - RNS.log("Interface "+str(self)+" is transmitting beacon data: "+str(self.id_callsign.decode("utf-8")), RNS.LOG_DEBUG) + RNS.log(f"Interface {self} is transmitting beacon data: {self.id_callsign.decode('utf-8')}", RNS.LOG_DEBUG) self.processOutgoing(self.id_callsign) sleep(0.08) except Exception as e: self.online = False - RNS.log("A serial port error occurred, the contained exception was: "+str(e), RNS.LOG_ERROR) - RNS.log("The interface "+str(self)+" experienced an unrecoverable error and is now offline.", RNS.LOG_ERROR) + RNS.log(f"A serial port error occurred, the contained exception was: {e}", RNS.LOG_ERROR) + RNS.log(f"The interface {self} experienced an unrecoverable error and is now offline.", RNS.LOG_ERROR) if RNS.Reticulum.panic_on_interface_error: RNS.panic() @@ -927,16 +927,16 @@ class RNodeInterface(Interface): while not self.online and not self.detached: try: time.sleep(5) - RNS.log("Attempting to reconnect serial port "+str(self.port)+" for "+str(self)+"...", RNS.LOG_VERBOSE) + RNS.log(f"Attempting to reconnect serial port {self.port} for {self}...", RNS.LOG_VERBOSE) self.open_port() if self.serial.is_open: self.configure_device() except Exception as e: - RNS.log("Error while reconnecting port, the contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Error while reconnecting port, the contained exception was: {e}", RNS.LOG_ERROR) self.reconnecting = False if self.online: - RNS.log("Reconnected serial port for "+str(self)) + RNS.log(f"Reconnected serial port for {self}") def detach(self): self.detached = True @@ -980,7 +980,7 @@ class RNodeInterface(Interface): return data def __str__(self): - return "RNodeInterface["+str(self.name)+"]" + return f"RNodeInterface[{self.name}]" class BLEConnection(): UART_SERVICE_UUID = "6E400001-B5A3-F393-E0A9-E50E24DCCA9E" diff --git a/RNS/Interfaces/RNodeMultiInterface.py b/RNS/Interfaces/RNodeMultiInterface.py index df3fed2..021bbb1 100644 --- a/RNS/Interfaces/RNodeMultiInterface.py +++ b/RNS/Interfaces/RNodeMultiInterface.py @@ -241,14 +241,14 @@ class RNodeMultiInterface(Interface): self.id_callsign = id_callsign.encode("utf-8") self.id_interval = id_interval else: - RNS.log("The encoded ID callsign for "+str(self)+" exceeds the max length of "+str(RNodeMultiInterface.CALLSIGN_MAX_LEN)+" bytes.", RNS.LOG_ERROR) + RNS.log(f"The encoded ID callsign for {self} exceeds the max length of {RNodeMultiInterface.CALLSIGN_MAX_LEN} bytes.", RNS.LOG_ERROR) self.validcfg = False else: self.id_interval = None self.id_callsign = None if (not self.validcfg): - raise ValueError("The configuration for "+str(self)+" contains errors, interface is offline") + raise ValueError(f"The configuration for {self} contains errors, interface is offline") def start(self): try: @@ -257,11 +257,11 @@ class RNodeMultiInterface(Interface): if self.serial.is_open: self.configure_device() else: - raise IOError("Could not open serial port") + raise OSError("Could not open serial port") except Exception as e: - RNS.log("Could not open serial port for interface "+str(self), RNS.LOG_ERROR) - RNS.log("The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Could not open serial port for interface {self}", RNS.LOG_ERROR) + RNS.log(f"The contained exception was: {e}", RNS.LOG_ERROR) RNS.log("Reticulum will attempt to bring up this interface periodically", RNS.LOG_ERROR) if not self.detached and not self.reconnecting: thread = threading.Thread(target=self.reconnect_port) @@ -269,7 +269,7 @@ class RNodeMultiInterface(Interface): thread.start() def open_port(self): - RNS.log("Opening serial port "+self.port+"...") + RNS.log(f"Opening serial port {self.port}...") self.serial = self.pyserial.Serial( port = self.port, baudrate = self.speed, @@ -296,13 +296,13 @@ class RNodeMultiInterface(Interface): sleep(0.2) if not self.detected: - RNS.log("Could not detect device for "+str(self), RNS.LOG_ERROR) + RNS.log(f"Could not detect device for {self}", RNS.LOG_ERROR) self.serial.close() else: if self.platform == KISS.PLATFORM_ESP32 or self.platform == KISS.PLATFORM_NRF52: self.display = True - RNS.log("Serial port "+self.port+" is now open") + RNS.log(f"Serial port {self.port} is now open") RNS.log("Creating subinterfaces...", RNS.LOG_VERBOSE) for subint in self.subint_config: subint_vport = int(subint[1]) @@ -333,38 +333,38 @@ class RNodeMultiInterface(Interface): interface.HW_MTU = self.HW_MTU interface.detected = True RNS.Transport.interfaces.append(interface) - RNS.log("Spawned new RNode subinterface: "+str(interface), RNS.LOG_VERBOSE) + RNS.log(f"Spawned new RNode subinterface: {interface}", RNS.LOG_VERBOSE) self.clients += 1 else: - raise ValueError("Virtual port \""+subint[1]+"\" for subinterface "+subint[0]+" does not exist on "+self.name) + raise ValueError(f"Virtual port \"{subint[1]}\" for subinterface {subint[0]} does not exist on {self.name}") self.online = True def detect(self): kiss_command = bytes([KISS.FEND, KISS.CMD_DETECT, KISS.DETECT_REQ, KISS.FEND, KISS.CMD_FW_VERSION, 0x00, KISS.FEND, KISS.CMD_PLATFORM, 0x00, KISS.FEND, KISS.CMD_MCU, 0x00, KISS.FEND, KISS.CMD_INTERFACES, 0x00, KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while detecting hardware for "+str(self)) + raise OSError(f"An IO error occurred while detecting hardware for {self}") def leave(self): kiss_command = bytes([KISS.FEND, KISS.CMD_LEAVE, 0xFF, KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while sending host left command to device") + raise OSError("An IO error occurred while sending host left command to device") def enable_external_framebuffer(self): if self.display != None: kiss_command = bytes([KISS.FEND, KISS.CMD_FB_EXT, 0x01, KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while enabling external framebuffer on device") + raise OSError("An IO error occurred while enabling external framebuffer on device") def disable_external_framebuffer(self): if self.display != None: kiss_command = bytes([KISS.FEND, KISS.CMD_FB_EXT, 0x00, KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while disabling external framebuffer on device") + raise OSError("An IO error occurred while disabling external framebuffer on device") FB_PIXEL_WIDTH = 64 FB_BITS_PER_PIXEL = 1 @@ -388,13 +388,13 @@ class RNodeMultiInterface(Interface): written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while writing framebuffer data device") + raise OSError("An IO error occurred while writing framebuffer data device") def hard_reset(self): kiss_command = bytes([KISS.FEND, KISS.CMD_RESET, 0xf8, KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while restarting device") + raise OSError("An IO error occurred while restarting device") sleep(2.25); def setFrequency(self, frequency, interface): @@ -407,7 +407,7 @@ class RNodeMultiInterface(Interface): kiss_command = bytes([KISS.FEND])+bytes([interface.sel_cmd])+bytes([KISS.FEND])+bytes([KISS.FEND])+bytes([KISS.CMD_FREQUENCY])+data+bytes([KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while configuring frequency for "+str(self)) + raise OSError(f"An IO error occurred while configuring frequency for {self}") self.selected_index = interface.index def setBandwidth(self, bandwidth, interface): @@ -420,7 +420,7 @@ class RNodeMultiInterface(Interface): kiss_command = bytes([KISS.FEND])+bytes([interface.sel_cmd])+bytes([KISS.FEND])+bytes([KISS.FEND])+bytes([KISS.CMD_BANDWIDTH])+data+bytes([KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while configuring bandwidth for "+str(self)) + raise OSError(f"An IO error occurred while configuring bandwidth for {self}") self.selected_index = interface.index def setTXPower(self, txpower, interface): @@ -428,7 +428,7 @@ class RNodeMultiInterface(Interface): kiss_command = bytes([KISS.FEND])+bytes([interface.sel_cmd])+bytes([KISS.FEND])+bytes([KISS.FEND])+bytes([KISS.CMD_TXPOWER])+txp+bytes([KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while configuring TX power for "+str(self)) + raise OSError(f"An IO error occurred while configuring TX power for {self}") self.selected_index = interface.index def setSpreadingFactor(self, sf, interface): @@ -436,7 +436,7 @@ class RNodeMultiInterface(Interface): kiss_command = bytes([KISS.FEND])+bytes([interface.sel_cmd])+bytes([KISS.FEND])+bytes([KISS.FEND])+bytes([KISS.CMD_SF])+sf+bytes([KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while configuring spreading factor for "+str(self)) + raise OSError(f"An IO error occurred while configuring spreading factor for {self}") self.selected_index = interface.index def setCodingRate(self, cr, interface): @@ -444,7 +444,7 @@ class RNodeMultiInterface(Interface): kiss_command = bytes([KISS.FEND])+bytes([interface.sel_cmd])+bytes([KISS.FEND])+bytes([KISS.FEND])+bytes([KISS.CMD_CR])+cr+bytes([KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while configuring coding rate for "+str(self)) + raise OSError(f"An IO error occurred while configuring coding rate for {self}") self.selected_index = interface.index def setSTALock(self, st_alock, interface): @@ -457,7 +457,7 @@ class RNodeMultiInterface(Interface): kiss_command = bytes([KISS.FEND])+bytes([interface.sel_cmd])+bytes([KISS.FEND])+bytes([KISS.FEND])+bytes([KISS.CMD_ST_ALOCK])+data+bytes([KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while configuring short-term airtime limit for "+str(self)) + raise OSError(f"An IO error occurred while configuring short-term airtime limit for {self}") self.selected_index = interface.index def setLTALock(self, lt_alock, interface): @@ -470,7 +470,7 @@ class RNodeMultiInterface(Interface): kiss_command = bytes([KISS.FEND])+bytes([interface.sel_cmd])+bytes([KISS.FEND])+bytes([KISS.FEND])+bytes([KISS.CMD_LT_ALOCK])+data+bytes([KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while configuring long-term airtime limit for "+str(self)) + raise OSError(f"An IO error occurred while configuring long-term airtime limit for {self}") self.selected_index = interface.index def setRadioState(self, state, interface): @@ -478,7 +478,7 @@ class RNodeMultiInterface(Interface): kiss_command = bytes([KISS.FEND])+bytes([interface.sel_cmd])+bytes([KISS.FEND])+bytes([KISS.FEND])+bytes([KISS.CMD_RADIO_STATE])+bytes([state])+bytes([KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while configuring radio state for "+str(self)) + raise OSError(f"An IO error occurred while configuring radio state for {self}") self.selected_index = interface.index def validate_firmware(self): @@ -489,8 +489,8 @@ class RNodeMultiInterface(Interface): if self.firmware_ok: return - RNS.log("The firmware version of the connected RNode is "+str(self.maj_version)+"."+str(self.min_version), RNS.LOG_ERROR) - RNS.log("This version of Reticulum requires at least version "+str(RNodeMultiInterface.REQUIRED_FW_VER_MAJ)+"."+str(RNodeMultiInterface.REQUIRED_FW_VER_MIN), RNS.LOG_ERROR) + RNS.log(f"The firmware version of the connected RNode is {self.maj_version}.{self.min_version}", RNS.LOG_ERROR) + RNS.log(f"This version of Reticulum requires at least version {RNodeMultiInterface.REQUIRED_FW_VER_MAJ}.{RNodeMultiInterface.REQUIRED_FW_VER_MIN}", RNS.LOG_ERROR) RNS.log("Please update your RNode firmware with rnodeconf from https://github.com/markqvist/Reticulum/RNS/Utilities/rnodeconf.py") RNS.panic() @@ -506,7 +506,7 @@ class RNodeMultiInterface(Interface): self.txb += len(data) if written != len(frame): - raise IOError("Serial interface only wrote "+str(written)+" bytes of "+str(len(data))) + raise OSError(f"Serial interface only wrote {written} bytes of {len(data)}") def received_announce(self, from_spawned=False): if from_spawned: self.ia_freq_deque.append(time.time()) @@ -589,7 +589,7 @@ class RNodeMultiInterface(Interface): command_buffer = command_buffer+bytes([byte]) if (len(command_buffer) == 4): self.subinterfaces[self.selected_index].r_frequency = command_buffer[0] << 24 | command_buffer[1] << 16 | command_buffer[2] << 8 | command_buffer[3] - RNS.log(str(self.subinterfaces[self.selected_index])+" Radio reporting frequency is "+str(self.subinterfaces[self.selected_index].r_frequency/1000000.0)+" MHz", RNS.LOG_DEBUG) + RNS.log(f"{self.subinterfaces[self.selected_index]} Radio reporting frequency is {self.subinterfaces[self.selected_index].r_frequency / 1000000.0} MHz", RNS.LOG_DEBUG) self.subinterfaces[self.selected_index].updateBitrate() elif (command == KISS.CMD_BANDWIDTH): @@ -605,20 +605,20 @@ class RNodeMultiInterface(Interface): command_buffer = command_buffer+bytes([byte]) if (len(command_buffer) == 4): self.subinterfaces[self.selected_index].r_bandwidth = command_buffer[0] << 24 | command_buffer[1] << 16 | command_buffer[2] << 8 | command_buffer[3] - RNS.log(str(self.subinterfaces[self.selected_index])+" Radio reporting bandwidth is "+str(self.subinterfaces[self.selected_index].r_bandwidth/1000.0)+" KHz", RNS.LOG_DEBUG) + RNS.log(f"{self.subinterfaces[self.selected_index]} Radio reporting bandwidth is {self.subinterfaces[self.selected_index].r_bandwidth / 1000.0} KHz", RNS.LOG_DEBUG) self.subinterfaces[self.selected_index].updateBitrate() elif (command == KISS.CMD_TXPOWER): txp = byte - 256 if byte > 127 else byte self.subinterfaces[self.selected_index].r_txpower = txp - RNS.log(str(self.subinterfaces[self.selected_index])+" Radio reporting TX power is "+str(self.subinterfaces[self.selected_index].r_txpower)+" dBm", RNS.LOG_DEBUG) + RNS.log(f"{self.subinterfaces[self.selected_index]} Radio reporting TX power is {self.subinterfaces[self.selected_index].r_txpower} dBm", RNS.LOG_DEBUG) elif (command == KISS.CMD_SF): self.subinterfaces[self.selected_index].r_sf = byte - RNS.log(str(self.subinterfaces[self.selected_index])+" Radio reporting spreading factor is "+str(self.subinterfaces[self.selected_index].r_sf), RNS.LOG_DEBUG) + RNS.log(f"{self.subinterfaces[self.selected_index]} Radio reporting spreading factor is {self.subinterfaces[self.selected_index].r_sf}", RNS.LOG_DEBUG) self.subinterfaces[self.selected_index].updateBitrate() elif (command == KISS.CMD_CR): self.subinterfaces[self.selected_index].r_cr = byte - RNS.log(str(self.subinterfaces[self.selected_index])+" Radio reporting coding rate is "+str(self.subinterfaces[self.selected_index].r_cr), RNS.LOG_DEBUG) + RNS.log(f"{self.subinterfaces[self.selected_index]} Radio reporting coding rate is {self.subinterfaces[self.selected_index].r_cr}", RNS.LOG_DEBUG) self.subinterfaces[self.selected_index].updateBitrate() elif (command == KISS.CMD_RADIO_STATE): self.subinterfaces[self.selected_index].r_state = byte @@ -626,7 +626,7 @@ class RNodeMultiInterface(Interface): pass #RNS.log(str(self)+" Radio reporting state is online", RNS.LOG_DEBUG) else: - RNS.log(str(self.subinterfaces[self.selected_index])+" Radio reporting state is offline", RNS.LOG_DEBUG) + RNS.log(f"{self.subinterfaces[self.selected_index]} Radio reporting state is offline", RNS.LOG_DEBUG) elif (command == KISS.CMD_RADIO_LOCK): self.subinterfaces[self.selected_index].r_lock = byte @@ -705,7 +705,7 @@ class RNodeMultiInterface(Interface): if (len(command_buffer) == 2): at = command_buffer[0] << 8 | command_buffer[1] self.subinterfaces[self.selected_index].r_st_alock = at/100.0 - RNS.log(str(self.subinterfaces[self.selected_index])+" Radio reporting short-term airtime limit is "+str(self.subinterfaces[self.selected_index].r_st_alock)+"%", RNS.LOG_DEBUG) + RNS.log(f"{self.subinterfaces[self.selected_index]} Radio reporting short-term airtime limit is {self.subinterfaces[self.selected_index].r_st_alock}%", RNS.LOG_DEBUG) elif (command == KISS.CMD_LT_ALOCK): if (byte == KISS.FESC): escape = True @@ -720,7 +720,7 @@ class RNodeMultiInterface(Interface): if (len(command_buffer) == 2): at = command_buffer[0] << 8 | command_buffer[1] self.subinterfaces[self.selected_index].r_lt_alock = at/100.0 - RNS.log(str(self.subinterfaces[self.selected_index])+" Radio reporting long-term airtime limit is "+str(self.subinterfaces[self.selected_index].r_lt_alock)+"%", RNS.LOG_DEBUG) + RNS.log(f"{self.subinterfaces[self.selected_index]} Radio reporting long-term airtime limit is {self.subinterfaces[self.selected_index].r_lt_alock}%", RNS.LOG_DEBUG) elif (command == KISS.CMD_STAT_CHTM): if (byte == KISS.FESC): escape = True @@ -766,9 +766,9 @@ class RNodeMultiInterface(Interface): self.subinterfaces[self.selected_index].r_preamble_symbols = prs self.subinterfaces[self.selected_index].r_premable_time_ms = prt self.subinterfaces[self.selected_index].r_csma_slot_time_ms = cst - RNS.log(str(self.subinterfaces[self.selected_index])+" Radio reporting symbol time is "+str(round(self.subinterfaces[self.selected_index].r_symbol_time_ms,2))+"ms (at "+str(self.subinterfaces[self.selected_index].r_symbol_rate)+" baud)", RNS.LOG_DEBUG) - RNS.log(str(self.subinterfaces[self.selected_index])+" Radio reporting preamble is "+str(self.subinterfaces[self.selected_index].r_preamble_symbols)+" symbols ("+str(self.subinterfaces[self.selected_index].r_premable_time_ms)+"ms)", RNS.LOG_DEBUG) - RNS.log(str(self.subinterfaces[self.selected_index])+" Radio reporting CSMA slot time is "+str(self.subinterfaces[self.selected_index].r_csma_slot_time_ms)+"ms", RNS.LOG_DEBUG) + RNS.log(f"{self.subinterfaces[self.selected_index]} Radio reporting symbol time is {round(self.subinterfaces[self.selected_index].r_symbol_time_ms, 2)}ms (at {self.subinterfaces[self.selected_index].r_symbol_rate} baud)", RNS.LOG_DEBUG) + RNS.log(f"{self.subinterfaces[self.selected_index]} Radio reporting preamble is {self.subinterfaces[self.selected_index].r_preamble_symbols} symbols ({self.subinterfaces[self.selected_index].r_premable_time_ms}ms)", RNS.LOG_DEBUG) + RNS.log(f"{self.subinterfaces[self.selected_index]} Radio reporting CSMA slot time is {self.subinterfaces[self.selected_index].r_csma_slot_time_ms}ms", RNS.LOG_DEBUG) elif (command == KISS.CMD_RANDOM): self.r_random = byte elif (command == KISS.CMD_PLATFORM): @@ -777,20 +777,20 @@ class RNodeMultiInterface(Interface): self.mcu = byte elif (command == KISS.CMD_ERROR): if (byte == KISS.ERROR_INITRADIO): - RNS.log(str(self)+" hardware initialisation error (code "+RNS.hexrep(byte)+")", RNS.LOG_ERROR) - raise IOError("Radio initialisation failure") + RNS.log(f"{self} hardware initialisation error (code {RNS.hexrep(byte)})", RNS.LOG_ERROR) + raise OSError("Radio initialisation failure") elif (byte == KISS.ERROR_TXFAILED): - RNS.log(str(self)+" hardware TX error (code "+RNS.hexrep(byte)+")", RNS.LOG_ERROR) - raise IOError("Hardware transmit failure") + RNS.log(f"{self} hardware TX error (code {RNS.hexrep(byte)})", RNS.LOG_ERROR) + raise OSError("Hardware transmit failure") else: - RNS.log(str(self)+" hardware error (code "+RNS.hexrep(byte)+")", RNS.LOG_ERROR) - raise IOError("Unknown hardware failure") + RNS.log(f"{self} hardware error (code {RNS.hexrep(byte)})", RNS.LOG_ERROR) + raise OSError("Unknown hardware failure") elif (command == KISS.CMD_RESET): if (byte == 0xF8): if self.platform == KISS.PLATFORM_ESP32: if self.online: RNS.log("Detected reset while device was online, reinitialising device...", RNS.LOG_ERROR) - raise IOError("ESP32 reset") + raise OSError("ESP32 reset") elif (command == KISS.CMD_READY): self.process_queue() elif (command == KISS.CMD_DETECT): @@ -808,7 +808,7 @@ class RNodeMultiInterface(Interface): else: time_since_last = int(time.time()*1000) - last_read_ms if len(data_buffer) > 0 and time_since_last > self.timeout: - RNS.log(str(self)+" serial read timeout in command "+str(command), RNS.LOG_WARNING) + RNS.log(f"{self} serial read timeout in command {command}", RNS.LOG_WARNING) data_buffer = b"" in_frame = False command = KISS.CMD_UNKNOWN @@ -824,14 +824,14 @@ class RNodeMultiInterface(Interface): self.subinterfaces[interface.index].processOutgoing(self.id_callsign) if interface_available: - RNS.log("Interface "+str(self)+" is transmitting beacon data on all subinterfaces: "+str(self.id_callsign.decode("utf-8")), RNS.LOG_DEBUG) + RNS.log(f"Interface {self} is transmitting beacon data on all subinterfaces: {self.id_callsign.decode('utf-8')}", RNS.LOG_DEBUG) sleep(0.08) except Exception as e: self.online = False - RNS.log("A serial port error occurred, the contained exception was: "+str(e), RNS.LOG_ERROR) - RNS.log("The interface "+str(self)+" experienced an unrecoverable error and is now offline.", RNS.LOG_ERROR) + RNS.log(f"A serial port error occurred, the contained exception was: {e}", RNS.LOG_ERROR) + RNS.log(f"The interface {self} experienced an unrecoverable error and is now offline.", RNS.LOG_ERROR) if RNS.Reticulum.panic_on_interface_error: RNS.panic() @@ -854,16 +854,16 @@ class RNodeMultiInterface(Interface): while not self.online and not self.detached: try: time.sleep(5) - RNS.log("Attempting to reconnect serial port "+str(self.port)+" for "+str(self)+"...", RNS.LOG_VERBOSE) + RNS.log(f"Attempting to reconnect serial port {self.port} for {self}...", RNS.LOG_VERBOSE) self.open_port() if self.serial.is_open: self.configure_device() except Exception as e: - RNS.log("Error while reconnecting port, the contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Error while reconnecting port, the contained exception was: {e}", RNS.LOG_ERROR) self.reconnecting = False if self.online: - RNS.log("Reconnected serial port for "+str(self)) + RNS.log(f"Reconnected serial port for {self}") def detach(self): self.detached = True @@ -890,7 +890,7 @@ class RNodeMultiInterface(Interface): interface.process_queue() def __str__(self): - return "RNodeMultiInterface["+str(self.name)+"]" + return f"RNodeMultiInterface[{self.name}]" class RNodeSubInterface(Interface): LOW_FREQ_MIN = 137000000 @@ -1019,42 +1019,42 @@ class RNodeSubInterface(Interface): self.validcfg = True if (self.interface_type == "SX126X" or self.interface_type == "SX127X"): if (self.frequency < RNodeSubInterface.LOW_FREQ_MIN or self.frequency > RNodeSubInterface.LOW_FREQ_MAX): - RNS.log("Invalid frequency configured for "+str(self), RNS.LOG_ERROR) + RNS.log(f"Invalid frequency configured for {self}", RNS.LOG_ERROR) self.validcfg = False elif (self.interface_type == "SX128X"): if (self.frequency < RNodeSubInterface.HIGH_FREQ_MIN or self.frequency > RNodeSubInterface.HIGH_FREQ_MAX): - RNS.log("Invalid frequency configured for "+str(self), RNS.LOG_ERROR) + RNS.log(f"Invalid frequency configured for {self}", RNS.LOG_ERROR) self.validcfg = False else: - RNS.log("Invalid interface type configured for "+str(self), RNS.LOG_ERROR) + RNS.log(f"Invalid interface type configured for {self}", RNS.LOG_ERROR) self.validcfg = False if (self.txpower < -9 or self.txpower > 27): - RNS.log("Invalid TX power configured for "+str(self), RNS.LOG_ERROR) + RNS.log(f"Invalid TX power configured for {self}", RNS.LOG_ERROR) self.validcfg = False if (self.bandwidth < 7800 or self.bandwidth > 1625000): - RNS.log("Invalid bandwidth configured for "+str(self), RNS.LOG_ERROR) + RNS.log(f"Invalid bandwidth configured for {self}", RNS.LOG_ERROR) self.validcfg = False if (self.sf < 5 or self.sf > 12): - RNS.log("Invalid spreading factor configured for "+str(self), RNS.LOG_ERROR) + RNS.log(f"Invalid spreading factor configured for {self}", RNS.LOG_ERROR) self.validcfg = False if (self.cr < 5 or self.cr > 8): - RNS.log("Invalid coding rate configured for "+str(self), RNS.LOG_ERROR) + RNS.log(f"Invalid coding rate configured for {self}", RNS.LOG_ERROR) self.validcfg = False if (self.st_alock and (self.st_alock < 0.0 or self.st_alock > 100.0)): - RNS.log("Invalid short-term airtime limit configured for "+str(self), RNS.LOG_ERROR) + RNS.log(f"Invalid short-term airtime limit configured for {self}", RNS.LOG_ERROR) self.validcfg = False if (self.lt_alock and (self.lt_alock < 0.0 or self.lt_alock > 100.0)): - RNS.log("Invalid long-term airtime limit configured for "+str(self), RNS.LOG_ERROR) + RNS.log(f"Invalid long-term airtime limit configured for {self}", RNS.LOG_ERROR) self.validcfg = False if (not self.validcfg): - raise ValueError("The configuration for "+str(self)+" contains errors, interface is offline") + raise ValueError(f"The configuration for {self} contains errors, interface is offline") self.configure_device() @@ -1068,15 +1068,15 @@ class RNodeSubInterface(Interface): self.r_lock = None sleep(2.0) - RNS.log("Configuring RNode subinterface "+str(self)+"...", RNS.LOG_VERBOSE) + RNS.log(f"Configuring RNode subinterface {self}...", RNS.LOG_VERBOSE) self.initRadio() if (self.validateRadioState()): self.interface_ready = True - RNS.log(str(self)+" is configured and powered up") + RNS.log(f"{self} is configured and powered up") sleep(0.3) self.online = True else: - RNS.log("After configuring "+str(self)+", the reported radio parameters did not match your configuration.", RNS.LOG_ERROR) + RNS.log(f"After configuring {self}, the reported radio parameters did not match your configuration.", RNS.LOG_ERROR) RNS.log("Make sure that your hardware actually supports the parameters specified in the configuration", RNS.LOG_ERROR) RNS.log("Aborting RNode startup", RNS.LOG_ERROR) @@ -1093,7 +1093,7 @@ class RNodeSubInterface(Interface): self.state = KISS.RADIO_STATE_ON def validateRadioState(self): - RNS.log("Waiting for radio configuration validation for "+str(self)+"...", RNS.LOG_VERBOSE) + RNS.log(f"Waiting for radio configuration validation for {self}...", RNS.LOG_VERBOSE) sleep(0.25); self.validcfg = True @@ -1123,7 +1123,7 @@ class RNodeSubInterface(Interface): try: self.bitrate = self.r_sf * ( (4.0/self.r_cr) / (math.pow(2,self.r_sf)/(self.r_bandwidth/1000)) ) * 1000 self.bitrate_kbps = round(self.bitrate/1000.0, 2) - RNS.log(str(self)+" On-air bitrate is now "+str(self.bitrate_kbps)+ " kbps", RNS.LOG_VERBOSE) + RNS.log(f"{self} On-air bitrate is now {self.bitrate_kbps} kbps", RNS.LOG_VERBOSE) except: self.bitrate = 0 @@ -1162,4 +1162,4 @@ class RNodeSubInterface(Interface): self.interface_ready = True def __str__(self): - return self.parent_interface.name+"["+self.name+"]" + return f"{self.parent_interface.name}[{self.name}]" diff --git a/RNS/Interfaces/SerialInterface.py b/RNS/Interfaces/SerialInterface.py index 89f73c6..e69b347 100755 --- a/RNS/Interfaces/SerialInterface.py +++ b/RNS/Interfaces/SerialInterface.py @@ -86,17 +86,17 @@ class SerialInterface(Interface): try: self.open_port() except Exception as e: - RNS.log("Could not open serial port for interface "+str(self), RNS.LOG_ERROR) + RNS.log(f"Could not open serial port for interface {self}", RNS.LOG_ERROR) raise e if self.serial.is_open: self.configure_device() else: - raise IOError("Could not open serial port") + raise OSError("Could not open serial port") def open_port(self): - RNS.log("Opening serial port "+self.port+"...", RNS.LOG_VERBOSE) + RNS.log(f"Opening serial port {self.port}...", RNS.LOG_VERBOSE) self.serial = self.pyserial.Serial( port = self.port, baudrate = self.speed, @@ -118,7 +118,7 @@ class SerialInterface(Interface): thread.daemon = True thread.start() self.online = True - RNS.log("Serial port "+self.port+" is now open", RNS.LOG_VERBOSE) + RNS.log(f"Serial port {self.port} is now open", RNS.LOG_VERBOSE) def processIncoming(self, data): @@ -132,7 +132,7 @@ class SerialInterface(Interface): written = self.serial.write(data) self.txb += len(data) if written != len(data): - raise IOError("Serial interface only wrote "+str(written)+" bytes of "+str(len(data))) + raise OSError(f"Serial interface only wrote {written} bytes of {len(data)}") def readLoop(self): @@ -175,8 +175,8 @@ class SerialInterface(Interface): except Exception as e: self.online = False - RNS.log("A serial port error occurred, the contained exception was: "+str(e), RNS.LOG_ERROR) - RNS.log("The interface "+str(self)+" experienced an unrecoverable error and is now offline.", RNS.LOG_ERROR) + RNS.log(f"A serial port error occurred, the contained exception was: {e}", RNS.LOG_ERROR) + RNS.log(f"The interface {self} experienced an unrecoverable error and is now offline.", RNS.LOG_ERROR) if RNS.Reticulum.panic_on_interface_error: RNS.panic() @@ -191,17 +191,17 @@ class SerialInterface(Interface): while not self.online: try: time.sleep(5) - RNS.log("Attempting to reconnect serial port "+str(self.port)+" for "+str(self)+"...", RNS.LOG_VERBOSE) + RNS.log(f"Attempting to reconnect serial port {self.port} for {self}...", RNS.LOG_VERBOSE) self.open_port() if self.serial.is_open: self.configure_device() except Exception as e: - RNS.log("Error while reconnecting port, the contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Error while reconnecting port, the contained exception was: {e}", RNS.LOG_ERROR) - RNS.log("Reconnected serial port for "+str(self)) + RNS.log(f"Reconnected serial port for {self}") def should_ingress_limit(self): return False def __str__(self): - return "SerialInterface["+self.name+"]" + return f"SerialInterface[{self.name}]" diff --git a/RNS/Interfaces/TCPInterface.py b/RNS/Interfaces/TCPInterface.py index 54eadb0..fbdb3f3 100644 --- a/RNS/Interfaces/TCPInterface.py +++ b/RNS/Interfaces/TCPInterface.py @@ -180,25 +180,25 @@ class TCPClientInterface(Interface): if self.socket != None: if hasattr(self.socket, "close"): if callable(self.socket.close): - RNS.log("Detaching "+str(self), RNS.LOG_DEBUG) + RNS.log(f"Detaching {self}", RNS.LOG_DEBUG) self.detached = True try: self.socket.shutdown(socket.SHUT_RDWR) except Exception as e: - RNS.log("Error while shutting down socket for "+str(self)+": "+str(e)) + RNS.log(f"Error while shutting down socket for {self}: {e}") try: self.socket.close() except Exception as e: - RNS.log("Error while closing socket for "+str(self)+": "+str(e)) + RNS.log(f"Error while closing socket for {self}: {e}") self.socket = None def connect(self, initial=False): try: if initial: - RNS.log("Establishing TCP connection for "+str(self)+"...", RNS.LOG_DEBUG) + RNS.log(f"Establishing TCP connection for {self}...", RNS.LOG_DEBUG) self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.socket.settimeout(TCPClientInterface.INITIAL_CONNECT_TIMEOUT) @@ -208,12 +208,12 @@ class TCPClientInterface(Interface): self.online = True if initial: - RNS.log("TCP connection for "+str(self)+" established", RNS.LOG_DEBUG) + RNS.log(f"TCP connection for {self} established", RNS.LOG_DEBUG) except Exception as e: if initial: - RNS.log("Initial connection for "+str(self)+" could not be established: "+str(e), RNS.LOG_ERROR) - RNS.log("Leaving unconnected and retrying connection in "+str(TCPClientInterface.RECONNECT_WAIT)+" seconds.", RNS.LOG_ERROR) + RNS.log(f"Initial connection for {self} could not be established: {e}", RNS.LOG_ERROR) + RNS.log(f"Leaving unconnected and retrying connection in {TCPClientInterface.RECONNECT_WAIT} seconds.", RNS.LOG_ERROR) return False else: @@ -241,7 +241,7 @@ class TCPClientInterface(Interface): attempts += 1 if self.max_reconnect_tries != None and attempts > self.max_reconnect_tries: - RNS.log("Max reconnection attempts reached for "+str(self), RNS.LOG_ERROR) + RNS.log(f"Max reconnection attempts reached for {self}", RNS.LOG_ERROR) self.teardown() break @@ -249,10 +249,10 @@ class TCPClientInterface(Interface): self.connect() except Exception as e: - RNS.log("Connection attempt for "+str(self)+" failed: "+str(e), RNS.LOG_DEBUG) + RNS.log(f"Connection attempt for {self} failed: {e}", RNS.LOG_DEBUG) if not self.never_connected: - RNS.log("Reconnected socket for "+str(self)+".", RNS.LOG_INFO) + RNS.log(f"Reconnected socket for {self}.", RNS.LOG_INFO) self.reconnecting = False thread = threading.Thread(target=self.read_loop) @@ -263,7 +263,7 @@ class TCPClientInterface(Interface): else: RNS.log("Attempt to reconnect on a non-initiator TCP interface. This should not happen.", RNS.LOG_ERROR) - raise IOError("Attempt to reconnect on a non-initiator TCP interface") + raise OSError("Attempt to reconnect on a non-initiator TCP interface") def processIncoming(self, data): self.rxb += len(data) @@ -292,8 +292,8 @@ class TCPClientInterface(Interface): self.parent_interface.txb += len(data) except Exception as e: - RNS.log("Exception occurred while transmitting via "+str(self)+", tearing down interface", RNS.LOG_ERROR) - RNS.log("The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Exception occurred while transmitting via {self}, tearing down interface", RNS.LOG_ERROR) + RNS.log(f"The contained exception was: {e}", RNS.LOG_ERROR) self.teardown() @@ -361,10 +361,10 @@ class TCPClientInterface(Interface): else: self.online = False if self.initiator and not self.detached: - RNS.log("The socket for "+str(self)+" was closed, attempting to reconnect...", RNS.LOG_WARNING) + RNS.log(f"The socket for {self} was closed, attempting to reconnect...", RNS.LOG_WARNING) self.reconnect() else: - RNS.log("The socket for remote client "+str(self)+" was closed.", RNS.LOG_VERBOSE) + RNS.log(f"The socket for remote client {self} was closed.", RNS.LOG_VERBOSE) self.teardown() break @@ -372,7 +372,7 @@ class TCPClientInterface(Interface): except Exception as e: self.online = False - RNS.log("An interface error occurred for "+str(self)+", the contained exception was: "+str(e), RNS.LOG_WARNING) + RNS.log(f"An interface error occurred for {self}, the contained exception was: {e}", RNS.LOG_WARNING) if self.initiator: RNS.log("Attempting to reconnect...", RNS.LOG_WARNING) @@ -382,12 +382,12 @@ class TCPClientInterface(Interface): def teardown(self): if self.initiator and not self.detached: - RNS.log("The interface "+str(self)+" experienced an unrecoverable error and is being torn down. Restart Reticulum to attempt to open this interface again.", RNS.LOG_ERROR) + RNS.log(f"The interface {self} experienced an unrecoverable error and is being torn down. Restart Reticulum to attempt to open this interface again.", RNS.LOG_ERROR) if RNS.Reticulum.panic_on_interface_error: RNS.panic() else: - RNS.log("The interface "+str(self)+" is being torn down.", RNS.LOG_VERBOSE) + RNS.log(f"The interface {self} is being torn down.", RNS.LOG_VERBOSE) self.online = False self.OUT = False @@ -402,7 +402,7 @@ class TCPClientInterface(Interface): def __str__(self): - return "TCPInterface["+str(self.name)+"/"+str(self.target_ip)+":"+str(self.target_port)+"]" + return f"TCPInterface[{self.name}/{self.target_ip}:{self.target_port}]" class TCPServerInterface(Interface): @@ -466,7 +466,7 @@ class TCPServerInterface(Interface): def incoming_connection(self, handler): RNS.log("Accepting incoming TCP connection", RNS.LOG_VERBOSE) - interface_name = "Client on "+self.name + interface_name = f"Client on {self.name}" spawned_interface = TCPClientInterface(self.owner, interface_name, target_ip=None, target_port=None, connected_socket=handler.request, i2p_tunneled=self.i2p_tunneled) spawned_interface.OUT = self.OUT spawned_interface.IN = self.IN @@ -501,7 +501,7 @@ class TCPServerInterface(Interface): spawned_interface.mode = self.mode spawned_interface.HW_MTU = self.HW_MTU spawned_interface.online = True - RNS.log("Spawned new TCPClient Interface: "+str(spawned_interface), RNS.LOG_VERBOSE) + RNS.log(f"Spawned new TCPClient Interface: {spawned_interface}", RNS.LOG_VERBOSE) RNS.Transport.interfaces.append(spawned_interface) self.clients += 1 spawned_interface.read_loop() @@ -521,17 +521,17 @@ class TCPServerInterface(Interface): if hasattr(self.server, "shutdown"): if callable(self.server.shutdown): try: - RNS.log("Detaching "+str(self), RNS.LOG_DEBUG) + RNS.log(f"Detaching {self}", RNS.LOG_DEBUG) self.server.shutdown() self.detached = True self.server = None except Exception as e: - RNS.log("Error while shutting down server for "+str(self)+": "+str(e)) + RNS.log(f"Error while shutting down server for {self}: {e}") def __str__(self): - return "TCPServerInterface["+self.name+"/"+self.bind_ip+":"+str(self.bind_port)+"]" + return f"TCPServerInterface[{self.name}/{self.bind_ip}:{self.bind_port}]" class TCPInterfaceHandler(socketserver.BaseRequestHandler): diff --git a/RNS/Interfaces/UDPInterface.py b/RNS/Interfaces/UDPInterface.py index f230af9..d407a78 100644 --- a/RNS/Interfaces/UDPInterface.py +++ b/RNS/Interfaces/UDPInterface.py @@ -101,11 +101,11 @@ class UDPInterface(Interface): self.txb += len(data) except Exception as e: - RNS.log("Could not transmit on "+str(self)+". The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Could not transmit on {self}. The contained exception was: {e}", RNS.LOG_ERROR) def __str__(self): - return "UDPInterface["+self.name+"/"+self.bind_ip+":"+str(self.bind_port)+"]" + return f"UDPInterface[{self.name}/{self.bind_ip}:{self.bind_port}]" class UDPInterfaceHandler(socketserver.BaseRequestHandler): def __init__(self, callback, *args, **keys): diff --git a/RNS/Interfaces/__init__.py b/RNS/Interfaces/__init__.py index 84fff6a..33fc3d8 100755 --- a/RNS/Interfaces/__init__.py +++ b/RNS/Interfaces/__init__.py @@ -24,5 +24,5 @@ import os import glob import RNS.Interfaces.Android -modules = glob.glob(os.path.dirname(__file__)+"/*.py") +modules = glob.glob(f"{os.path.dirname(__file__)}/*.py") __all__ = [ os.path.basename(f)[:-3] for f in modules if not f.endswith('__init__.py')] diff --git a/RNS/Link.py b/RNS/Link.py index 01641b1..a74a444 100644 --- a/RNS/Link.py +++ b/RNS/Link.py @@ -115,8 +115,8 @@ class Link: link.destination = packet.destination link.establishment_timeout = Link.ESTABLISHMENT_TIMEOUT_PER_HOP * max(1, packet.hops) + Link.KEEPALIVE link.establishment_cost += len(packet.raw) - RNS.log("Validating link request "+RNS.prettyhexrep(link.link_id), RNS.LOG_VERBOSE) - RNS.log(f"Establishment timeout is {RNS.prettytime(link.establishment_timeout)} for incoming link request "+RNS.prettyhexrep(link.link_id), RNS.LOG_EXTREME) + RNS.log(f"Validating link request {RNS.prettyhexrep(link.link_id)}", RNS.LOG_VERBOSE) + RNS.log(f"Establishment timeout is {RNS.prettytime(link.establishment_timeout)} for incoming link request {RNS.prettyhexrep(link.link_id)}", RNS.LOG_EXTREME) link.handshake() link.attached_interface = packet.receiving_interface link.prove() @@ -125,12 +125,12 @@ class Link: link.last_inbound = time.time() link.start_watchdog() - RNS.log("Incoming link request "+str(link)+" accepted on "+str(link.attached_interface), RNS.LOG_DEBUG) + RNS.log(f"Incoming link request {link} accepted on {link.attached_interface}", RNS.LOG_DEBUG) return link except Exception as e: RNS.log("Validating link request failed", RNS.LOG_VERBOSE) - RNS.log("exc: "+str(e)) + RNS.log(f"exc: {e}") return None else: @@ -219,8 +219,8 @@ class Link: self.start_watchdog() self.packet.send() self.had_outbound() - RNS.log("Link request "+RNS.prettyhexrep(self.link_id)+" sent to "+str(self.destination), RNS.LOG_DEBUG) - RNS.log(f"Establishment timeout is {RNS.prettytime(self.establishment_timeout)} for link request "+RNS.prettyhexrep(self.link_id), RNS.LOG_EXTREME) + RNS.log(f"Link request {RNS.prettyhexrep(self.link_id)} sent to {self.destination}", RNS.LOG_DEBUG) + RNS.log(f"Establishment timeout is {RNS.prettytime(self.establishment_timeout)} for link request {RNS.prettyhexrep(self.link_id)}", RNS.LOG_EXTREME) def load_peer(self, peer_pub_bytes, peer_sig_pub_bytes): @@ -249,7 +249,7 @@ class Link: context=self.get_context(), ) else: - RNS.log("Handshake attempt on "+str(self)+" with invalid state "+str(self.status), RNS.LOG_ERROR) + RNS.log(f"Handshake attempt on {self} with invalid state {self.status}", RNS.LOG_ERROR) def prove(self): @@ -291,7 +291,7 @@ class Link: if self.destination.identity.validate(signature, signed_data): if self.status != Link.HANDSHAKE: - raise IOError("Invalid link state for proof validation: "+str(self.status)) + raise OSError(f"Invalid link state for proof validation: {self.status}") self.rtt = time.time() - self.request_time self.attached_interface = packet.receiving_interface @@ -300,7 +300,7 @@ class Link: self.activated_at = time.time() self.last_proof = self.activated_at RNS.Transport.activate_link(self) - RNS.log("Link "+str(self)+" established with "+str(self.destination)+", RTT is "+str(round(self.rtt, 3))+"s", RNS.LOG_VERBOSE) + RNS.log(f"Link {self} established with {self.destination}, RTT is {round(self.rtt, 3)}s", RNS.LOG_VERBOSE) if self.rtt != None and self.establishment_cost != None and self.rtt > 0 and self.establishment_cost > 0: self.establishment_rate = self.establishment_cost/self.rtt @@ -315,12 +315,12 @@ class Link: thread.daemon = True thread.start() else: - RNS.log("Invalid link proof signature received by "+str(self)+". Ignoring.", RNS.LOG_DEBUG) + RNS.log(f"Invalid link proof signature received by {self}. Ignoring.", RNS.LOG_DEBUG) except Exception as e: self.status = Link.CLOSED - RNS.log("An error ocurred while validating link request proof on "+str(self)+".", RNS.LOG_ERROR) - RNS.log("The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"An error ocurred while validating link request proof on {self}.", RNS.LOG_ERROR) + RNS.log(f"The contained exception was: {e}", RNS.LOG_ERROR) def identify(self, identity): @@ -380,7 +380,7 @@ class Link: else: request_id = RNS.Identity.truncated_hash(packed_request) - RNS.log("Sending request "+RNS.prettyhexrep(request_id)+" as resource.", RNS.LOG_DEBUG) + RNS.log(f"Sending request {RNS.prettyhexrep(request_id)} as resource.", RNS.LOG_DEBUG) request_resource = RNS.Resource(packed_request, self, request_id = request_id, is_response = False, timeout = timeout) return RequestReceipt( @@ -411,10 +411,10 @@ class Link: if self.owner.callbacks.link_established != None: self.owner.callbacks.link_established(self) except Exception as e: - RNS.log("Error occurred in external link establishment callback. The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Error occurred in external link establishment callback. The contained exception was: {e}", RNS.LOG_ERROR) except Exception as e: - RNS.log("Error occurred while processing RTT packet, tearing down link. The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Error occurred while processing RTT packet, tearing down link. The contained exception was: {e}", RNS.LOG_ERROR) self.teardown() def track_phy_stats(self, track): @@ -563,7 +563,7 @@ class Link: try: self.callbacks.link_closed(self) except Exception as e: - RNS.log("Error while executing link closed callback from "+str(self)+". The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Error while executing link closed callback from {self}. The contained exception was: {e}", RNS.LOG_ERROR) def start_watchdog(self): @@ -634,7 +634,7 @@ class Link: if sleep_time == 0: RNS.log("Warning! Link watchdog sleep time of 0!", RNS.LOG_ERROR) if sleep_time == None or sleep_time < 0: - RNS.log("Timing error! Tearing down link "+str(self)+" now.", RNS.LOG_ERROR) + RNS.log(f"Timing error! Tearing down link {self} now.", RNS.LOG_ERROR) self.teardown() sleep_time = 0.1 @@ -683,7 +683,7 @@ class Link: allowed = True if allowed: - RNS.log("Handling request "+RNS.prettyhexrep(request_id)+" for: "+str(path), RNS.LOG_DEBUG) + RNS.log(f"Handling request {RNS.prettyhexrep(request_id)} for: {path}", RNS.LOG_DEBUG) if len(inspect.signature(response_generator).parameters) == 5: response = response_generator(path, request_data, request_id, self.__remote_identity, requested_at) elif len(inspect.signature(response_generator).parameters) == 6: @@ -700,7 +700,7 @@ class Link: response_resource = RNS.Resource(packed_response, self, request_id = request_id, is_response = True) else: identity_string = str(self.get_remote_identity()) if self.get_remote_identity() != None else "" - RNS.log("Request "+RNS.prettyhexrep(request_id)+" from "+identity_string+" not allowed for: "+str(path), RNS.LOG_DEBUG) + RNS.log(f"Request {RNS.prettyhexrep(request_id)} from {identity_string} not allowed for: {path}", RNS.LOG_DEBUG) def handle_response(self, request_id, response_data, response_size, response_transfer_size): if self.status == Link.ACTIVE: @@ -715,7 +715,7 @@ class Link: pending_request.response_transfer_size += response_transfer_size pending_request.response_received(response_data) except Exception as e: - RNS.log("Error occurred while handling response. The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Error occurred while handling response. The contained exception was: {e}", RNS.LOG_ERROR) break @@ -732,7 +732,7 @@ class Link: self.handle_request(request_id, request_data) else: - RNS.log("Incoming request resource failed with status: "+RNS.hexrep([resource.status]), RNS.LOG_DEBUG) + RNS.log(f"Incoming request resource failed with status: {RNS.hexrep([resource.status])}", RNS.LOG_DEBUG) def response_resource_concluded(self, resource): if resource.status == RNS.Resource.COMPLETE: @@ -743,7 +743,7 @@ class Link: self.handle_response(request_id, response_data, resource.total_size, resource.size) else: - RNS.log("Incoming response resource failed with status: "+RNS.hexrep([resource.status]), RNS.LOG_DEBUG) + RNS.log(f"Incoming response resource failed with status: {RNS.hexrep([resource.status])}", RNS.LOG_DEBUG) for pending_request in self.pending_requests: if pending_request.request_id == resource.request_id: pending_request.request_timed_out(None) @@ -794,7 +794,7 @@ class Link: packet.prove() should_query = True except Exception as e: - RNS.log("Error while executing proof request callback from "+str(self)+". The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Error while executing proof request callback from {self}. The contained exception was: {e}", RNS.LOG_ERROR) self.__update_phy_stats(packet, query_shared=should_query) @@ -814,7 +814,7 @@ class Link: try: self.callbacks.remote_identified(self, self.__remote_identity) except Exception as e: - RNS.log("Error while executing remote identified callback from "+str(self)+". The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Error while executing remote identified callback from {self}. The contained exception was: {e}", RNS.LOG_ERROR) self.__update_phy_stats(packet, query_shared=True) @@ -827,7 +827,7 @@ class Link: self.handle_request(request_id, unpacked_request) self.__update_phy_stats(packet, query_shared=True) except Exception as e: - RNS.log("Error occurred while handling request. The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Error occurred while handling request. The contained exception was: {e}", RNS.LOG_ERROR) elif packet.context == RNS.Packet.RESPONSE: try: @@ -840,7 +840,7 @@ class Link: self.handle_response(request_id, response_data, transfer_size, transfer_size) self.__update_phy_stats(packet, query_shared=True) except Exception as e: - RNS.log("Error occurred while handling response. The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Error occurred while handling response. The contained exception was: {e}", RNS.LOG_ERROR) elif packet.context == RNS.Packet.LRRTT: if not self.initiator: @@ -883,7 +883,7 @@ class Link: if self.callbacks.resource(resource_advertisement): RNS.Resource.accept(packet, self.callbacks.resource_concluded) except Exception as e: - RNS.log("Error while executing resource accept callback from "+str(self)+". The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Error while executing resource accept callback from {self}. The contained exception was: {e}", RNS.LOG_ERROR) elif self.resource_strategy == Link.ACCEPT_ALL: RNS.Resource.accept(packet, self.callbacks.resource_concluded) @@ -970,13 +970,13 @@ class Link: try: self.fernet = Fernet(self.derived_key) except Exception as e: - RNS.log("Could not instantiate Fernet while performin encryption on link "+str(self)+". The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Could not instantiate Fernet while performin encryption on link {self}. The contained exception was: {e}", RNS.LOG_ERROR) raise e return self.fernet.encrypt(plaintext) except Exception as e: - RNS.log("Encryption on link "+str(self)+" failed. The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Encryption on link {self} failed. The contained exception was: {e}", RNS.LOG_ERROR) raise e @@ -988,7 +988,7 @@ class Link: return self.fernet.decrypt(ciphertext) except Exception as e: - RNS.log("Decryption failed on link "+str(self)+". The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Decryption failed on link {self}. The contained exception was: {e}", RNS.LOG_ERROR) return None @@ -1169,7 +1169,7 @@ class RequestReceipt(): def request_resource_concluded(self, resource): if resource.status == RNS.Resource.COMPLETE: - RNS.log("Request "+RNS.prettyhexrep(self.request_id)+" successfully sent as resource.", RNS.LOG_DEBUG) + RNS.log(f"Request {RNS.prettyhexrep(self.request_id)} successfully sent as resource.", RNS.LOG_DEBUG) if self.started_at == None: self.started_at = time.time() self.status = RequestReceipt.DELIVERED @@ -1178,7 +1178,7 @@ class RequestReceipt(): response_timeout_thread.daemon = True response_timeout_thread.start() else: - RNS.log("Sending request "+RNS.prettyhexrep(self.request_id)+" as resource failed with status: "+RNS.hexrep([resource.status]), RNS.LOG_DEBUG) + RNS.log(f"Sending request {RNS.prettyhexrep(self.request_id)} as resource failed with status: {RNS.hexrep([resource.status])}", RNS.LOG_DEBUG) self.status = RequestReceipt.FAILED self.concluded_at = time.time() self.link.pending_requests.remove(self) @@ -1187,7 +1187,7 @@ class RequestReceipt(): try: self.callbacks.failed(self) except Exception as e: - RNS.log("Error while executing request failed callback from "+str(self)+". The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Error while executing request failed callback from {self}. The contained exception was: {e}", RNS.LOG_ERROR) def __response_timeout_job(self): @@ -1208,7 +1208,7 @@ class RequestReceipt(): try: self.callbacks.failed(self) except Exception as e: - RNS.log("Error while executing request timed out callback from "+str(self)+". The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Error while executing request timed out callback from {self}. The contained exception was: {e}", RNS.LOG_ERROR) def response_resource_progress(self, resource): @@ -1229,7 +1229,7 @@ class RequestReceipt(): try: self.callbacks.progress(self) except Exception as e: - RNS.log("Error while executing response progress callback from "+str(self)+". The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Error while executing response progress callback from {self}. The contained exception was: {e}", RNS.LOG_ERROR) else: resource.cancel() @@ -1252,13 +1252,13 @@ class RequestReceipt(): try: self.callbacks.progress(self) except Exception as e: - RNS.log("Error while executing response progress callback from "+str(self)+". The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Error while executing response progress callback from {self}. The contained exception was: {e}", RNS.LOG_ERROR) if self.callbacks.response != None: try: self.callbacks.response(self) except Exception as e: - RNS.log("Error while executing response received callback from "+str(self)+". The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Error while executing response received callback from {self}. The contained exception was: {e}", RNS.LOG_ERROR) def get_request_id(self): """ diff --git a/RNS/Packet.py b/RNS/Packet.py index 2db664b..03eccf0 100755 --- a/RNS/Packet.py +++ b/RNS/Packet.py @@ -208,14 +208,14 @@ class Packet: # Announce packets are not encrypted self.ciphertext = self.data else: - raise IOError("Packet with header type 2 must have a transport ID") + raise OSError("Packet with header type 2 must have a transport ID") self.header += bytes([self.context]) self.raw = self.header + self.ciphertext if len(self.raw) > self.MTU: - raise IOError("Packet size of "+str(len(self.raw))+" exceeds MTU of "+str(self.MTU)+" bytes") + raise OSError(f"Packet size of {len(self.raw)} exceeds MTU of {self.MTU} bytes") self.packed = True self.update_hash() @@ -250,7 +250,7 @@ class Packet: return True except Exception as e: - RNS.log("Received malformed packet, dropping it. The contained exception was: "+str(e), RNS.LOG_EXTREME) + RNS.log(f"Received malformed packet, dropping it. The contained exception was: {e}", RNS.LOG_EXTREME) return False def send(self): @@ -262,7 +262,7 @@ class Packet: if not self.sent: if self.destination.type == RNS.Destination.LINK: if self.destination.status == RNS.Link.CLOSED: - raise IOError("Attempt to transmit over a closed link") + raise OSError("Attempt to transmit over a closed link") else: self.destination.last_outbound = time.time() self.destination.tx += 1 @@ -280,7 +280,7 @@ class Packet: return False else: - raise IOError("Packet was already sent") + raise OSError("Packet was already sent") def resend(self): """ @@ -301,7 +301,7 @@ class Packet: self.receipt = None return False else: - raise IOError("Packet was not sent yet") + raise OSError("Packet was not sent yet") def prove(self, destination=None): if self.fromPacked and hasattr(self, "destination") and self.destination: @@ -419,8 +419,8 @@ class PacketReceipt: try: self.callbacks.delivery(self) except Exception as e: - RNS.log("An error occurred while evaluating external delivery callback for "+str(link), RNS.LOG_ERROR) - RNS.log("The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"An error occurred while evaluating external delivery callback for {link}", RNS.LOG_ERROR) + RNS.log(f"The contained exception was: {e}", RNS.LOG_ERROR) RNS.trace_exception(e) return True @@ -465,7 +465,7 @@ class PacketReceipt: try: self.callbacks.delivery(self) except Exception as e: - RNS.log("Error while executing proof validated callback. The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Error while executing proof validated callback. The contained exception was: {e}", RNS.LOG_ERROR) return True else: @@ -489,7 +489,7 @@ class PacketReceipt: try: self.callbacks.delivery(self) except Exception as e: - RNS.log("Error while executing proof validated callback. The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Error while executing proof validated callback. The contained exception was: {e}", RNS.LOG_ERROR) return True else: diff --git a/RNS/Resource.py b/RNS/Resource.py index d61dbf2..222bc5e 100644 --- a/RNS/Resource.py +++ b/RNS/Resource.py @@ -173,7 +173,7 @@ class Resource: resource.window_flexibility = Resource.WINDOW_FLEXIBILITY resource.last_activity = time.time() - resource.storagepath = RNS.Reticulum.resourcepath+"/"+resource.original_hash.hex() + resource.storagepath = f"{RNS.Reticulum.resourcepath}/{resource.original_hash.hex()}" resource.segment_index = adv.i resource.total_segments = adv.l if adv.l > 1: @@ -195,7 +195,7 @@ class Resource: try: resource.link.callbacks.resource_started(resource) except Exception as e: - RNS.log("Error while executing resource started callback from "+str(resource)+". The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Error while executing resource started callback from {resource}. The contained exception was: {e}", RNS.LOG_ERROR) resource.hashmap_update(0, resource.hashmap_raw) @@ -204,7 +204,7 @@ class Resource: return resource else: - RNS.log("Ignoring resource advertisement for "+RNS.prettyhexrep(resource.hash)+", resource already transferring", RNS.LOG_DEBUG) + RNS.log(f"Ignoring resource advertisement for {RNS.prettyhexrep(resource.hash)}, resource already transferring", RNS.LOG_DEBUG) return None except Exception as e: @@ -308,7 +308,7 @@ class Resource: if (auto_compress and len(self.uncompressed_data) <= Resource.AUTO_COMPRESS_MAX_SIZE): RNS.log("Compressing resource data...", RNS.LOG_DEBUG) self.compressed_data = bz2.compress(self.uncompressed_data) - RNS.log("Compression completed in "+str(round(time.time()-compression_began, 3))+" seconds", RNS.LOG_DEBUG) + RNS.log(f"Compression completed in {round(time.time() - compression_began, 3)} seconds", RNS.LOG_DEBUG) else: self.compressed_data = self.uncompressed_data @@ -317,7 +317,7 @@ class Resource: if (self.compressed_size < self.uncompressed_size and auto_compress): saved_bytes = len(self.uncompressed_data) - len(self.compressed_data) - RNS.log("Compression saved "+str(saved_bytes)+" bytes, sending compressed", RNS.LOG_DEBUG) + RNS.log(f"Compression saved {saved_bytes} bytes, sending compressed", RNS.LOG_DEBUG) self.data = b"" self.data += RNS.Identity.get_random_hash()[:Resource.RANDOM_HASH_SIZE] @@ -352,7 +352,7 @@ class Resource: hashmap_ok = False while not hashmap_ok: hashmap_computation_began = time.time() - RNS.log("Starting resource hashmap computation with "+str(hashmap_entries)+" entries...", RNS.LOG_DEBUG) + RNS.log(f"Starting resource hashmap computation with {hashmap_entries} entries...", RNS.LOG_DEBUG) self.random_hash = RNS.Identity.get_random_hash()[:Resource.RANDOM_HASH_SIZE] self.hash = RNS.Identity.full_hash(data+self.random_hash) @@ -388,7 +388,7 @@ class Resource: self.hashmap += part.map_hash self.parts.append(part) - RNS.log("Hashmap computation concluded in "+str(round(time.time()-hashmap_computation_began, 3))+" seconds", RNS.LOG_DEBUG) + RNS.log(f"Hashmap computation concluded in {round(time.time() - hashmap_computation_began, 3)} seconds", RNS.LOG_DEBUG) if advertise: self.advertise() @@ -447,9 +447,9 @@ class Resource: self.status = Resource.ADVERTISED self.retries_left = self.max_adv_retries self.link.register_outgoing_resource(self) - RNS.log("Sent resource advertisement for "+RNS.prettyhexrep(self.hash), RNS.LOG_DEBUG) + RNS.log(f"Sent resource advertisement for {RNS.prettyhexrep(self.hash)}", RNS.LOG_DEBUG) except Exception as e: - RNS.log("Could not advertise resource, the contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Could not advertise resource, the contained exception was: {e}", RNS.LOG_ERROR) self.cancel() return @@ -487,7 +487,7 @@ class Resource: self.adv_sent = self.last_activity sleep_time = 0.001 except Exception as e: - RNS.log("Could not resend advertisement packet, cancelling resource. The contained exception was: "+str(e), RNS.LOG_VERBOSE) + RNS.log(f"Could not resend advertisement packet, cancelling resource. The contained exception was: {e}", RNS.LOG_VERBOSE) self.cancel() @@ -508,7 +508,7 @@ class Resource: if sleep_time < 0: if self.retries_left > 0: ms = "" if self.outstanding_parts == 1 else "s" - RNS.log("Timed out waiting for "+str(self.outstanding_parts)+" part"+ms+", requesting retry", RNS.LOG_DEBUG) + RNS.log(f"Timed out waiting for {self.outstanding_parts} part{ms}, requesting retry", RNS.LOG_DEBUG) if self.window > self.window_min: self.window -= 1 if self.window_max > self.window_min: @@ -595,7 +595,7 @@ class Resource: except Exception as e: RNS.log("Error while assembling received resource.", RNS.LOG_ERROR) - RNS.log("The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"The contained exception was: {e}", RNS.LOG_ERROR) self.status = Resource.CORRUPT self.link.resource_concluded(self) @@ -606,7 +606,7 @@ class Resource: try: self.callback(self) except Exception as e: - RNS.log("Error while executing resource assembled callback from "+str(self)+". The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Error while executing resource assembled callback from {self}. The contained exception was: {e}", RNS.LOG_ERROR) try: if hasattr(self.data, "close") and callable(self.data.close): @@ -618,7 +618,7 @@ class Resource: RNS.log("Error while cleaning up resource files, the contained exception was:", RNS.LOG_ERROR) RNS.log(str(e)) else: - RNS.log("Resource segment "+str(self.segment_index)+" of "+str(self.total_segments)+" received, waiting for next segment to be announced", RNS.LOG_DEBUG) + RNS.log(f"Resource segment {self.segment_index} of {self.total_segments} received, waiting for next segment to be announced", RNS.LOG_DEBUG) def prove(self): @@ -631,7 +631,7 @@ class Resource: RNS.Transport.cache(proof_packet, force_cache=True) except Exception as e: RNS.log("Could not send proof packet, cancelling resource", RNS.LOG_DEBUG) - RNS.log("The contained exception was: "+str(e), RNS.LOG_DEBUG) + RNS.log(f"The contained exception was: {e}", RNS.LOG_DEBUG) self.cancel() def __prepare_next_segment(self): @@ -662,7 +662,7 @@ class Resource: try: self.callback(self) except Exception as e: - RNS.log("Error while executing resource concluded callback from "+str(self)+". The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Error while executing resource concluded callback from {self}. The contained exception was: {e}", RNS.LOG_ERROR) finally: try: if hasattr(self, "input_file"): @@ -670,7 +670,7 @@ class Resource: self.input_file.close() except Exception as e: - RNS.log("Error while closing resource input file: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Error while closing resource input file: {e}", RNS.LOG_ERROR) else: # Otherwise we'll recursively create the # next segment of the resource @@ -747,7 +747,7 @@ class Resource: try: self.__progress_callback(self) except Exception as e: - RNS.log("Error while executing progress callback from "+str(self)+". The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Error while executing progress callback from {self}. The contained exception was: {e}", RNS.LOG_ERROR) i += 1 @@ -835,7 +835,7 @@ class Resource: except Exception as e: RNS.log("Could not send resource request packet, cancelling resource", RNS.LOG_DEBUG) - RNS.log("The contained exception was: "+str(e), RNS.LOG_DEBUG) + RNS.log(f"The contained exception was: {e}", RNS.LOG_DEBUG) self.cancel() # Called on outgoing resource to make it send more data @@ -881,7 +881,7 @@ class Resource: except Exception as e: RNS.log("Resource could not send parts, cancelling transfer!", RNS.LOG_DEBUG) - RNS.log("The contained exception was: "+str(e), RNS.LOG_DEBUG) + RNS.log(f"The contained exception was: {e}", RNS.LOG_DEBUG) self.cancel() if wants_more_hashmap: @@ -920,7 +920,7 @@ class Resource: self.last_activity = time.time() except Exception as e: RNS.log("Could not send resource HMU packet, cancelling resource", RNS.LOG_DEBUG) - RNS.log("The contained exception was: "+str(e), RNS.LOG_DEBUG) + RNS.log(f"The contained exception was: {e}", RNS.LOG_DEBUG) self.cancel() if self.sent_parts == len(self.parts): @@ -931,7 +931,7 @@ class Resource: try: self.__progress_callback(self) except Exception as e: - RNS.log("Error while executing progress callback from "+str(self)+". The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Error while executing progress callback from {self}. The contained exception was: {e}", RNS.LOG_ERROR) def cancel(self): """ @@ -945,7 +945,7 @@ class Resource: cancel_packet = RNS.Packet(self.link, self.hash, context=RNS.Packet.RESOURCE_ICL) cancel_packet.send() except Exception as e: - RNS.log("Could not send resource cancel packet, the contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Could not send resource cancel packet, the contained exception was: {e}", RNS.LOG_ERROR) self.link.cancel_outgoing_resource(self) else: self.link.cancel_incoming_resource(self) @@ -955,7 +955,7 @@ class Resource: self.link.resource_concluded(self) self.callback(self) except Exception as e: - RNS.log("Error while executing callbacks on resource cancel from "+str(self)+". The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Error while executing callbacks on resource cancel from {self}. The contained exception was: {e}", RNS.LOG_ERROR) def set_callback(self, callback): self.callback = callback @@ -1068,7 +1068,7 @@ class Resource: return self.compressed def __str__(self): - return "<"+RNS.hexrep(self.hash,delimit=False)+"/"+RNS.hexrep(self.link.link_id,delimit=False)+">" + return f"<{RNS.hexrep(self.hash, delimit=False)}/{RNS.hexrep(self.link.link_id, delimit=False)}>" class ResourceAdvertisement: diff --git a/RNS/Reticulum.py b/RNS/Reticulum.py index 1176db1..6259c3e 100755 --- a/RNS/Reticulum.py +++ b/RNS/Reticulum.py @@ -204,20 +204,20 @@ class Reticulum: else: if os.path.isdir("/etc/reticulum") and os.path.isfile("/etc/reticulum/config"): Reticulum.configdir = "/etc/reticulum" - elif os.path.isdir(Reticulum.userdir+"/.config/reticulum") and os.path.isfile(Reticulum.userdir+"/.config/reticulum/config"): - Reticulum.configdir = Reticulum.userdir+"/.config/reticulum" + elif os.path.isdir(f"{Reticulum.userdir}/.config/reticulum") and os.path.isfile(f"{Reticulum.userdir}/.config/reticulum/config"): + Reticulum.configdir = f"{Reticulum.userdir}/.config/reticulum" else: - Reticulum.configdir = Reticulum.userdir+"/.reticulum" + Reticulum.configdir = f"{Reticulum.userdir}/.reticulum" if logdest == RNS.LOG_FILE: RNS.logdest = RNS.LOG_FILE - RNS.logfile = Reticulum.configdir+"/logfile" + RNS.logfile = f"{Reticulum.configdir}/logfile" - Reticulum.configpath = Reticulum.configdir+"/config" - Reticulum.storagepath = Reticulum.configdir+"/storage" - Reticulum.cachepath = Reticulum.configdir+"/storage/cache" - Reticulum.resourcepath = Reticulum.configdir+"/storage/resources" - Reticulum.identitypath = Reticulum.configdir+"/storage/identities" + Reticulum.configpath = f"{Reticulum.configdir}/config" + Reticulum.storagepath = f"{Reticulum.configdir}/storage" + Reticulum.cachepath = f"{Reticulum.configdir}/storage/cache" + Reticulum.resourcepath = f"{Reticulum.configdir}/storage/resources" + Reticulum.identitypath = f"{Reticulum.configdir}/storage/identities" Reticulum.__transport_enabled = False Reticulum.__remote_management_enabled = False @@ -267,17 +267,17 @@ class Reticulum: try: self.config = ConfigObj(self.configpath) except Exception as e: - RNS.log("Could not parse the configuration at "+self.configpath, RNS.LOG_ERROR) + RNS.log(f"Could not parse the configuration at {self.configpath}", RNS.LOG_ERROR) RNS.log("Check your configuration file for errors!", RNS.LOG_ERROR) RNS.panic() else: RNS.log("Could not load config file, creating default configuration file...") self.__create_default_config() - RNS.log("Default config file created. Make any necessary changes in "+Reticulum.configdir+"/config and restart Reticulum if needed.") + RNS.log(f"Default config file created. Make any necessary changes in {Reticulum.configdir}/config and restart Reticulum if needed.") time.sleep(1.5) self.__apply_config() - RNS.log("Configuration loaded from "+self.configpath, RNS.LOG_VERBOSE) + RNS.log(f"Configuration loaded from {self.configpath}", RNS.LOG_VERBOSE) RNS.Identity.load_known_destinations() @@ -332,7 +332,7 @@ class Reticulum: RNS.Transport.interfaces.append(interface) self.is_shared_instance = True - RNS.log("Started shared instance interface: "+str(interface), RNS.LOG_DEBUG) + RNS.log(f"Started shared instance interface: {interface}", RNS.LOG_DEBUG) self.__start_jobs() except Exception as e: @@ -354,10 +354,10 @@ class Reticulum: Reticulum.__transport_enabled = False Reticulum.__remote_management_enabled = False Reticulum.__allow_probes = False - RNS.log("Connected to locally available Reticulum instance via: "+str(interface), RNS.LOG_DEBUG) + RNS.log(f"Connected to locally available Reticulum instance via: {interface}", RNS.LOG_DEBUG) except Exception as e: RNS.log("Local shared instance appears to be running, but it could not be connected", RNS.LOG_ERROR) - RNS.log("The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"The contained exception was: {e}", RNS.LOG_ERROR) self.is_shared_instance = False self.is_standalone_instance = True self.is_connected_to_shared_instance = False @@ -412,11 +412,11 @@ class Reticulum: for hexhash in v: dest_len = (RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2 if len(hexhash) != dest_len: - raise ValueError("Identity hash length for remote management ACL "+str(hexhash)+" is invalid, must be {hex} hexadecimal characters ({byte} bytes).".format(hex=dest_len, byte=dest_len//2)) + raise ValueError(f"Identity hash length for remote management ACL {hexhash} is invalid, must be {dest_len} hexadecimal characters ({dest_len // 2} bytes).") try: allowed_hash = bytes.fromhex(hexhash) except Exception as e: - raise ValueError("Invalid identity hash for remote management ACL: "+str(hexhash)) + raise ValueError(f"Invalid identity hash for remote management ACL: {hexhash}") if not allowed_hash in RNS.Transport.remote_management_allowed: RNS.Transport.remote_management_allowed.append(allowed_hash) @@ -659,7 +659,7 @@ class Reticulum: interface.OUT = True if interface_mode == Interface.Interface.MODE_ACCESS_POINT: - RNS.log(str(interface)+" does not support Access Point mode, reverting to default mode: Full", RNS.LOG_WARNING) + RNS.log(f"{interface} does not support Access Point mode, reverting to default mode: Full", RNS.LOG_WARNING) interface_mode = Interface.Interface.MODE_FULL interface.mode = interface_mode @@ -696,7 +696,7 @@ class Reticulum: interface.OUT = True if interface_mode == Interface.Interface.MODE_ACCESS_POINT: - RNS.log(str(interface)+" does not support Access Point mode, reverting to default mode: Full", RNS.LOG_WARNING) + RNS.log(f"{interface} does not support Access Point mode, reverting to default mode: Full", RNS.LOG_WARNING) interface_mode = Interface.Interface.MODE_FULL interface.mode = interface_mode @@ -733,7 +733,7 @@ class Reticulum: interface.OUT = True if interface_mode == Interface.Interface.MODE_ACCESS_POINT: - RNS.log(str(interface)+" does not support Access Point mode, reverting to default mode: Full", RNS.LOG_WARNING) + RNS.log(f"{interface} does not support Access Point mode, reverting to default mode: Full", RNS.LOG_WARNING) interface_mode = Interface.Interface.MODE_FULL interface.mode = interface_mode @@ -1030,17 +1030,17 @@ class Reticulum: # if no subinterfaces are defined if count == 0: - raise ValueError("No subinterfaces configured for "+name) + raise ValueError(f"No subinterfaces configured for {name}") # if no subinterfaces are enabled elif enabled_count == 0: - raise ValueError("No subinterfaces enabled for "+name) + raise ValueError(f"No subinterfaces enabled for {name}") id_interval = int(c["id_interval"]) if "id_interval" in c else None id_callsign = c["id_callsign"] if "id_callsign" in c else None port = c["port"] if "port" in c else None if port == None: - raise ValueError("No port specified for "+name) + raise ValueError(f"No port specified for {name}") interface = RNodeMultiInterface.RNodeMultiInterface( RNS.Transport, @@ -1107,14 +1107,14 @@ class Reticulum: interface.start() else: - RNS.log("Skipping disabled interface \""+name+"\"", RNS.LOG_DEBUG) + RNS.log(f"Skipping disabled interface \"{name}\"", RNS.LOG_DEBUG) except Exception as e: - RNS.log("The interface \""+name+"\" could not be created. Check your configuration file for errors!", RNS.LOG_ERROR) - RNS.log("The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"The interface \"{name}\" could not be created. Check your configuration file for errors!", RNS.LOG_ERROR) + RNS.log(f"The contained exception was: {e}", RNS.LOG_ERROR) RNS.panic() else: - RNS.log("The interface name \""+name+"\" was already used. Check your configuration file for errors!", RNS.LOG_ERROR) + RNS.log(f"The interface name \"{name}\" was already used. Check your configuration file for errors!", RNS.LOG_ERROR) RNS.panic() RNS.log("System interfaces are ready", RNS.LOG_VERBOSE) @@ -1182,27 +1182,27 @@ class Reticulum: for filename in os.listdir(self.resourcepath): try: if len(filename) == (RNS.Identity.HASHLENGTH//8)*2: - filepath = self.resourcepath + "/" + filename + filepath = f"{self.resourcepath}/{filename}" mtime = os.path.getmtime(filepath) age = now - mtime if age > Reticulum.RESOURCE_CACHE: os.unlink(filepath) except Exception as e: - RNS.log("Error while cleaning resources cache, the contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Error while cleaning resources cache, the contained exception was: {e}", RNS.LOG_ERROR) # Clean packet caches for filename in os.listdir(self.cachepath): try: if len(filename) == (RNS.Identity.HASHLENGTH//8)*2: - filepath = self.cachepath + "/" + filename + filepath = f"{self.cachepath}/{filename}" mtime = os.path.getmtime(filepath) age = now - mtime if age > RNS.Transport.DESTINATION_TIMEOUT: os.unlink(filepath) except Exception as e: - RNS.log("Error while cleaning resources cache, the contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Error while cleaning resources cache, the contained exception was: {e}", RNS.LOG_ERROR) def __create_default_config(self): self.config = ConfigObj(__default_rns_config__) @@ -1267,7 +1267,7 @@ class Reticulum: rpc_connection.close() except Exception as e: - RNS.log("An error ocurred while handling RPC call from local client: "+str(e), RNS.LOG_ERROR) + RNS.log(f"An error ocurred while handling RPC call from local client: {e}", RNS.LOG_ERROR) def get_interface_stats(self): if self.is_connected_to_shared_instance: @@ -1297,7 +1297,7 @@ class Reticulum: if hasattr(interface, "b32"): if interface.b32 != None: - ifstats["i2p_b32"] = interface.b32+".b32.i2p" + ifstats["i2p_b32"] = f"{interface.b32}.b32.i2p" else: ifstats["i2p_b32"] = None @@ -1486,12 +1486,12 @@ class Reticulum: if self.is_connected_to_shared_instance and hasattr(self, "_force_shared_instance_bitrate") and self._force_shared_instance_bitrate: simulated_latency = ((1/self._force_shared_instance_bitrate)*8)*RNS.Reticulum.MTU - RNS.log("Adding simulated latency of "+RNS.prettytime(simulated_latency)+" to first hop timeout", RNS.LOG_DEBUG) + RNS.log(f"Adding simulated latency of {RNS.prettytime(simulated_latency)} to first hop timeout", RNS.LOG_DEBUG) response += simulated_latency return response except Exception as e: - RNS.log("An error occurred while getting first hop timeout from shared instance: "+str(e), RNS.LOG_ERROR) + RNS.log(f"An error occurred while getting first hop timeout from shared instance: {e}", RNS.LOG_ERROR) return RNS.Reticulum.DEFAULT_PER_HOP_TIMEOUT else: diff --git a/RNS/Transport.py b/RNS/Transport.py index 2338383..3fe77a8 100755 --- a/RNS/Transport.py +++ b/RNS/Transport.py @@ -148,7 +148,7 @@ class Transport: Transport.owner = reticulum_instance if Transport.identity == None: - transport_identity_path = RNS.Reticulum.storagepath+"/transport_identity" + transport_identity_path = f"{RNS.Reticulum.storagepath}/transport_identity" if os.path.isfile(transport_identity_path): Transport.identity = RNS.Identity.from_file(transport_identity_path) @@ -159,7 +159,7 @@ class Transport: else: RNS.log("Loaded Transport Identity from storage", RNS.LOG_VERBOSE) - packet_hashlist_path = RNS.Reticulum.storagepath+"/packet_hashlist" + packet_hashlist_path = f"{RNS.Reticulum.storagepath}/packet_hashlist" if not Transport.owner.is_connected_to_shared_instance: if os.path.isfile(packet_hashlist_path): try: @@ -167,7 +167,7 @@ class Transport: Transport.packet_hashlist = umsgpack.unpackb(file.read()) file.close() except Exception as e: - RNS.log("Could not load packet hashlist from storage, the contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Could not load packet hashlist from storage, the contained exception was: {e}", RNS.LOG_ERROR) # Create transport-specific destinations Transport.path_request_destination = RNS.Destination(None, RNS.Destination.IN, RNS.Destination.PLAIN, Transport.APP_NAME, "path", "request") @@ -186,15 +186,15 @@ class Transport: Transport.remote_management_destination.register_request_handler("/path", response_generator = Transport.remote_path_handler, allow = RNS.Destination.ALLOW_LIST, allowed_list=Transport.remote_management_allowed) Transport.control_destinations.append(Transport.remote_management_destination) Transport.control_hashes.append(Transport.remote_management_destination.hash) - RNS.log("Enabled remote management on "+str(Transport.remote_management_destination), RNS.LOG_NOTICE) + RNS.log(f"Enabled remote management on {Transport.remote_management_destination}", RNS.LOG_NOTICE) Transport.jobs_running = False thread = threading.Thread(target=Transport.jobloop, daemon=True) thread.start() if RNS.Reticulum.transport_enabled(): - destination_table_path = RNS.Reticulum.storagepath+"/destination_table" - tunnel_table_path = RNS.Reticulum.storagepath+"/tunnels" + destination_table_path = f"{RNS.Reticulum.storagepath}/destination_table" + tunnel_table_path = f"{RNS.Reticulum.storagepath}/tunnels" if os.path.isfile(destination_table_path) and not Transport.owner.is_connected_to_shared_instance: serialised_destinations = [] @@ -223,9 +223,9 @@ class Transport: # increased hop-count. announce_packet.hops += 1 Transport.destination_table[destination_hash] = [timestamp, received_from, hops, expires, random_blobs, receiving_interface, announce_packet] - RNS.log("Loaded path table entry for "+RNS.prettyhexrep(destination_hash)+" from storage", RNS.LOG_DEBUG) + RNS.log(f"Loaded path table entry for {RNS.prettyhexrep(destination_hash)} from storage", RNS.LOG_DEBUG) else: - RNS.log("Could not reconstruct path table entry from storage for "+RNS.prettyhexrep(destination_hash), RNS.LOG_DEBUG) + RNS.log(f"Could not reconstruct path table entry from storage for {RNS.prettyhexrep(destination_hash)}", RNS.LOG_DEBUG) if announce_packet == None: RNS.log("The announce packet could not be loaded from cache", RNS.LOG_DEBUG) if receiving_interface == None: @@ -236,10 +236,10 @@ class Transport: else: specifier = "entries" - RNS.log("Loaded "+str(len(Transport.destination_table))+" path table "+specifier+" from storage", RNS.LOG_VERBOSE) + RNS.log(f"Loaded {len(Transport.destination_table)} path table {specifier} from storage", RNS.LOG_VERBOSE) except Exception as e: - RNS.log("Could not load destination table from storage, the contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Could not load destination table from storage, the contained exception was: {e}", RNS.LOG_ERROR) if os.path.isfile(tunnel_table_path) and not Transport.owner.is_connected_to_shared_instance: serialised_tunnels = [] @@ -284,21 +284,21 @@ class Transport: else: specifier = "entries" - RNS.log("Loaded "+str(len(Transport.tunnels))+" tunnel table "+specifier+" from storage", RNS.LOG_VERBOSE) + RNS.log(f"Loaded {len(Transport.tunnels)} tunnel table {specifier} from storage", RNS.LOG_VERBOSE) except Exception as e: - RNS.log("Could not load tunnel table from storage, the contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Could not load tunnel table from storage, the contained exception was: {e}", RNS.LOG_ERROR) if RNS.Reticulum.probe_destination_enabled(): Transport.probe_destination = RNS.Destination(Transport.identity, RNS.Destination.IN, RNS.Destination.SINGLE, Transport.APP_NAME, "probe") Transport.probe_destination.accepts_links(False) Transport.probe_destination.set_proof_strategy(RNS.Destination.PROVE_ALL) Transport.probe_destination.announce() - RNS.log("Transport Instance will respond to probe requests on "+str(Transport.probe_destination), RNS.LOG_NOTICE) + RNS.log(f"Transport Instance will respond to probe requests on {Transport.probe_destination}", RNS.LOG_NOTICE) else: Transport.probe_destination = None - RNS.log("Transport instance "+str(Transport.identity)+" started", RNS.LOG_VERBOSE) + RNS.log(f"Transport instance {Transport.identity} started", RNS.LOG_VERBOSE) Transport.start_time = time.time() # Sort interfaces according to bitrate @@ -354,7 +354,7 @@ class Transport: last_path_request = Transport.path_requests[link.destination.hash] if time.time() - last_path_request > Transport.PATH_REQUEST_MI: - RNS.log("Trying to rediscover path for "+RNS.prettyhexrep(link.destination.hash)+" since an attempted link was never established", RNS.LOG_DEBUG) + RNS.log(f"Trying to rediscover path for {RNS.prettyhexrep(link.destination.hash)} since an attempted link was never established", RNS.LOG_DEBUG) if not link.destination.hash in path_requests: blocked_if = None path_requests[link.destination.hash] = blocked_if @@ -388,7 +388,7 @@ class Transport: for destination_hash in Transport.announce_table: announce_entry = Transport.announce_table[destination_hash] if announce_entry[2] > Transport.PATHFINDER_R: - RNS.log("Completed announce processing for "+RNS.prettyhexrep(destination_hash)+", retry limit reached", RNS.LOG_EXTREME) + RNS.log(f"Completed announce processing for {RNS.prettyhexrep(destination_hash)}, retry limit reached", RNS.LOG_EXTREME) completed_announces.append(destination_hash) else: if time.time() > announce_entry[1]: @@ -420,9 +420,9 @@ class Transport: new_packet.hops = announce_entry[4] if block_rebroadcasts: - RNS.log("Rebroadcasting announce as path response for "+RNS.prettyhexrep(announce_destination.hash)+" with hop count "+str(new_packet.hops), RNS.LOG_DEBUG) + RNS.log(f"Rebroadcasting announce as path response for {RNS.prettyhexrep(announce_destination.hash)} with hop count {new_packet.hops}", RNS.LOG_DEBUG) else: - RNS.log("Rebroadcasting announce for "+RNS.prettyhexrep(announce_destination.hash)+" with hop count "+str(new_packet.hops), RNS.LOG_DEBUG) + RNS.log(f"Rebroadcasting announce for {RNS.prettyhexrep(announce_destination.hash)} with hop count {new_packet.hops}", RNS.LOG_DEBUG) outgoing.append(new_packet) @@ -490,14 +490,14 @@ class Transport: # If the path has been invalidated between the time of # making the link request and now, try to rediscover it if not Transport.has_path(link_entry[6]): - RNS.log("Trying to rediscover path for "+RNS.prettyhexrep(link_entry[6])+" since an attempted link was never established, and path is now missing", RNS.LOG_DEBUG) + RNS.log(f"Trying to rediscover path for {RNS.prettyhexrep(link_entry[6])} since an attempted link was never established, and path is now missing", RNS.LOG_DEBUG) path_request_conditions =True # If this link request was originated from a local client # attempt to rediscover a path to the destination, if this # has not already happened recently. elif not path_request_throttle and lr_taken_hops == 0: - RNS.log("Trying to rediscover path for "+RNS.prettyhexrep(link_entry[6])+" since an attempted local client link was never established", RNS.LOG_DEBUG) + RNS.log(f"Trying to rediscover path for {RNS.prettyhexrep(link_entry[6])} since an attempted local client link was never established", RNS.LOG_DEBUG) path_request_conditions = True # If the link destination was previously only 1 hop @@ -506,7 +506,7 @@ class Transport: # In that case, try to discover a new path, and mark # the old one as unresponsive. elif not path_request_throttle and Transport.hops_to(link_entry[6]) == 1: - RNS.log("Trying to rediscover path for "+RNS.prettyhexrep(link_entry[6])+" since an attempted link was never established, and destination was previously local to an interface on this instance", RNS.LOG_DEBUG) + RNS.log(f"Trying to rediscover path for {RNS.prettyhexrep(link_entry[6])} since an attempted link was never established, and destination was previously local to an interface on this instance", RNS.LOG_DEBUG) path_request_conditions = True blocked_if = link_entry[4] @@ -528,7 +528,7 @@ class Transport: # changed. In that case, we try to discover a new path, # and mark the old one as potentially unresponsive. elif not path_request_throttle and lr_taken_hops == 1: - RNS.log("Trying to rediscover path for "+RNS.prettyhexrep(link_entry[6])+" since an attempted link was never established, and link initiator is local to an interface on this instance", RNS.LOG_DEBUG) + RNS.log(f"Trying to rediscover path for {RNS.prettyhexrep(link_entry[6])} since an attempted link was never established, and link initiator is local to an interface on this instance", RNS.LOG_DEBUG) path_request_conditions = True blocked_if = link_entry[4] @@ -561,10 +561,10 @@ class Transport: if time.time() > destination_expiry: stale_paths.append(destination_hash) - RNS.log("Path to "+RNS.prettyhexrep(destination_hash)+" timed out and was removed", RNS.LOG_DEBUG) + RNS.log(f"Path to {RNS.prettyhexrep(destination_hash)} timed out and was removed", RNS.LOG_DEBUG) elif not attached_interface in Transport.interfaces: stale_paths.append(destination_hash) - RNS.log("Path to "+RNS.prettyhexrep(destination_hash)+" was removed since the attached interface no longer exists", RNS.LOG_DEBUG) + RNS.log(f"Path to {RNS.prettyhexrep(destination_hash)} was removed since the attached interface no longer exists", RNS.LOG_DEBUG) # Cull the pending discovery path requests table stale_discovery_path_requests = [] @@ -573,7 +573,7 @@ class Transport: if time.time() > entry["timeout"]: stale_discovery_path_requests.append(destination_hash) - RNS.log("Waiting path request for "+RNS.prettyhexrep(destination_hash)+" timed out and was removed", RNS.LOG_DEBUG) + RNS.log(f"Waiting path request for {RNS.prettyhexrep(destination_hash)} timed out and was removed", RNS.LOG_DEBUG) # Cull the tunnel table stale_tunnels = [] @@ -584,7 +584,7 @@ class Transport: expires = tunnel_entry[3] if time.time() > expires: stale_tunnels.append(tunnel_id) - RNS.log("Tunnel "+RNS.prettyhexrep(tunnel_id)+" timed out and was removed", RNS.LOG_EXTREME) + RNS.log(f"Tunnel {RNS.prettyhexrep(tunnel_id)} timed out and was removed", RNS.LOG_EXTREME) else: stale_tunnel_paths = [] tunnel_paths = tunnel_entry[2] @@ -593,7 +593,7 @@ class Transport: if time.time() > tunnel_path_entry[0] + Transport.DESTINATION_TIMEOUT: stale_tunnel_paths.append(tunnel_path) - RNS.log("Tunnel path to "+RNS.prettyhexrep(tunnel_path)+" timed out and was removed", RNS.LOG_EXTREME) + RNS.log(f"Tunnel path to {RNS.prettyhexrep(tunnel_path)} timed out and was removed", RNS.LOG_EXTREME) for tunnel_path in stale_tunnel_paths: tunnel_paths.pop(tunnel_path) @@ -602,9 +602,9 @@ class Transport: if ti > 0: if ti == 1: - RNS.log("Removed "+str(ti)+" tunnel path", RNS.LOG_EXTREME) + RNS.log(f"Removed {ti} tunnel path", RNS.LOG_EXTREME) else: - RNS.log("Removed "+str(ti)+" tunnel paths", RNS.LOG_EXTREME) + RNS.log(f"Removed {ti} tunnel paths", RNS.LOG_EXTREME) i = 0 for truncated_packet_hash in stale_reverse_entries: @@ -613,9 +613,9 @@ class Transport: if i > 0: if i == 1: - RNS.log("Released "+str(i)+" reverse table entry", RNS.LOG_EXTREME) + RNS.log(f"Released {i} reverse table entry", RNS.LOG_EXTREME) else: - RNS.log("Released "+str(i)+" reverse table entries", RNS.LOG_EXTREME) + RNS.log(f"Released {i} reverse table entries", RNS.LOG_EXTREME) i = 0 for link_id in stale_links: @@ -624,9 +624,9 @@ class Transport: if i > 0: if i == 1: - RNS.log("Released "+str(i)+" link", RNS.LOG_EXTREME) + RNS.log(f"Released {i} link", RNS.LOG_EXTREME) else: - RNS.log("Released "+str(i)+" links", RNS.LOG_EXTREME) + RNS.log(f"Released {i} links", RNS.LOG_EXTREME) i = 0 for destination_hash in stale_paths: @@ -635,9 +635,9 @@ class Transport: if i > 0: if i == 1: - RNS.log("Removed "+str(i)+" path", RNS.LOG_EXTREME) + RNS.log(f"Removed {i} path", RNS.LOG_EXTREME) else: - RNS.log("Removed "+str(i)+" paths", RNS.LOG_EXTREME) + RNS.log(f"Removed {i} paths", RNS.LOG_EXTREME) i = 0 for destination_hash in stale_discovery_path_requests: @@ -646,9 +646,9 @@ class Transport: if i > 0: if i == 1: - RNS.log("Removed "+str(i)+" waiting path request", RNS.LOG_EXTREME) + RNS.log(f"Removed {i} waiting path request", RNS.LOG_EXTREME) else: - RNS.log("Removed "+str(i)+" waiting path requests", RNS.LOG_EXTREME) + RNS.log(f"Removed {i} waiting path requests", RNS.LOG_EXTREME) i = 0 for tunnel_id in stale_tunnels: @@ -657,9 +657,9 @@ class Transport: if i > 0: if i == 1: - RNS.log("Removed "+str(i)+" tunnel", RNS.LOG_EXTREME) + RNS.log(f"Removed {i} tunnel", RNS.LOG_EXTREME) else: - RNS.log("Removed "+str(i)+" tunnels", RNS.LOG_EXTREME) + RNS.log(f"Removed {i} tunnels", RNS.LOG_EXTREME) i = 0 for destination_hash in stale_path_states: @@ -668,9 +668,9 @@ class Transport: if i > 0: if i == 1: - RNS.log("Removed "+str(i)+" path state entry", RNS.LOG_EXTREME) + RNS.log(f"Removed {i} path state entry", RNS.LOG_EXTREME) else: - RNS.log("Removed "+str(i)+" path state entries", RNS.LOG_EXTREME) + RNS.log(f"Removed {i} path state entries", RNS.LOG_EXTREME) Transport.tables_last_culled = time.time() @@ -686,7 +686,7 @@ class Transport: except Exception as e: RNS.log("An exception occurred while running Transport jobs.", RNS.LOG_ERROR) - RNS.log("The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"The contained exception was: {e}", RNS.LOG_ERROR) Transport.jobs_running = False @@ -749,7 +749,7 @@ class Transport: interface.processOutgoing(raw) except Exception as e: - RNS.log("Error while transmitting on "+str(interface)+". The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Error while transmitting on {interface}. The contained exception was: {e}", RNS.LOG_ERROR) @staticmethod def outbound(packet): @@ -857,7 +857,7 @@ class Transport: if packet.packet_type == RNS.Packet.ANNOUNCE: if packet.attached_interface == None: if interface.mode == RNS.Interfaces.Interface.Interface.MODE_ACCESS_POINT: - RNS.log("Blocking announce broadcast on "+str(interface)+" due to AP mode", RNS.LOG_EXTREME) + RNS.log(f"Blocking announce broadcast on {interface} due to AP mode", RNS.LOG_EXTREME) should_transmit = False elif interface.mode == RNS.Interfaces.Interface.Interface.MODE_ROAMING: @@ -870,15 +870,15 @@ class Transport: if from_interface == None or not hasattr(from_interface, "mode"): should_transmit = False if from_interface == None: - RNS.log("Blocking announce broadcast on "+str(interface)+" since next hop interface doesn't exist", RNS.LOG_EXTREME) + RNS.log(f"Blocking announce broadcast on {interface} since next hop interface doesn't exist", RNS.LOG_EXTREME) elif not hasattr(from_interface, "mode"): - RNS.log("Blocking announce broadcast on "+str(interface)+" since next hop interface has no mode configured", RNS.LOG_EXTREME) + RNS.log(f"Blocking announce broadcast on {interface} since next hop interface has no mode configured", RNS.LOG_EXTREME) else: if from_interface.mode == RNS.Interfaces.Interface.Interface.MODE_ROAMING: - RNS.log("Blocking announce broadcast on "+str(interface)+" due to roaming-mode next-hop interface", RNS.LOG_EXTREME) + RNS.log(f"Blocking announce broadcast on {interface} due to roaming-mode next-hop interface", RNS.LOG_EXTREME) should_transmit = False elif from_interface.mode == RNS.Interfaces.Interface.Interface.MODE_BOUNDARY: - RNS.log("Blocking announce broadcast on "+str(interface)+" due to boundary-mode next-hop interface", RNS.LOG_EXTREME) + RNS.log(f"Blocking announce broadcast on {interface} due to boundary-mode next-hop interface", RNS.LOG_EXTREME) should_transmit = False elif interface.mode == RNS.Interfaces.Interface.Interface.MODE_BOUNDARY: @@ -891,12 +891,12 @@ class Transport: if from_interface == None or not hasattr(from_interface, "mode"): should_transmit = False if from_interface == None: - RNS.log("Blocking announce broadcast on "+str(interface)+" since next hop interface doesn't exist", RNS.LOG_EXTREME) + RNS.log(f"Blocking announce broadcast on {interface} since next hop interface doesn't exist", RNS.LOG_EXTREME) elif not hasattr(from_interface, "mode"): - RNS.log("Blocking announce broadcast on "+str(interface)+" since next hop interface has no mode configured", RNS.LOG_EXTREME) + RNS.log(f"Blocking announce broadcast on {interface} since next hop interface has no mode configured", RNS.LOG_EXTREME) else: if from_interface.mode == RNS.Interfaces.Interface.Interface.MODE_ROAMING: - RNS.log("Blocking announce broadcast on "+str(interface)+" due to roaming-mode next-hop interface", RNS.LOG_EXTREME) + RNS.log(f"Blocking announce broadcast on {interface} due to roaming-mode next-hop interface", RNS.LOG_EXTREME) should_transmit = False else: @@ -959,23 +959,23 @@ class Transport: timer.start() if wait_time < 1: - wait_time_str = str(round(wait_time*1000,2))+"ms" + wait_time_str = f"{round(wait_time * 1000, 2)}ms" else: - wait_time_str = str(round(wait_time*1,2))+"s" + wait_time_str = f"{round(wait_time * 1, 2)}s" ql_str = str(len(interface.announce_queue)) - RNS.log("Added announce to queue (height "+ql_str+") on "+str(interface)+" for processing in "+wait_time_str, RNS.LOG_EXTREME) + RNS.log(f"Added announce to queue (height {ql_str}) on {interface} for processing in {wait_time_str}", RNS.LOG_EXTREME) else: wait_time = max(interface.announce_allowed_at - time.time(), 0) if wait_time < 1: - wait_time_str = str(round(wait_time*1000,2))+"ms" + wait_time_str = f"{round(wait_time * 1000, 2)}ms" else: - wait_time_str = str(round(wait_time*1,2))+"s" + wait_time_str = f"{round(wait_time * 1, 2)}s" ql_str = str(len(interface.announce_queue)) - RNS.log("Added announce to queue (height "+ql_str+") on "+str(interface)+" for processing in "+wait_time_str, RNS.LOG_EXTREME) + RNS.log(f"Added announce to queue (height {ql_str}) on {interface} for processing in {wait_time_str}", RNS.LOG_EXTREME) else: pass @@ -1013,7 +1013,7 @@ class Transport: # Filter packets intended for other transport instances if packet.transport_id != None and packet.packet_type != RNS.Packet.ANNOUNCE: if packet.transport_id != Transport.identity.hash: - RNS.log("Ignored packet "+RNS.prettyhexrep(packet.packet_hash)+" in transport for other transport instance", RNS.LOG_EXTREME) + RNS.log(f"Ignored packet {RNS.prettyhexrep(packet.packet_hash)} in transport for other transport instance", RNS.LOG_EXTREME) return False if packet.context == RNS.Packet.KEEPALIVE: @@ -1032,7 +1032,7 @@ class Transport: if packet.destination_type == RNS.Destination.PLAIN: if packet.packet_type != RNS.Packet.ANNOUNCE: if packet.hops > 1: - RNS.log("Dropped PLAIN packet "+RNS.prettyhexrep(packet.hash)+" with "+str(packet.hops)+" hops", RNS.LOG_DEBUG) + RNS.log(f"Dropped PLAIN packet {RNS.prettyhexrep(packet.hash)} with {packet.hops} hops", RNS.LOG_DEBUG) return False else: return True @@ -1043,7 +1043,7 @@ class Transport: if packet.destination_type == RNS.Destination.GROUP: if packet.packet_type != RNS.Packet.ANNOUNCE: if packet.hops > 1: - RNS.log("Dropped GROUP packet "+RNS.prettyhexrep(packet.hash)+" with "+str(packet.hops)+" hops", RNS.LOG_DEBUG) + RNS.log(f"Dropped GROUP packet {RNS.prettyhexrep(packet.hash)} with {packet.hops} hops", RNS.LOG_DEBUG) return False else: return True @@ -1061,7 +1061,7 @@ class Transport: RNS.log("Dropped invalid announce packet", RNS.LOG_DEBUG) return False - RNS.log("Filtered packet with hash "+RNS.prettyhexrep(packet.packet_hash), RNS.LOG_EXTREME) + RNS.log(f"Filtered packet with hash {RNS.prettyhexrep(packet.packet_hash)}", RNS.LOG_EXTREME) return False @staticmethod @@ -1316,7 +1316,7 @@ class Transport: # TODO: There should probably be some kind of REJECT # mechanism here, to signal to the source that their # expected path failed. - RNS.log("Got packet in transport, but no known path to final destination "+RNS.prettyhexrep(packet.destination_hash)+". Dropping packet.", RNS.LOG_EXTREME) + RNS.log(f"Got packet in transport, but no known path to final destination {RNS.prettyhexrep(packet.destination_hash)}. Dropping packet.", RNS.LOG_EXTREME) # Link transport handling. Directs packets according # to entries in the link tables @@ -1391,17 +1391,17 @@ class Transport: announce_entry = Transport.announce_table[packet.destination_hash] if packet.hops-1 == announce_entry[4]: - RNS.log("Heard a local rebroadcast of announce for "+RNS.prettyhexrep(packet.destination_hash), RNS.LOG_DEBUG) + RNS.log(f"Heard a local rebroadcast of announce for {RNS.prettyhexrep(packet.destination_hash)}", RNS.LOG_DEBUG) announce_entry[6] += 1 if announce_entry[6] >= Transport.LOCAL_REBROADCASTS_MAX: - RNS.log("Max local rebroadcasts of announce for "+RNS.prettyhexrep(packet.destination_hash)+" reached, dropping announce from our table", RNS.LOG_DEBUG) + RNS.log(f"Max local rebroadcasts of announce for {RNS.prettyhexrep(packet.destination_hash)} reached, dropping announce from our table", RNS.LOG_DEBUG) if packet.destination_hash in Transport.announce_table: Transport.announce_table.pop(packet.destination_hash) if packet.hops-1 == announce_entry[4]+1 and announce_entry[2] > 0: now = time.time() if now < announce_entry[1]: - RNS.log("Rebroadcasted announce for "+RNS.prettyhexrep(packet.destination_hash)+" has been passed on to another node, no further tries needed", RNS.LOG_DEBUG) + RNS.log(f"Rebroadcasted announce for {RNS.prettyhexrep(packet.destination_hash)} has been passed on to another node, no further tries needed", RNS.LOG_DEBUG) Transport.announce_table.pop(packet.destination_hash) else: @@ -1458,7 +1458,7 @@ class Transport: if not random_blob in random_blobs: # TODO: Check that this ^ approach actually # works under all circumstances - RNS.log("Replacing destination table entry for "+str(RNS.prettyhexrep(packet.destination_hash))+" with new announce due to expired path", RNS.LOG_DEBUG) + RNS.log(f"Replacing destination table entry for {RNS.prettyhexrep(packet.destination_hash)} with new announce due to expired path", RNS.LOG_DEBUG) Transport.mark_path_unknown_state(packet.destination_hash) should_add = True else: @@ -1469,7 +1469,7 @@ class Transport: # this announce before, update the path table. if (announce_emitted > path_announce_emitted): if not random_blob in random_blobs: - RNS.log("Replacing destination table entry for "+str(RNS.prettyhexrep(packet.destination_hash))+" with new announce, since it was more recently emitted", RNS.LOG_DEBUG) + RNS.log(f"Replacing destination table entry for {RNS.prettyhexrep(packet.destination_hash)} with new announce, since it was more recently emitted", RNS.LOG_DEBUG) Transport.mark_path_unknown_state(packet.destination_hash) should_add = True else: @@ -1481,7 +1481,7 @@ class Transport: # allow updating the path table to this one. elif announce_emitted == path_announce_emitted: if Transport.path_is_unresponsive(packet.destination_hash): - RNS.log("Replacing destination table entry for "+str(RNS.prettyhexrep(packet.destination_hash))+" with new announce, since previously tried path was unresponsive", RNS.LOG_DEBUG) + RNS.log(f"Replacing destination table entry for {RNS.prettyhexrep(packet.destination_hash)} with new announce, since previously tried path was unresponsive", RNS.LOG_DEBUG) should_add = True else: should_add = False @@ -1551,7 +1551,7 @@ class Transport: # Insert announce into announce table for retransmission if rate_blocked: - RNS.log("Blocking rebroadcast of announce from "+RNS.prettyhexrep(packet.destination_hash)+" due to excessive announce rate", RNS.LOG_DEBUG) + RNS.log(f"Blocking rebroadcast of announce from {RNS.prettyhexrep(packet.destination_hash)} due to excessive announce rate", RNS.LOG_DEBUG) else: if Transport.from_local_client(packet): @@ -1648,9 +1648,9 @@ class Transport: pr_entry = Transport.discovery_path_requests[packet.destination_hash] attached_interface = pr_entry["requesting_interface"] - interface_str = " on "+str(attached_interface) + interface_str = f" on {attached_interface}" - RNS.log("Got matching announce, answering waiting discovery path request for "+RNS.prettyhexrep(packet.destination_hash)+interface_str, RNS.LOG_DEBUG) + RNS.log(f"Got matching announce, answering waiting discovery path request for {RNS.prettyhexrep(packet.destination_hash)}{interface_str}", RNS.LOG_DEBUG) announce_identity = RNS.Identity.recall(packet.destination_hash) announce_destination = RNS.Destination(announce_identity, RNS.Destination.OUT, RNS.Destination.SINGLE, "unknown", "unknown"); announce_destination.hash = packet.destination_hash @@ -1675,7 +1675,7 @@ class Transport: destination_table_entry = [now, received_from, announce_hops, expires, random_blobs, packet.receiving_interface, packet] Transport.destination_table[packet.destination_hash] = destination_table_entry - RNS.log("Destination "+RNS.prettyhexrep(packet.destination_hash)+" is now "+str(announce_hops)+" hops away via "+RNS.prettyhexrep(received_from)+" on "+str(packet.receiving_interface), RNS.LOG_DEBUG) + RNS.log(f"Destination {RNS.prettyhexrep(packet.destination_hash)} is now {announce_hops} hops away via {RNS.prettyhexrep(received_from)} on {packet.receiving_interface}", RNS.LOG_DEBUG) # If the receiving interface is a tunnel, we add the # announce to the tunnels table @@ -1685,7 +1685,7 @@ class Transport: paths[packet.destination_hash] = destination_table_entry expires = time.time() + Transport.DESTINATION_TIMEOUT tunnel_entry[3] = expires - RNS.log("Path to "+RNS.prettyhexrep(packet.destination_hash)+" associated with tunnel "+RNS.prettyhexrep(packet.receiving_interface.tunnel_id), RNS.LOG_DEBUG) + RNS.log(f"Path to {RNS.prettyhexrep(packet.destination_hash)} associated with tunnel {RNS.prettyhexrep(packet.receiving_interface.tunnel_id)}", RNS.LOG_DEBUG) # Call externally registered callbacks from apps # wanting to know when an announce arrives @@ -1720,7 +1720,7 @@ class Transport: ) except Exception as e: RNS.log("Error while processing external announce callback.", RNS.LOG_ERROR) - RNS.log("The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"The contained exception was: {e}", RNS.LOG_ERROR) RNS.trace_exception(e) # Handling for link requests to local destinations @@ -1773,7 +1773,7 @@ class Transport: if destination.callbacks.proof_requested(packet): packet.prove() except Exception as e: - RNS.log("Error while executing proof request callback. The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Error while executing proof request callback. The contained exception was: {e}", RNS.LOG_ERROR) # Handling for proofs and link-request proofs elif packet.packet_type == RNS.Packet.PROOF: @@ -1794,7 +1794,7 @@ class Transport: signature = packet.data[:RNS.Identity.SIGLENGTH//8] if peer_identity.validate(signature, signed_data): - RNS.log("Link request proof validated for transport via "+str(link_entry[4]), RNS.LOG_EXTREME) + RNS.log(f"Link request proof validated for transport via {link_entry[4]}", RNS.LOG_EXTREME) new_raw = packet.raw[0:1] new_raw += struct.pack("!B", packet.hops) new_raw += packet.raw[2:] @@ -1802,10 +1802,10 @@ class Transport: Transport.transmit(link_entry[4], new_raw) else: - RNS.log("Invalid link request proof in transport for link "+RNS.prettyhexrep(packet.destination_hash)+", dropping proof.", RNS.LOG_DEBUG) + RNS.log(f"Invalid link request proof in transport for link {RNS.prettyhexrep(packet.destination_hash)}, dropping proof.", RNS.LOG_DEBUG) except Exception as e: - RNS.log("Error while transporting link request proof. The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Error while transporting link request proof. The contained exception was: {e}", RNS.LOG_ERROR) else: RNS.log("Link request proof received on wrong interface, not transporting it.", RNS.LOG_DEBUG) @@ -1854,7 +1854,7 @@ class Transport: if (RNS.Reticulum.transport_enabled() or from_local_client or proof_for_local_client) and packet.destination_hash in Transport.reverse_table: reverse_entry = Transport.reverse_table.pop(packet.destination_hash) if packet.receiving_interface == reverse_entry[1]: - RNS.log("Proof received on correct interface, transporting it via "+str(reverse_entry[0]), RNS.LOG_EXTREME) + RNS.log(f"Proof received on correct interface, transporting it via {reverse_entry[0]}", RNS.LOG_EXTREME) new_raw = packet.raw[0:1] new_raw += struct.pack("!B", packet.hops) new_raw += packet.raw[2:] @@ -1922,19 +1922,19 @@ class Transport: except Exception as e: RNS.log("An error occurred while validating tunnel establishment packet.", RNS.LOG_DEBUG) - RNS.log("The contained exception was: "+str(e), RNS.LOG_DEBUG) + RNS.log(f"The contained exception was: {e}", RNS.LOG_DEBUG) @staticmethod def handle_tunnel(tunnel_id, interface): expires = time.time() + Transport.DESTINATION_TIMEOUT if not tunnel_id in Transport.tunnels: - RNS.log("Tunnel endpoint "+RNS.prettyhexrep(tunnel_id)+" established.", RNS.LOG_DEBUG) + RNS.log(f"Tunnel endpoint {RNS.prettyhexrep(tunnel_id)} established.", RNS.LOG_DEBUG) paths = {} tunnel_entry = [tunnel_id, interface, paths, expires] interface.tunnel_id = tunnel_id Transport.tunnels[tunnel_id] = tunnel_entry else: - RNS.log("Tunnel endpoint "+RNS.prettyhexrep(tunnel_id)+" reappeared. Restoring paths...", RNS.LOG_DEBUG) + RNS.log(f"Tunnel endpoint {RNS.prettyhexrep(tunnel_id)} reappeared. Restoring paths...", RNS.LOG_DEBUG) tunnel_entry = Transport.tunnels[tunnel_id] tunnel_entry[1] = interface tunnel_entry[3] = expires @@ -1959,21 +1959,21 @@ class Transport: if announce_hops <= old_hops or time.time() > old_expires: should_add = True else: - RNS.log("Did not restore path to "+RNS.prettyhexrep(packet.destination_hash)+" because a newer path with fewer hops exist", RNS.LOG_DEBUG) + RNS.log(f"Did not restore path to {RNS.prettyhexrep(packet.destination_hash)} because a newer path with fewer hops exist", RNS.LOG_DEBUG) else: if time.time() < expires: should_add = True else: - RNS.log("Did not restore path to "+RNS.prettyhexrep(packet.destination_hash)+" because it has expired", RNS.LOG_DEBUG) + RNS.log(f"Did not restore path to {RNS.prettyhexrep(packet.destination_hash)} because it has expired", RNS.LOG_DEBUG) if should_add: Transport.destination_table[destination_hash] = new_entry - RNS.log("Restored path to "+RNS.prettyhexrep(packet.destination_hash)+" is now "+str(announce_hops)+" hops away via "+RNS.prettyhexrep(received_from)+" on "+str(receiving_interface), RNS.LOG_DEBUG) + RNS.log(f"Restored path to {RNS.prettyhexrep(packet.destination_hash)} is now {announce_hops} hops away via {RNS.prettyhexrep(received_from)} on {receiving_interface}", RNS.LOG_DEBUG) else: deprecated_paths.append(destination_hash) for deprecated_path in deprecated_paths: - RNS.log("Removing path to "+RNS.prettyhexrep(deprecated_path)+" from tunnel "+RNS.prettyhexrep(tunnel_id), RNS.LOG_DEBUG) + RNS.log(f"Removing path to {RNS.prettyhexrep(deprecated_path)} from tunnel {RNS.prettyhexrep(tunnel_id)}", RNS.LOG_DEBUG) paths.pop(deprecated_path) @staticmethod @@ -1997,7 +1997,7 @@ class Transport: @staticmethod def register_link(link): - RNS.log("Registering link "+str(link), RNS.LOG_EXTREME) + RNS.log(f"Registering link {link}", RNS.LOG_EXTREME) if link.initiator: Transport.pending_links.append(link) else: @@ -2005,10 +2005,10 @@ class Transport: @staticmethod def activate_link(link): - RNS.log("Activating link "+str(link), RNS.LOG_EXTREME) + RNS.log(f"Activating link {link}", RNS.LOG_EXTREME) if link in Transport.pending_links: if link.status != RNS.Link.ACTIVE: - raise IOError("Invalid link state for link activation: "+str(link.status)) + raise OSError(f"Invalid link state for link activation: {link.status}") Transport.pending_links.remove(link) Transport.active_links.append(link) link.status = RNS.Link.ACTIVE @@ -2070,18 +2070,18 @@ class Transport: if packet.receiving_interface != None: interface_reference = str(packet.receiving_interface) - file = open(RNS.Reticulum.cachepath+"/"+packet_hash, "wb") + file = open(f"{RNS.Reticulum.cachepath}/{packet_hash}", "wb") file.write(umsgpack.packb([packet.raw, interface_reference])) file.close() except Exception as e: - RNS.log("Error writing packet to cache. The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Error writing packet to cache. The contained exception was: {e}", RNS.LOG_ERROR) @staticmethod def get_cached_packet(packet_hash): try: packet_hash = RNS.hexrep(packet_hash, delimit=False) - path = RNS.Reticulum.cachepath+"/"+packet_hash + path = f"{RNS.Reticulum.cachepath}/{packet_hash}" if os.path.isfile(path): file = open(path, "rb") @@ -2100,7 +2100,7 @@ class Transport: return None except Exception as e: RNS.log("Exception occurred while getting cached packet.", RNS.LOG_ERROR) - RNS.log("The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"The contained exception was: {e}", RNS.LOG_ERROR) @staticmethod def cache_request_packet(packet): @@ -2290,12 +2290,12 @@ class Transport: queued_announces = True if len(on_interface.announce_queue) > 0 else False if queued_announces: - RNS.log("Blocking recursive path request on "+str(on_interface)+" due to queued announces", RNS.LOG_EXTREME) + RNS.log(f"Blocking recursive path request on {on_interface} due to queued announces", RNS.LOG_EXTREME) return else: now = time.time() if now < on_interface.announce_allowed_at: - RNS.log("Blocking recursive path request on "+str(on_interface)+" due to active announce cap", RNS.LOG_EXTREME) + RNS.log(f"Blocking recursive path request on {on_interface} due to active announce cap", RNS.LOG_EXTREME) return else: tx_time = ((len(path_request_data)+RNS.Reticulum.HEADER_MINSIZE)*8) / on_interface.bitrate @@ -2319,8 +2319,8 @@ class Transport: return response except Exception as e: - RNS.log("An error occurred while processing remote status request from "+str(remote_identity), RNS.LOG_ERROR) - RNS.log("The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"An error occurred while processing remote status request from {remote_identity}", RNS.LOG_ERROR) + RNS.log(f"The contained exception was: {e}", RNS.LOG_ERROR) return None @@ -2355,8 +2355,8 @@ class Transport: return response except Exception as e: - RNS.log("An error occurred while processing remote status request from "+str(remote_identity), RNS.LOG_ERROR) - RNS.log("The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"An error occurred while processing remote status request from {remote_identity}", RNS.LOG_ERROR) + RNS.log(f"The contained exception was: {e}", RNS.LOG_ERROR) return None @@ -2402,13 +2402,13 @@ class Transport: ) else: - RNS.log("Ignoring duplicate path request for "+RNS.prettyhexrep(destination_hash)+" with tag "+RNS.prettyhexrep(unique_tag), RNS.LOG_DEBUG) + RNS.log(f"Ignoring duplicate path request for {RNS.prettyhexrep(destination_hash)} with tag {RNS.prettyhexrep(unique_tag)}", RNS.LOG_DEBUG) else: - RNS.log("Ignoring tagless path request for "+RNS.prettyhexrep(destination_hash), RNS.LOG_DEBUG) + RNS.log(f"Ignoring tagless path request for {RNS.prettyhexrep(destination_hash)}", RNS.LOG_DEBUG) except Exception as e: - RNS.log("Error while handling path request. The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Error while handling path request. The contained exception was: {e}", RNS.LOG_ERROR) @staticmethod def path_request(destination_hash, is_from_local_client, attached_interface, requestor_transport_id=None, tag=None): @@ -2418,11 +2418,11 @@ class Transport: if RNS.Reticulum.transport_enabled() and attached_interface.mode in RNS.Interfaces.Interface.Interface.DISCOVER_PATHS_FOR: should_search_for_unknown = True - interface_str = " on "+str(attached_interface) + interface_str = f" on {attached_interface}" else: interface_str = "" - RNS.log("Path request for "+RNS.prettyhexrep(destination_hash)+interface_str, RNS.LOG_DEBUG) + RNS.log(f"Path request for {RNS.prettyhexrep(destination_hash)}{interface_str}", RNS.LOG_DEBUG) destination_exists_on_local_client = False if len(Transport.local_client_interfaces) > 0: @@ -2436,7 +2436,7 @@ class Transport: local_destination = next((d for d in Transport.destinations if d.hash == destination_hash), None) if local_destination != None: local_destination.announce(path_response=True, tag=tag, attached_interface=attached_interface) - RNS.log("Answering path request for "+RNS.prettyhexrep(destination_hash)+interface_str+", destination is local to this system", RNS.LOG_DEBUG) + RNS.log(f"Answering path request for {RNS.prettyhexrep(destination_hash)}{interface_str}, destination is local to this system", RNS.LOG_DEBUG) elif (RNS.Reticulum.transport_enabled() or is_from_local_client) and (destination_hash in Transport.destination_table): packet = Transport.destination_table[destination_hash][6] @@ -2454,9 +2454,9 @@ class Transport: # inefficient. There is probably a better way. Doing # path invalidation here would decrease the network # convergence time. Maybe just drop it? - RNS.log("Not answering path request for "+RNS.prettyhexrep(destination_hash)+interface_str+", since next hop is the requestor", RNS.LOG_DEBUG) + RNS.log(f"Not answering path request for {RNS.prettyhexrep(destination_hash)}{interface_str}, since next hop is the requestor", RNS.LOG_DEBUG) else: - RNS.log("Answering path request for "+RNS.prettyhexrep(destination_hash)+interface_str+", path is known", RNS.LOG_DEBUG) + RNS.log(f"Answering path request for {RNS.prettyhexrep(destination_hash)}{interface_str}, path is known", RNS.LOG_DEBUG) now = time.time() retries = Transport.PATHFINDER_R @@ -2468,7 +2468,7 @@ class Transport: retransmit_timeout = now else: if Transport.is_local_client_interface(Transport.next_hop_interface(destination_hash)): - RNS.log("Path request destination "+RNS.prettyhexrep(destination_hash)+" is on a local client interface, rebroadcasting immediately", RNS.LOG_EXTREME) + RNS.log(f"Path request destination {RNS.prettyhexrep(destination_hash)} is on a local client interface, rebroadcasting immediately", RNS.LOG_EXTREME) retransmit_timeout = now else: @@ -2495,7 +2495,7 @@ class Transport: elif is_from_local_client: # Forward path request on all interfaces # except the local client - RNS.log("Forwarding path request from local client for "+RNS.prettyhexrep(destination_hash)+interface_str+" to all other interfaces", RNS.LOG_DEBUG) + RNS.log(f"Forwarding path request from local client for {RNS.prettyhexrep(destination_hash)}{interface_str} to all other interfaces", RNS.LOG_DEBUG) request_tag = RNS.Identity.get_random_hash() for interface in Transport.interfaces: if not interface == attached_interface: @@ -2503,11 +2503,11 @@ class Transport: elif should_search_for_unknown: if destination_hash in Transport.discovery_path_requests: - RNS.log("There is already a waiting path request for "+RNS.prettyhexrep(destination_hash)+" on behalf of path request"+interface_str, RNS.LOG_DEBUG) + RNS.log(f"There is already a waiting path request for {RNS.prettyhexrep(destination_hash)} on behalf of path request{interface_str}", RNS.LOG_DEBUG) else: # Forward path request on all interfaces # except the requestor interface - RNS.log("Attempting to discover unknown path to "+RNS.prettyhexrep(destination_hash)+" on behalf of path request"+interface_str, RNS.LOG_DEBUG) + RNS.log(f"Attempting to discover unknown path to {RNS.prettyhexrep(destination_hash)} on behalf of path request{interface_str}", RNS.LOG_DEBUG) pr_entry = { "destination_hash": destination_hash, "timeout": time.time()+Transport.PATH_REQUEST_TIMEOUT, "requesting_interface": attached_interface } Transport.discovery_path_requests[destination_hash] = pr_entry @@ -2520,12 +2520,12 @@ class Transport: elif not is_from_local_client and len(Transport.local_client_interfaces) > 0: # Forward the path request on all local # client interfaces - RNS.log("Forwarding path request for "+RNS.prettyhexrep(destination_hash)+interface_str+" to local clients", RNS.LOG_DEBUG) + RNS.log(f"Forwarding path request for {RNS.prettyhexrep(destination_hash)}{interface_str} to local clients", RNS.LOG_DEBUG) for interface in Transport.local_client_interfaces: Transport.request_path(destination_hash, on_interface=interface) else: - RNS.log("Ignoring path request for "+RNS.prettyhexrep(destination_hash)+interface_str+", no path known", RNS.LOG_DEBUG) + RNS.log(f"Ignoring path request for {RNS.prettyhexrep(destination_hash)}{interface_str}, no path known", RNS.LOG_DEBUG) @staticmethod def from_local_client(packet): @@ -2577,7 +2577,7 @@ class Transport: try: interface.detach() except Exception as e: - RNS.log("An error occurred while detaching "+str(interface)+". The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"An error occurred while detaching {interface}. The contained exception was: {e}", RNS.LOG_ERROR) @staticmethod def shared_connection_disappeared(): @@ -2613,10 +2613,10 @@ class Transport: if na == 1: na_str = "1 announce" else: - na_str = str(na)+" announces" + na_str = f"{na} announces" interface.announce_queue = [] - RNS.log("Dropped "+na_str+" on "+str(interface), RNS.LOG_VERBOSE) + RNS.log(f"Dropped {na_str} on {interface}", RNS.LOG_VERBOSE) @staticmethod @@ -2649,20 +2649,20 @@ class Transport: else: RNS.log("Saving packet hashlist to storage...", RNS.LOG_DEBUG) - packet_hashlist_path = RNS.Reticulum.storagepath+"/packet_hashlist" + packet_hashlist_path = f"{RNS.Reticulum.storagepath}/packet_hashlist" file = open(packet_hashlist_path, "wb") file.write(umsgpack.packb(Transport.packet_hashlist)) file.close() save_time = time.time() - save_start if save_time < 1: - time_str = str(round(save_time*1000,2))+"ms" + time_str = f"{round(save_time * 1000, 2)}ms" else: - time_str = str(round(save_time,2))+"s" - RNS.log("Saved packet hashlist in "+time_str, RNS.LOG_DEBUG) + time_str = f"{round(save_time, 2)}s" + RNS.log(f"Saved packet hashlist in {time_str}", RNS.LOG_DEBUG) except Exception as e: - RNS.log("Could not save packet hashlist to storage, the contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Could not save packet hashlist to storage, the contained exception was: {e}", RNS.LOG_ERROR) Transport.saving_packet_hashlist = False @@ -2719,20 +2719,20 @@ class Transport: Transport.cache(de[6], force_cache=True) - destination_table_path = RNS.Reticulum.storagepath+"/destination_table" + destination_table_path = f"{RNS.Reticulum.storagepath}/destination_table" file = open(destination_table_path, "wb") file.write(umsgpack.packb(serialised_destinations)) file.close() save_time = time.time() - save_start if save_time < 1: - time_str = str(round(save_time*1000,2))+"ms" + time_str = f"{round(save_time * 1000, 2)}ms" else: - time_str = str(round(save_time,2))+"s" - RNS.log("Saved "+str(len(serialised_destinations))+" path table entries in "+time_str, RNS.LOG_DEBUG) + time_str = f"{round(save_time, 2)}s" + RNS.log(f"Saved {len(serialised_destinations)} path table entries in {time_str}", RNS.LOG_DEBUG) except Exception as e: - RNS.log("Could not save path table to storage, the contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Could not save path table to storage, the contained exception was: {e}", RNS.LOG_ERROR) Transport.saving_path_table = False @@ -2797,19 +2797,19 @@ class Transport: serialised_tunnel = [tunnel_id, interface_hash, serialised_paths, expires] serialised_tunnels.append(serialised_tunnel) - tunnels_path = RNS.Reticulum.storagepath+"/tunnels" + tunnels_path = f"{RNS.Reticulum.storagepath}/tunnels" file = open(tunnels_path, "wb") file.write(umsgpack.packb(serialised_tunnels)) file.close() save_time = time.time() - save_start if save_time < 1: - time_str = str(round(save_time*1000,2))+"ms" + time_str = f"{round(save_time * 1000, 2)}ms" else: - time_str = str(round(save_time,2))+"s" - RNS.log("Saved "+str(len(serialised_tunnels))+" tunnel table entries in "+time_str, RNS.LOG_DEBUG) + time_str = f"{round(save_time, 2)}s" + RNS.log(f"Saved {len(serialised_tunnels)} tunnel table entries in {time_str}", RNS.LOG_DEBUG) except Exception as e: - RNS.log("Could not save tunnel table to storage, the contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Could not save tunnel table to storage, the contained exception was: {e}", RNS.LOG_ERROR) Transport.saving_tunnel_table = False diff --git a/RNS/Utilities/__init__.py b/RNS/Utilities/__init__.py index be84862..5fd7259 100644 --- a/RNS/Utilities/__init__.py +++ b/RNS/Utilities/__init__.py @@ -23,5 +23,5 @@ import os import glob -modules = glob.glob(os.path.dirname(__file__)+"/*.py") +modules = glob.glob(f"{os.path.dirname(__file__)}/*.py") __all__ = [ os.path.basename(f)[:-3] for f in modules if not f.endswith('__init__.py')] diff --git a/RNS/Utilities/rncp.py b/RNS/Utilities/rncp.py index a4c7a3e..601a667 100644 --- a/RNS/Utilities/rncp.py +++ b/RNS/Utilities/rncp.py @@ -59,7 +59,7 @@ def listen(configdir, verbosity = 0, quietness = 0, allowed = [], display_identi if jail != None: fetch_jail = os.path.abspath(os.path.expanduser(jail)) - RNS.log("Restricting fetch requests to paths under \""+fetch_jail+"\"", RNS.LOG_VERBOSE) + RNS.log(f"Restricting fetch requests to paths under \"{fetch_jail}\"", RNS.LOG_VERBOSE) if save != None: sp = os.path.abspath(os.path.expanduser(save)) @@ -73,9 +73,9 @@ def listen(configdir, verbosity = 0, quietness = 0, allowed = [], display_identi RNS.log("Output directory not found", RNS.LOG_ERROR) exit(3) - RNS.log("Saving received files in \""+save_path+"\"", RNS.LOG_VERBOSE) + RNS.log(f"Saving received files in \"{save_path}\"", RNS.LOG_VERBOSE) - identity_path = RNS.Reticulum.identitypath+"/"+APP_NAME + identity_path = f"{RNS.Reticulum.identitypath}/{APP_NAME}" if os.path.isfile(identity_path): identity = RNS.Identity.from_file(identity_path) @@ -87,8 +87,8 @@ def listen(configdir, verbosity = 0, quietness = 0, allowed = [], display_identi destination = RNS.Destination(identity, RNS.Destination.IN, RNS.Destination.SINGLE, APP_NAME, "receive") if display_identity: - print("Identity : "+str(identity)) - print("Listening on : "+RNS.prettyhexrep(destination.hash)) + print(f"Identity : {identity}") + print(f"Listening on : {RNS.prettyhexrep(destination.hash)}") exit(0) if disable_auth: @@ -98,14 +98,14 @@ def listen(configdir, verbosity = 0, quietness = 0, allowed = [], display_identi try: allowed_file_name = "allowed_identities" allowed_file = None - if os.path.isfile(os.path.expanduser("/etc/rncp/"+allowed_file_name)): - allowed_file = os.path.expanduser("/etc/rncp/"+allowed_file_name) - elif os.path.isfile(os.path.expanduser("~/.config/rncp/"+allowed_file_name)): - allowed_file = os.path.expanduser("~/.config/rncp/"+allowed_file_name) - elif os.path.isfile(os.path.expanduser("~/.rncp/"+allowed_file_name)): - allowed_file = os.path.expanduser("~/.rncp/"+allowed_file_name) + if os.path.isfile(os.path.expanduser(f"/etc/rncp/{allowed_file_name}")): + allowed_file = os.path.expanduser(f"/etc/rncp/{allowed_file_name}") + elif os.path.isfile(os.path.expanduser(f"~/.config/rncp/{allowed_file_name}")): + allowed_file = os.path.expanduser(f"~/.config/rncp/{allowed_file_name}") + elif os.path.isfile(os.path.expanduser(f"~/.rncp/{allowed_file_name}")): + allowed_file = os.path.expanduser(f"~/.rncp/{allowed_file_name}") if allowed_file != None: - af = open(allowed_file, "r") + af = open(allowed_file) al = af.read().replace("\r", "").split("\n") ali = [] for a in al: @@ -122,16 +122,16 @@ def listen(configdir, verbosity = 0, quietness = 0, allowed = [], display_identi else: ms = "ies" - RNS.log("Loaded "+str(len(ali))+" allowed identit"+ms+" from "+str(allowed_file), RNS.LOG_VERBOSE) + RNS.log(f"Loaded {len(ali)} allowed identit{ms} from {allowed_file}", RNS.LOG_VERBOSE) except Exception as e: - RNS.log("Error while parsing allowed_identities file. The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Error while parsing allowed_identities file. The contained exception was: {e}", RNS.LOG_ERROR) if allowed != None: for a in allowed: try: if len(a) != dest_len: - raise ValueError("Allowed destination length is invalid, must be {hex} hexadecimal characters ({byte} bytes).".format(hex=dest_len, byte=dest_len//2)) + raise ValueError(f"Allowed destination length is invalid, must be {dest_len} hexadecimal characters ({dest_len // 2} bytes).") try: destination_hash = bytes.fromhex(a) allowed_identity_hashes.append(destination_hash) @@ -165,11 +165,11 @@ def listen(configdir, verbosity = 0, quietness = 0, allowed = [], display_identi target_link = link if not os.path.isfile(file_path): - RNS.log("Client-requested file not found: "+str(file_path), RNS.LOG_VERBOSE) + RNS.log(f"Client-requested file not found: {file_path}", RNS.LOG_VERBOSE) return False else: if target_link != None: - RNS.log("Sending file "+str(file_path)+" to client", RNS.LOG_VERBOSE) + RNS.log(f"Sending file {file_path} to client", RNS.LOG_VERBOSE) temp_file = TemporaryFile() real_file = open(file_path, "rb") @@ -199,7 +199,7 @@ def listen(configdir, verbosity = 0, quietness = 0, allowed = [], display_identi else: destination.register_request_handler("fetch_file", response_generator=fetch_request, allow=RNS.Destination.ALLOW_LIST, allowed_list=allowed_identity_hashes) - print("rncp listening on "+RNS.prettyhexrep(destination.hash)) + print(f"rncp listening on {RNS.prettyhexrep(destination.hash)}") if announce >= 0: def job(): @@ -250,16 +250,16 @@ def receive_resource_callback(resource): def receive_resource_started(resource): if resource.link.get_remote_identity(): - id_str = " from "+RNS.prettyhexrep(resource.link.get_remote_identity().hash) + id_str = f" from {RNS.prettyhexrep(resource.link.get_remote_identity().hash)}" else: id_str = "" - print("Starting resource transfer "+RNS.prettyhexrep(resource.hash)+id_str) + print(f"Starting resource transfer {RNS.prettyhexrep(resource.hash)}{id_str}") def receive_resource_concluded(resource): global save_path if resource.status == RNS.Resource.COMPLETE: - print(str(resource)+" completed") + print(f"{resource} completed") if resource.total_size > 4: filename_len = int.from_bytes(resource.data.read(2), "big") @@ -277,7 +277,7 @@ def receive_resource_concluded(resource): full_save_path = saved_filename while os.path.isfile(full_save_path): counter += 1 - full_save_path = saved_filename+"."+str(counter) + full_save_path = f"{saved_filename}.{counter}" file = open(full_save_path, "wb") file.write(resource.data.read()) @@ -348,7 +348,7 @@ def fetch(configdir, verbosity = 0, quietness = 0, destination = None, file = No try: dest_len = (RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2 if len(destination) != dest_len: - raise ValueError("Allowed destination length is invalid, must be {hex} hexadecimal characters ({byte} bytes).".format(hex=dest_len, byte=dest_len//2)) + raise ValueError(f"Allowed destination length is invalid, must be {dest_len} hexadecimal characters ({dest_len // 2} bytes).") try: destination_hash = bytes.fromhex(destination) except Exception as e: @@ -359,11 +359,11 @@ def fetch(configdir, verbosity = 0, quietness = 0, destination = None, file = No reticulum = RNS.Reticulum(configdir=configdir, loglevel=targetloglevel) - identity_path = RNS.Reticulum.identitypath+"/"+APP_NAME + identity_path = f"{RNS.Reticulum.identitypath}/{APP_NAME}" if os.path.isfile(identity_path): identity = RNS.Identity.from_file(identity_path) if identity == None: - RNS.log("Could not load identity for rncp. The identity file at \""+str(identity_path)+"\" may be corrupt or unreadable.", RNS.LOG_ERROR) + RNS.log(f"Could not load identity for rncp. The identity file at \"{identity_path}\" may be corrupt or unreadable.", RNS.LOG_ERROR) exit(2) else: identity = None @@ -376,9 +376,9 @@ def fetch(configdir, verbosity = 0, quietness = 0, destination = None, file = No if not RNS.Transport.has_path(destination_hash): RNS.Transport.request_path(destination_hash) if silent: - print("Path to "+RNS.prettyhexrep(destination_hash)+" requested") + print(f"Path to {RNS.prettyhexrep(destination_hash)} requested") else: - print("Path to "+RNS.prettyhexrep(destination_hash)+" requested ", end=es) + print(f"Path to {RNS.prettyhexrep(destination_hash)} requested ", end=es) sys.stdout.flush() i = 0 @@ -387,7 +387,7 @@ def fetch(configdir, verbosity = 0, quietness = 0, destination = None, file = No while not RNS.Transport.has_path(destination_hash) and time.time() < estab_timeout: if not silent: time.sleep(0.1) - print(("\b\b"+syms[i]+" "), end="") + print(f"\b\b{syms[i]} ", end="") sys.stdout.flush() i = (i+1)%len(syms) @@ -399,9 +399,9 @@ def fetch(configdir, verbosity = 0, quietness = 0, destination = None, file = No exit(1) else: if silent: - print("Establishing link with "+RNS.prettyhexrep(destination_hash)) + print(f"Establishing link with {RNS.prettyhexrep(destination_hash)}") else: - print(f"{erase_str}Establishing link with "+RNS.prettyhexrep(destination_hash)+" ", end=es) + print(f"{erase_str}Establishing link with {RNS.prettyhexrep(destination_hash)} ", end=es) listener_identity = RNS.Identity.recall(destination_hash) listener_destination = RNS.Destination( @@ -416,15 +416,15 @@ def fetch(configdir, verbosity = 0, quietness = 0, destination = None, file = No while link.status != RNS.Link.ACTIVE and time.time() < estab_timeout: if not silent: time.sleep(0.1) - print(("\b\b"+syms[i]+" "), end="") + print(f"\b\b{syms[i]} ", end="") sys.stdout.flush() i = (i+1)%len(syms) if not RNS.Transport.has_path(destination_hash): if silent: - print("Could not establish link with "+RNS.prettyhexrep(destination_hash)) + print(f"Could not establish link with {RNS.prettyhexrep(destination_hash)}") else: - print(f"{erase_str}Could not establish link with "+RNS.prettyhexrep(destination_hash)) + print(f"{erase_str}Could not establish link with {RNS.prettyhexrep(destination_hash)}") exit(1) else: if silent: @@ -481,8 +481,8 @@ def fetch(configdir, verbosity = 0, quietness = 0, destination = None, file = No full_save_path = saved_filename while os.path.isfile(full_save_path): counter += 1 - full_save_path = saved_filename+"."+str(counter) - + full_save_path = f"{saved_filename}.{counter)" + file = open(full_save_path, "wb") file.write(resource.data.read()) file.close() @@ -507,19 +507,19 @@ def fetch(configdir, verbosity = 0, quietness = 0, destination = None, file = No while not request_resolved: if not silent: time.sleep(0.1) - print(("\b\b"+syms[i]+" "), end="") + print(f"\b\b{syms[i]} ", end="") sys.stdout.flush() i = (i+1)%len(syms) if request_status == "fetch_not_allowed": if not silent: print(f"{erase_str}", end="") - print("Fetch request failed, fetching the file "+str(file)+" was not allowed by the remote") + print(f"Fetch request failed, fetching the file {file} was not allowed by the remote") link.teardown() time.sleep(0.15) exit(0) elif request_status == "not_found": if not silent: print(f"{erase_str}", end="") - print("Fetch request failed, the file "+str(file)+" was not found on the remote") + print(f"Fetch request failed, the file {file} was not found on the remote") link.teardown() time.sleep(0.15) exit(0) @@ -570,9 +570,9 @@ def fetch(configdir, verbosity = 0, quietness = 0, destination = None, file = No exit(1) else: if silent: - print(str(file)+" fetched from "+RNS.prettyhexrep(destination_hash)) + print(f"{file} fetched from {RNS.prettyhexrep(destination_hash)}") else: - print("\n"+str(file)+" fetched from "+RNS.prettyhexrep(destination_hash)) + print(f"\n{file} fetched from {RNS.prettyhexrep(destination_hash)}") link.teardown() time.sleep(0.15) exit(0) @@ -590,7 +590,7 @@ def send(configdir, verbosity = 0, quietness = 0, destination = None, file = Non try: dest_len = (RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2 if len(destination) != dest_len: - raise ValueError("Allowed destination length is invalid, must be {hex} hexadecimal characters ({byte} bytes).".format(hex=dest_len, byte=dest_len//2)) + raise ValueError(f"Allowed destination length is invalid, must be {dest_len} hexadecimal characters ({dest_len // 2} bytes).") try: destination_hash = bytes.fromhex(destination) except Exception as e: @@ -625,11 +625,11 @@ def send(configdir, verbosity = 0, quietness = 0, destination = None, file = Non reticulum = RNS.Reticulum(configdir=configdir, loglevel=targetloglevel) - identity_path = RNS.Reticulum.identitypath+"/"+APP_NAME + identity_path = f"{RNS.Reticulum.identitypath}/{APP_NAME}" if os.path.isfile(identity_path): identity = RNS.Identity.from_file(identity_path) if identity == None: - RNS.log("Could not load identity for rncp. The identity file at \""+str(identity_path)+"\" may be corrupt or unreadable.", RNS.LOG_ERROR) + RNS.log(f"Could not load identity for rncp. The identity file at \"{identity_path}\" may be corrupt or unreadable.", RNS.LOG_ERROR) exit(2) else: identity = None @@ -642,9 +642,9 @@ def send(configdir, verbosity = 0, quietness = 0, destination = None, file = Non if not RNS.Transport.has_path(destination_hash): RNS.Transport.request_path(destination_hash) if silent: - print("Path to "+RNS.prettyhexrep(destination_hash)+" requested") + print(f"Path to {RNS.prettyhexrep(destination_hash)} requested") else: - print("Path to "+RNS.prettyhexrep(destination_hash)+" requested ", end=es) + print(f"Path to {RNS.prettyhexrep(destination_hash)} requested ", end=es) sys.stdout.flush() i = 0 @@ -653,7 +653,7 @@ def send(configdir, verbosity = 0, quietness = 0, destination = None, file = Non while not RNS.Transport.has_path(destination_hash) and time.time() < estab_timeout: if not silent: time.sleep(0.1) - print(("\b\b"+syms[i]+" "), end="") + print(f"\b\b{syms[i]} ", end="") sys.stdout.flush() i = (i+1)%len(syms) @@ -665,9 +665,9 @@ def send(configdir, verbosity = 0, quietness = 0, destination = None, file = Non exit(1) else: if silent: - print("Establishing link with "+RNS.prettyhexrep(destination_hash)) + print(f"Establishing link with {RNS.prettyhexrep(destination_hash)}") else: - print(f"{erase_str}Establishing link with "+RNS.prettyhexrep(destination_hash)+" ", end=es) + print(f"{erase_str}Establishing link with {RNS.prettyhexrep(destination_hash)} ", end=es) receiver_identity = RNS.Identity.recall(destination_hash) receiver_destination = RNS.Destination( @@ -682,21 +682,21 @@ def send(configdir, verbosity = 0, quietness = 0, destination = None, file = Non while link.status != RNS.Link.ACTIVE and time.time() < estab_timeout: if not silent: time.sleep(0.1) - print(("\b\b"+syms[i]+" "), end="") + print(f"\b\b{syms[i]} ", end="") sys.stdout.flush() i = (i+1)%len(syms) if time.time() > estab_timeout: if silent: - print("Link establishment with "+RNS.prettyhexrep(destination_hash)+" timed out") + print(f"Link establishment with {RNS.prettyhexrep(destination_hash)} timed out") else: - print(f"{erase_str}Link establishment with "+RNS.prettyhexrep(destination_hash)+" timed out") + print(f"{erase_str}Link establishment with {RNS.prettyhexrep(destination_hash)} timed out") exit(1) elif not RNS.Transport.has_path(destination_hash): if silent: - print("No path found to "+RNS.prettyhexrep(destination_hash)) + print(f"No path found to {RNS.prettyhexrep(destination_hash)}") else: - print(f"{erase_str}No path found to "+RNS.prettyhexrep(destination_hash)) + print(f"{erase_str}No path found to {RNS.prettyhexrep(destination_hash)}") exit(1) else: if silent: @@ -711,16 +711,16 @@ def send(configdir, verbosity = 0, quietness = 0, destination = None, file = Non while resource.status < RNS.Resource.TRANSFERRING: if not silent: time.sleep(0.1) - print(("\b\b"+syms[i]+" "), end="") + print(f"\b\b{syms[i]} ", end="") sys.stdout.flush() i = (i+1)%len(syms) if resource.status > RNS.Resource.COMPLETE: if silent: - print("File was not accepted by "+RNS.prettyhexrep(destination_hash)) + print(f"File was not accepted by {RNS.prettyhexrep(destination_hash)}") else: - print(f"{erase_str}File was not accepted by "+RNS.prettyhexrep(destination_hash)) + print(f"{erase_str}File was not accepted by {RNS.prettyhexrep(destination_hash)}") exit(1) else: if silent: @@ -743,9 +743,9 @@ def send(configdir, verbosity = 0, quietness = 0, destination = None, file = Non ss = size_str(speed, "b") stat_str = f"{percent}% - {cs} of {ts} - {ss}ps{phy_str}" if not done: - print(f"{erase_str}Transferring file "+syms[i]+" "+stat_str, end=es) + print(f"{erase_str}Transferring file {syms[i]} {stat_str}", end=es) else: - print(f"{erase_str}Transfer complete "+stat_str, end=es) + print(f"{erase_str}Transfer complete {stat_str}", end=es) sys.stdout.flush() i = (i+1)%len(syms) return i @@ -765,9 +765,9 @@ def send(configdir, verbosity = 0, quietness = 0, destination = None, file = Non exit(1) else: if silent: - print(str(file_path)+" copied to "+RNS.prettyhexrep(destination_hash)) + print(f"{file_path} copied to {RNS.prettyhexrep(destination_hash)}") else: - print("\n"+str(file_path)+" copied to "+RNS.prettyhexrep(destination_hash)) + print(f"\n{file_path} copied to {RNS.prettyhexrep(destination_hash)}") link.teardown() time.sleep(0.25) real_file.close() @@ -795,7 +795,7 @@ def main(): parser.add_argument("-w", action="store", metavar="seconds", type=float, help="sender timeout before giving up", default=RNS.Transport.PATH_REQUEST_TIMEOUT) parser.add_argument('-P', '--phy-rates', action='store_true', default=False, help="display physical layer transfer rates") # parser.add_argument("--limit", action="store", metavar="files", type=float, help="maximum number of files to accept", default=None) - parser.add_argument("--version", action="version", version="rncp {version}".format(version=__version__)) + parser.add_argument("--version", action="version", version=f"rncp {__version__}") args = parser.parse_args() @@ -869,12 +869,12 @@ def size_str(num, suffix='B'): for unit in units: if abs(num) < 1000.0: if unit == "": - return "%.0f %s%s" % (num, unit, suffix) + return f"{num:.0f} {unit}{suffix}" else: - return "%.2f %s%s" % (num, unit, suffix) + return f"{num:.2f} {unit}{suffix}" num /= 1000.0 - return "%.2f%s%s" % (num, last_unit, suffix) + return f"{num:.2f}{last_unit}{suffix}" if __name__ == "__main__": main() diff --git a/RNS/Utilities/rnid.py b/RNS/Utilities/rnid.py index 97de3e0..211f81b 100644 --- a/RNS/Utilities/rnid.py +++ b/RNS/Utilities/rnid.py @@ -43,14 +43,14 @@ def spin(until=None, msg=None, timeout=None): if timeout != None: timeout = time.time()+timeout - print(msg+" ", end=" ") + print(f"{msg} ", end=" ") while (timeout == None or time.time() timeout: return False @@ -92,7 +92,7 @@ def main(): parser.add_argument("-b", "--base64", action="store_true", default=False, help="Use base64-encoded input and output") parser.add_argument("-B", "--base32", action="store_true", default=False, help="Use base32-encoded input and output") - parser.add_argument("--version", action="version", version="rnid {version}".format(version=__version__)) + parser.add_argument("--version", action="version", version=f"rnid {__version__}") args = parser.parse_args() @@ -124,30 +124,30 @@ def main(): else: identity_bytes = bytes.fromhex(args.import_str) except Exception as e: - print("Invalid identity data specified for import: "+str(e)) + print(f"Invalid identity data specified for import: {e}") exit(41) try: identity = RNS.Identity.from_bytes(identity_bytes) except Exception as e: - print("Could not create Reticulum identity from specified data: "+str(e)) + print(f"Could not create Reticulum identity from specified data: {e}") exit(42) RNS.log("Identity imported") if args.base64: - RNS.log("Public Key : "+base64.urlsafe_b64encode(identity.get_public_key()).decode("utf-8")) + RNS.log(f"Public Key : {base64.urlsafe_b64encode(identity.get_public_key()).decode('utf-8')}") elif args.base32: - RNS.log("Public Key : "+base64.b32encode(identity.get_public_key()).decode("utf-8")) + RNS.log(f"Public Key : {base64.b32encode(identity.get_public_key()).decode('utf-8')}") else: - RNS.log("Public Key : "+RNS.hexrep(identity.get_public_key(), delimit=False)) + RNS.log(f"Public Key : {RNS.hexrep(identity.get_public_key(), delimit=False)}") if identity.prv: if args.print_private: if args.base64: - RNS.log("Private Key : "+base64.urlsafe_b64encode(identity.get_private_key()).decode("utf-8")) + RNS.log(f"Private Key : {base64.urlsafe_b64encode(identity.get_private_key()).decode('utf-8')}") elif args.base32: - RNS.log("Private Key : "+base64.b32encode(identity.get_private_key()).decode("utf-8")) + RNS.log(f"Private Key : {base64.b32encode(identity.get_private_key()).decode('utf-8')}") else: - RNS.log("Private Key : "+RNS.hexrep(identity.get_private_key(), delimit=False)) + RNS.log(f"Private Key : {RNS.hexrep(identity.get_private_key(), delimit=False)}") else: RNS.log("Private Key : Hidden") @@ -156,13 +156,13 @@ def main(): wp = os.path.expanduser(args.write) if not os.path.isfile(wp) or args.force: identity.to_file(wp) - RNS.log("Wrote imported identity to "+str(args.write)) + RNS.log(f"Wrote imported identity to {args.write}") else: - print("File "+str(wp)+" already exists, not overwriting") + print(f"File {wp} already exists, not overwriting") exit(43) except Exception as e: - print("Error while writing imported identity to file: "+str(e)) + print(f"Error while writing imported identity to file: {e}") exit(44) exit(0) @@ -189,16 +189,16 @@ def main(): if args.generate: identity = RNS.Identity() if not args.force and os.path.isfile(args.generate): - RNS.log("Identity file "+str(args.generate)+" already exists. Not overwriting.", RNS.LOG_ERROR) + RNS.log(f"Identity file {args.generate} already exists. Not overwriting.", RNS.LOG_ERROR) exit(3) else: try: identity.to_file(args.generate) - RNS.log("New identity written to "+str(args.generate)) + RNS.log(f"New identity written to {args.generate}") exit(0) except Exception as e: RNS.log("An error ocurred while saving the generated Identity.", RNS.LOG_ERROR) - RNS.log("The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"The contained exception was: {e}", RNS.LOG_ERROR) exit(4) identity = None @@ -210,24 +210,24 @@ def main(): if identity == None: if not args.request: - RNS.log("Could not recall Identity for "+RNS.prettyhexrep(destination_hash)+".", RNS.LOG_ERROR) + RNS.log(f"Could not recall Identity for {RNS.prettyhexrep(destination_hash)}.", RNS.LOG_ERROR) RNS.log("You can query the network for unknown Identities with the -R option.", RNS.LOG_ERROR) exit(5) else: RNS.Transport.request_path(destination_hash) def spincheck(): return RNS.Identity.recall(destination_hash) != None - spin(spincheck, "Requesting unknown Identity for "+RNS.prettyhexrep(destination_hash), args.t) + spin(spincheck, f"Requesting unknown Identity for {RNS.prettyhexrep(destination_hash)}", args.t) if not spincheck(): RNS.log("Identity request timed out", RNS.LOG_ERROR) exit(6) else: identity = RNS.Identity.recall(destination_hash) - RNS.log("Received Identity "+str(identity)+" for destination "+RNS.prettyhexrep(destination_hash)+" from the network") + RNS.log(f"Received Identity {identity} for destination {RNS.prettyhexrep(destination_hash)} from the network") else: - RNS.log("Recalled Identity "+str(identity)+" for destination "+RNS.prettyhexrep(destination_hash)) + RNS.log(f"Recalled Identity {identity} for destination {RNS.prettyhexrep(destination_hash)}") except Exception as e: @@ -243,7 +243,7 @@ def main(): else: try: identity = RNS.Identity.from_file(identity_str) - RNS.log("Loaded Identity "+str(identity)+" from "+str(identity_str)) + RNS.log(f"Loaded Identity {identity} from {identity_str}") except Exception as e: RNS.log("Could not decode Identity from specified file") @@ -261,15 +261,15 @@ def main(): aspects = aspects[1:] if identity.pub != None: destination = RNS.Destination(identity, RNS.Destination.OUT, RNS.Destination.SINGLE, app_name, *aspects) - RNS.log("The "+str(args.hash)+" destination for this Identity is "+RNS.prettyhexrep(destination.hash)) - RNS.log("The full destination specifier is "+str(destination)) + RNS.log(f"The {args.hash} destination for this Identity is {RNS.prettyhexrep(destination.hash)}") + RNS.log(f"The full destination specifier is {destination}") time.sleep(0.25) exit(0) else: raise KeyError("No public key known") except Exception as e: RNS.log("An error ocurred while attempting to send the announce.", RNS.LOG_ERROR) - RNS.log("The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"The contained exception was: {e}", RNS.LOG_ERROR) exit(0) @@ -284,39 +284,39 @@ def main(): aspects = aspects[1:] if identity.prv != None: destination = RNS.Destination(identity, RNS.Destination.IN, RNS.Destination.SINGLE, app_name, *aspects) - RNS.log("Created destination "+str(destination)) - RNS.log("Announcing destination "+RNS.prettyhexrep(destination.hash)) + RNS.log(f"Created destination {destination}") + RNS.log(f"Announcing destination {RNS.prettyhexrep(destination.hash)}") destination.announce() time.sleep(0.25) exit(0) else: destination = RNS.Destination(identity, RNS.Destination.OUT, RNS.Destination.SINGLE, app_name, *aspects) - RNS.log("The "+str(args.announce)+" destination for this Identity is "+RNS.prettyhexrep(destination.hash)) - RNS.log("The full destination specifier is "+str(destination)) + RNS.log(f"The {args.announce} destination for this Identity is {RNS.prettyhexrep(destination.hash)}") + RNS.log(f"The full destination specifier is {destination}") RNS.log("Cannot announce this destination, since the private key is not held") time.sleep(0.25) exit(33) except Exception as e: RNS.log("An error ocurred while attempting to send the announce.", RNS.LOG_ERROR) - RNS.log("The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"The contained exception was: {e}", RNS.LOG_ERROR) exit(0) if args.print_identity: if args.base64: - RNS.log("Public Key : "+base64.urlsafe_b64encode(identity.get_public_key()).decode("utf-8")) + RNS.log(f"Public Key : {base64.urlsafe_b64encode(identity.get_public_key()).decode('utf-8')}") elif args.base32: - RNS.log("Public Key : "+base64.b32encode(identity.get_public_key()).decode("utf-8")) + RNS.log(f"Public Key : {base64.b32encode(identity.get_public_key()).decode('utf-8')}") else: - RNS.log("Public Key : "+RNS.hexrep(identity.get_public_key(), delimit=False)) + RNS.log(f"Public Key : {RNS.hexrep(identity.get_public_key(), delimit=False)}") if identity.prv: if args.print_private: if args.base64: - RNS.log("Private Key : "+base64.urlsafe_b64encode(identity.get_private_key()).decode("utf-8")) + RNS.log(f"Private Key : {base64.urlsafe_b64encode(identity.get_private_key()).decode('utf-8')}") elif args.base32: - RNS.log("Private Key : "+base64.b32encode(identity.get_private_key()).decode("utf-8")) + RNS.log(f"Private Key : {base64.b32encode(identity.get_private_key()).decode('utf-8')}") else: - RNS.log("Private Key : "+RNS.hexrep(identity.get_private_key(), delimit=False)) + RNS.log(f"Private Key : {RNS.hexrep(identity.get_private_key(), delimit=False)}") else: RNS.log("Private Key : Hidden") exit(0) @@ -324,11 +324,11 @@ def main(): if args.export: if identity.prv: if args.base64: - RNS.log("Exported Identity : "+base64.urlsafe_b64encode(identity.get_private_key()).decode("utf-8")) + RNS.log(f"Exported Identity : {base64.urlsafe_b64encode(identity.get_private_key()).decode('utf-8')}") elif args.base32: - RNS.log("Exported Identity : "+base64.b32encode(identity.get_private_key()).decode("utf-8")) + RNS.log(f"Exported Identity : {base64.b32encode(identity.get_private_key()).decode('utf-8')}") else: - RNS.log("Exported Identity : "+RNS.hexrep(identity.get_private_key(), delimit=False)) + RNS.log(f"Exported Identity : {RNS.hexrep(identity.get_private_key(), delimit=False)}") else: RNS.log("Identity doesn't hold a private key, cannot export") exit(50) @@ -336,28 +336,28 @@ def main(): exit(0) if args.validate: - if not args.read and args.validate.lower().endswith("."+SIG_EXT): - args.read = str(args.validate).replace("."+SIG_EXT, "") + if not args.read and args.validate.lower().endswith(f".{SIG_EXT}"): + args.read = str(args.validate).replace(f".{SIG_EXT}", "") if not os.path.isfile(args.validate): - RNS.log("Signature file "+str(args.read)+" not found", RNS.LOG_ERROR) + RNS.log(f"Signature file {args.read} not found", RNS.LOG_ERROR) exit(10) if not os.path.isfile(args.read): - RNS.log("Input file "+str(args.read)+" not found", RNS.LOG_ERROR) + RNS.log(f"Input file {args.read} not found", RNS.LOG_ERROR) exit(11) data_input = None if args.read: if not os.path.isfile(args.read): - RNS.log("Input file "+str(args.read)+" not found", RNS.LOG_ERROR) + RNS.log(f"Input file {args.read} not found", RNS.LOG_ERROR) exit(12) else: try: data_input = open(args.read, "rb") except Exception as e: RNS.log("Could not open input file for reading", RNS.LOG_ERROR) - RNS.log("The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"The contained exception was: {e}", RNS.LOG_ERROR) exit(13) # TODO: Actually expand this to a good solution @@ -368,28 +368,28 @@ def main(): data_output = None if args.encrypt and not args.write and not args.stdout and args.read: - args.write = str(args.read)+"."+ENCRYPT_EXT + args.write = f"{args.read}.{ENCRYPT_EXT}" - if args.decrypt and not args.write and not args.stdout and args.read and args.read.lower().endswith("."+ENCRYPT_EXT): - args.write = str(args.read).replace("."+ENCRYPT_EXT, "") + if args.decrypt and not args.write and not args.stdout and args.read and args.read.lower().endswith(f".{ENCRYPT_EXT}"): + args.write = str(args.read).replace(f".{ENCRYPT_EXT}", "") if args.sign and identity.prv == None: RNS.log("Specified Identity does not hold a private key. Cannot sign.", RNS.LOG_ERROR) exit(14) if args.sign and not args.write and not args.stdout and args.read: - args.write = str(args.read)+"."+SIG_EXT + args.write = f"{args.read}.{SIG_EXT}" if args.write: if not args.force and os.path.isfile(args.write): - RNS.log("Output file "+str(args.write)+" already exists. Not overwriting.", RNS.LOG_ERROR) + RNS.log(f"Output file {args.write} already exists. Not overwriting.", RNS.LOG_ERROR) exit(15) else: try: data_output = open(args.write, "wb") except Exception as e: RNS.log("Could not open output file for writing", RNS.LOG_ERROR) - RNS.log("The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"The contained exception was: {e}", RNS.LOG_ERROR) exit(15) # TODO: Actually expand this to a good solution @@ -414,7 +414,7 @@ def main(): exit(18) if not args.stdout: - RNS.log("Signing "+str(args.read)) + RNS.log(f"Signing {args.read}") try: data_output.write(identity.sign(data_input.read())) @@ -423,13 +423,13 @@ def main(): if not args.stdout: if args.read: - RNS.log("File "+str(args.read)+" signed with "+str(identity)+" to "+str(args.write)) + RNS.log(f"File {args.read} signed with {identity} to {args.write}") exit(0) except Exception as e: if not args.stdout: RNS.log("An error ocurred while encrypting data.", RNS.LOG_ERROR) - RNS.log("The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"The contained exception was: {e}", RNS.LOG_ERROR) try: data_output.close() except: @@ -453,8 +453,8 @@ def main(): try: sig_input = open(args.validate, "rb") except Exception as e: - RNS.log("An error ocurred while opening "+str(args.validate)+".", RNS.LOG_ERROR) - RNS.log("The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"An error ocurred while opening {args.validate}.", RNS.LOG_ERROR) + RNS.log(f"The contained exception was: {e}", RNS.LOG_ERROR) exit(21) @@ -464,17 +464,17 @@ def main(): if not validated: if not args.stdout: - RNS.log("Signature "+str(args.validate)+" for file "+str(args.read)+" is invalid", RNS.LOG_ERROR) + RNS.log(f"Signature {args.validate} for file {args.read} is invalid", RNS.LOG_ERROR) exit(22) else: if not args.stdout: - RNS.log("Signature "+str(args.validate)+" for file "+str(args.read)+" made by Identity "+str(identity)+" is valid") + RNS.log(f"Signature {args.validate} for file {args.read} made by Identity {identity} is valid") exit(0) except Exception as e: if not args.stdout: RNS.log("An error ocurred while validating signature.", RNS.LOG_ERROR) - RNS.log("The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"The contained exception was: {e}", RNS.LOG_ERROR) try: data_output.close() except: @@ -497,7 +497,7 @@ def main(): exit(25) if not args.stdout: - RNS.log("Encrypting "+str(args.read)) + RNS.log(f"Encrypting {args.read}") try: more_data = True @@ -511,13 +511,13 @@ def main(): data_input.close() if not args.stdout: if args.read: - RNS.log("File "+str(args.read)+" encrypted for "+str(identity)+" to "+str(args.write)) + RNS.log(f"File {args.read} encrypted for {identity} to {args.write}") exit(0) except Exception as e: if not args.stdout: RNS.log("An error ocurred while encrypting data.", RNS.LOG_ERROR) - RNS.log("The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"The contained exception was: {e}", RNS.LOG_ERROR) try: data_output.close() except: @@ -544,7 +544,7 @@ def main(): exit(29) if not args.stdout: - RNS.log("Decrypting "+str(args.read)+"...") + RNS.log(f"Decrypting {args.read}...") try: more_data = True @@ -564,13 +564,13 @@ def main(): data_input.close() if not args.stdout: if args.read: - RNS.log("File "+str(args.read)+" decrypted with "+str(identity)+" to "+str(args.write)) + RNS.log(f"File {args.read} decrypted with {identity} to {args.write}") exit(0) except Exception as e: if not args.stdout: RNS.log("An error ocurred while decrypting data.", RNS.LOG_ERROR) - RNS.log("The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"The contained exception was: {e}", RNS.LOG_ERROR) try: data_output.close() except: diff --git a/RNS/Utilities/rnir.py b/RNS/Utilities/rnir.py index 0e4bf9e..01c74da 100644 --- a/RNS/Utilities/rnir.py +++ b/RNS/Utilities/rnir.py @@ -48,7 +48,7 @@ def main(): parser.add_argument('-v', '--verbose', action='count', default=0) parser.add_argument('-q', '--quiet', action='count', default=0) parser.add_argument("--exampleconfig", action='store_true', default=False, help="print verbose configuration example to stdout and exit") - parser.add_argument("--version", action="version", version="ir {version}".format(version=__version__)) + parser.add_argument("--version", action="version", version=f"ir {__version__}") args = parser.parse_args() diff --git a/RNS/Utilities/rnodeconf.py b/RNS/Utilities/rnodeconf.py index 7e99c78..fc4601d 100755 --- a/RNS/Utilities/rnodeconf.py +++ b/RNS/Utilities/rnodeconf.py @@ -492,7 +492,7 @@ class RNode(): command_buffer = command_buffer+bytes([byte]) if (len(command_buffer) == 4): self.r_bt_pin = command_buffer[0] << 24 | command_buffer[1] << 16 | command_buffer[2] << 8 | command_buffer[3] - RNS.log("Bluetooth pairing PIN is: {:06d}".format(self.r_bt_pin)) + RNS.log(f"Bluetooth pairing PIN is: {self.r_bt_pin:06d}") elif (command == KISS.CMD_DEV_HASH): if (byte == KISS.FESC): @@ -642,13 +642,13 @@ class RNode(): kiss_command = bytes([KISS.FEND, KISS.CMD_DETECT, KISS.DETECT_REQ, KISS.FEND, KISS.CMD_FW_VERSION, 0x00, KISS.FEND, KISS.CMD_PLATFORM, 0x00, KISS.FEND, KISS.CMD_MCU, 0x00, KISS.FEND, KISS.CMD_BOARD, 0x00, KISS.FEND, KISS.CMD_DEV_HASH, 0x01, KISS.FEND, KISS.CMD_HASHES, 0x01, KISS.FEND, KISS.CMD_HASHES, 0x02, KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while detecting hardware for "+self(str)) + raise OSError("An IO error occurred while detecting hardware for "+self(str)) def leave(self): kiss_command = bytes([KISS.FEND, KISS.CMD_LEAVE, 0xFF, KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while sending host left command to device") + raise OSError("An IO error occurred while sending host left command to device") sleep(1) def set_display_intensity(self, intensity): @@ -656,46 +656,46 @@ class RNode(): kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_DISP_INT])+data+bytes([KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while sending display intensity command to device") + raise OSError("An IO error occurred while sending display intensity command to device") def set_display_blanking(self, blanking_timeout): data = bytes([blanking_timeout & 0xFF]) kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_DISP_BLNK])+data+bytes([KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while sending display blanking timeout command to device") + raise OSError("An IO error occurred while sending display blanking timeout command to device") def set_neopixel_intensity(self, intensity): data = bytes([intensity & 0xFF]) kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_NP_INT])+data+bytes([KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while sending NeoPixel intensity command to device") + raise OSError("An IO error occurred while sending NeoPixel intensity command to device") def set_display_address(self, address): data = bytes([address & 0xFF]) kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_DISP_ADR])+data+bytes([KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while sending display address command to device") + raise OSError("An IO error occurred while sending display address command to device") def enable_bluetooth(self): kiss_command = bytes([KISS.FEND, KISS.CMD_BT_CTRL, 0x01, KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while sending bluetooth enable command to device") + raise OSError("An IO error occurred while sending bluetooth enable command to device") def disable_bluetooth(self): kiss_command = bytes([KISS.FEND, KISS.CMD_BT_CTRL, 0x00, KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while sending bluetooth disable command to device") + raise OSError("An IO error occurred while sending bluetooth disable command to device") def bluetooth_pair(self): kiss_command = bytes([KISS.FEND, KISS.CMD_BT_CTRL, 0x02, KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while sending bluetooth pair command to device") + raise OSError("An IO error occurred while sending bluetooth pair command to device") def store_signature(self, signature_bytes): data = KISS.escape(signature_bytes) @@ -703,7 +703,7 @@ class RNode(): written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while sending signature to device") + raise OSError("An IO error occurred while sending signature to device") def set_firmware_hash(self, hash_bytes): data = KISS.escape(hash_bytes) @@ -711,14 +711,14 @@ class RNode(): written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while sending firmware hash to device") + raise OSError("An IO error occurred while sending firmware hash to device") def indicate_firmware_update(self): kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_FW_UPD])+bytes([0x01])+bytes([KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while sending firmware update command to device") + raise OSError("An IO error occurred while sending firmware update command to device") def initRadio(self): self.setFrequency() @@ -738,7 +738,7 @@ class RNode(): kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_FREQUENCY])+data+bytes([KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while configuring frequency for "+self(str)) + raise OSError("An IO error occurred while configuring frequency for "+self(str)) def setBandwidth(self): c1 = self.bandwidth >> 24 @@ -750,46 +750,46 @@ class RNode(): kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_BANDWIDTH])+data+bytes([KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while configuring bandwidth for "+self(str)) + raise OSError("An IO error occurred while configuring bandwidth for "+self(str)) def setTXPower(self): txp = bytes([self.txpower]) kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_TXPOWER])+txp+bytes([KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while configuring TX power for "+self(str)) + raise OSError("An IO error occurred while configuring TX power for "+self(str)) def setSpreadingFactor(self): sf = bytes([self.sf]) kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_SF])+sf+bytes([KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while configuring spreading factor for "+self(str)) + raise OSError("An IO error occurred while configuring spreading factor for "+self(str)) def setCodingRate(self): cr = bytes([self.cr]) kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_CR])+cr+bytes([KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while configuring coding rate for "+self(str)) + raise OSError("An IO error occurred while configuring coding rate for "+self(str)) def setRadioState(self, state): kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_RADIO_STATE])+bytes([state])+bytes([KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while configuring radio state for "+self(str)) + raise OSError("An IO error occurred while configuring radio state for "+self(str)) def setNormalMode(self): kiss_command = bytes([KISS.FEND, KISS.CMD_CONF_DELETE, 0x00, KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while configuring device mode") + raise OSError("An IO error occurred while configuring device mode") def setTNCMode(self): kiss_command = bytes([KISS.FEND, KISS.CMD_CONF_SAVE, 0x00, KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while configuring device mode") + raise OSError("An IO error occurred while configuring device mode") if self.platform == ROM.PLATFORM_ESP32: self.hard_reset() @@ -798,7 +798,7 @@ class RNode(): kiss_command = bytes([KISS.FEND, KISS.CMD_ROM_WIPE, 0xf8, KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while wiping EEPROM") + raise OSError("An IO error occurred while wiping EEPROM") sleep(13); # Due to the current janky emulated EEPROM implementation for the # RAK4631, extra time must be given to allow for writing. @@ -809,7 +809,7 @@ class RNode(): kiss_command = bytes([KISS.FEND, KISS.CMD_RESET, 0xf8, KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while restarting device") + raise OSError("An IO error occurred while restarting device") sleep(2); def write_eeprom(self, addr, byte): @@ -818,7 +818,7 @@ class RNode(): kiss_command = bytes([KISS.FEND, KISS.CMD_ROM_WRITE]) + write_payload + bytes([KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while writing EEPROM") + raise OSError("An IO error occurred while writing EEPROM") def download_eeprom(self): @@ -826,7 +826,7 @@ class RNode(): kiss_command = bytes([KISS.FEND, KISS.CMD_ROM_READ, 0x00, KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while configuring radio state") + raise OSError("An IO error occurred while configuring radio state") sleep(0.6) if self.eeprom == None: @@ -1031,7 +1031,7 @@ class RNode(): RNS.log("Current firmware version: "+self.version) return True else: - raise IOError("Got invalid response while detecting device") + raise OSError("Got invalid response while detecting device") selected_version = None selected_hash = None @@ -3436,7 +3436,7 @@ def main(): txp_mw = round(pow(10, (rnode.conf_txpower/10)), 3) RNS.log(""); RNS.log("\tDevice mode : TNC") - RNS.log("\t Frequency : "+str((rnode.conf_frequency/1000000.0))+" MHz") + RNS.log("\t Frequency : "+str(rnode.conf_frequency/1000000.0)+" MHz") RNS.log("\t Bandwidth : "+str(rnode.conf_bandwidth/1000.0)+" KHz") RNS.log("\t TX power : "+str(rnode.conf_txpower)+" dBm ("+str(txp_mw)+" mW)") RNS.log("\t Spreading factor : "+str(rnode.conf_sf)) @@ -3500,7 +3500,7 @@ def main(): counter_path = FWD_DIR+"/serial.counter" try: if os.path.isfile(counter_path): - file = open(counter_path, "r") + file = open(counter_path) counter_str = file.read() counter = int(counter_str) file.close() @@ -3933,7 +3933,7 @@ def extract_recovery_esptool(): import base64, gzip recovery_esptool = "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" out = open(RT_PATH, "wb") - out.write("#!/usr/bin/env python3\n\n".encode("utf-8")+gzip.decompress(base64.b64decode(recovery_esptool))) + out.write(b"#!/usr/bin/env python3\n\n"+gzip.decompress(base64.b64decode(recovery_esptool))) out.close() except Exception as e: RNS.log("Error: Could not extract recovery ESP-Tool. The contained exception was:") diff --git a/RNS/Utilities/rnpath.py b/RNS/Utilities/rnpath.py index 5578c70..353d020 100644 --- a/RNS/Utilities/rnpath.py +++ b/RNS/Utilities/rnpath.py @@ -35,7 +35,7 @@ def connect_remote(destination_hash, auth_identity, timeout, no_output = False): global remote_link, reticulum if not RNS.Transport.has_path(destination_hash): if not no_output: - print("Path to "+RNS.prettyhexrep(destination_hash)+" requested", end=" ") + print(f"Path to {RNS.prettyhexrep(destination_hash)} requested", end=" ") sys.stdout.flush() RNS.Transport.request_path(destination_hash) pr_time = time.time() @@ -88,7 +88,7 @@ def program_setup(configdir, table, rates, drop, destination_hexhash, verbosity, try: dest_len = (RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2 if len(remote) != dest_len: - raise ValueError("Destination length is invalid, must be {hex} hexadecimal characters ({byte} bytes).".format(hex=dest_len, byte=dest_len//2)) + raise ValueError(f"Destination length is invalid, must be {dest_len} hexadecimal characters ({dest_len // 2} bytes).") try: identity_hash = bytes.fromhex(remote) remote_hash = RNS.Destination.hash_from_name_and_identity("rnstransport.remote.management", identity_hash) @@ -97,7 +97,7 @@ def program_setup(configdir, table, rates, drop, destination_hexhash, verbosity, identity = RNS.Identity.from_file(os.path.expanduser(management_identity)) if identity == None: - raise ValueError("Could not load management identity from "+str(management_identity)) + raise ValueError(f"Could not load management identity from {management_identity}") try: connect_remote(remote_hash, identity, remote_timeout, no_output) @@ -118,7 +118,7 @@ def program_setup(configdir, table, rates, drop, destination_hexhash, verbosity, try: dest_len = (RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2 if len(destination_hexhash) != dest_len: - raise ValueError("Destination length is invalid, must be {hex} hexadecimal characters ({byte} bytes).".format(hex=dest_len, byte=dest_len//2)) + raise ValueError(f"Destination length is invalid, must be {dest_len} hexadecimal characters ({dest_len // 2} bytes).") try: destination_hash = bytes.fromhex(destination_hexhash) except Exception as e: @@ -166,7 +166,7 @@ def program_setup(configdir, table, rates, drop, destination_hexhash, verbosity, m_str = " " else: m_str = "s" - print(RNS.prettyhexrep(path["hash"])+" is "+str(path["hops"])+" hop"+m_str+" away via "+RNS.prettyhexrep(path["via"])+" on "+path["interface"]+" expires "+RNS.timestamp_str(path["expires"])) + print(f"{RNS.prettyhexrep(path['hash'])} is {path['hops']} hop{m_str} away via {RNS.prettyhexrep(path['via'])} on {path['interface']} expires {RNS.timestamp_str(path['expires'])}") if destination_hash != None and displayed == 0: print("No path known") @@ -178,7 +178,7 @@ def program_setup(configdir, table, rates, drop, destination_hexhash, verbosity, try: dest_len = (RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2 if len(destination_hexhash) != dest_len: - raise ValueError("Destination length is invalid, must be {hex} hexadecimal characters ({byte} bytes).".format(hex=dest_len, byte=dest_len//2)) + raise ValueError(f"Destination length is invalid, must be {dest_len} hexadecimal characters ({dest_len // 2} bytes).") try: destination_hash = bytes.fromhex(destination_hexhash) except Exception as e: @@ -242,21 +242,21 @@ def program_setup(configdir, table, rates, drop, destination_hexhash, verbosity, else: s_str = "s" - rv_str = ", "+str(entry["rate_violations"])+" active rate violation"+s_str + rv_str = f", {entry['rate_violations']} active rate violation{s_str}" else: rv_str = "" if entry["blocked_until"] > time.time(): bli = time.time()-(int(entry["blocked_until"])-time.time()) - bl_str = ", new announces allowed in "+pretty_date(int(bli)) + bl_str = f", new announces allowed in {pretty_date(int(bli))}" else: bl_str = "" - print(RNS.prettyhexrep(entry["hash"])+" last heard "+last_str+" ago, "+str(hour_rate)+" announces/hour in the last "+span_str+rv_str+bl_str) + print(f"{RNS.prettyhexrep(entry['hash'])} last heard {last_str} ago, {hour_rate} announces/hour in the last {span_str}{rv_str}{bl_str}") except Exception as e: - print("Error while processing entry for "+RNS.prettyhexrep(entry["hash"])) + print(f"Error while processing entry for {RNS.prettyhexrep(entry['hash'])}") print(str(e)) if destination_hash != None and displayed == 0: @@ -283,7 +283,7 @@ def program_setup(configdir, table, rates, drop, destination_hexhash, verbosity, try: dest_len = (RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2 if len(destination_hexhash) != dest_len: - raise ValueError("Destination length is invalid, must be {hex} hexadecimal characters ({byte} bytes).".format(hex=dest_len, byte=dest_len//2)) + raise ValueError(f"Destination length is invalid, must be {dest_len} hexadecimal characters ({dest_len // 2} bytes).") try: destination_hash = bytes.fromhex(destination_hexhash) except Exception as e: @@ -293,9 +293,9 @@ def program_setup(configdir, table, rates, drop, destination_hexhash, verbosity, sys.exit(1) if reticulum.drop_path(destination_hash): - print("Dropped path to "+RNS.prettyhexrep(destination_hash)) + print(f"Dropped path to {RNS.prettyhexrep(destination_hash)}") else: - print("Unable to drop path to "+RNS.prettyhexrep(destination_hash)+". Does it exist?") + print(f"Unable to drop path to {RNS.prettyhexrep(destination_hash)}. Does it exist?") sys.exit(1) elif drop_via: @@ -308,7 +308,7 @@ def program_setup(configdir, table, rates, drop, destination_hexhash, verbosity, try: dest_len = (RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2 if len(destination_hexhash) != dest_len: - raise ValueError("Destination length is invalid, must be {hex} hexadecimal characters ({byte} bytes).".format(hex=dest_len, byte=dest_len//2)) + raise ValueError(f"Destination length is invalid, must be {dest_len} hexadecimal characters ({dest_len // 2} bytes).") try: destination_hash = bytes.fromhex(destination_hexhash) except Exception as e: @@ -318,9 +318,9 @@ def program_setup(configdir, table, rates, drop, destination_hexhash, verbosity, sys.exit(1) if reticulum.drop_all_via(destination_hash): - print("Dropped all paths via "+RNS.prettyhexrep(destination_hash)) + print(f"Dropped all paths via {RNS.prettyhexrep(destination_hash)}") else: - print("Unable to drop paths via "+RNS.prettyhexrep(destination_hash)+". Does the transport instance exist?") + print(f"Unable to drop paths via {RNS.prettyhexrep(destination_hash)}. Does the transport instance exist?") sys.exit(1) else: @@ -333,7 +333,7 @@ def program_setup(configdir, table, rates, drop, destination_hexhash, verbosity, try: dest_len = (RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2 if len(destination_hexhash) != dest_len: - raise ValueError("Destination length is invalid, must be {hex} hexadecimal characters ({byte} bytes).".format(hex=dest_len, byte=dest_len//2)) + raise ValueError(f"Destination length is invalid, must be {dest_len} hexadecimal characters ({dest_len // 2} bytes).") try: destination_hash = bytes.fromhex(destination_hexhash) except Exception as e: @@ -344,7 +344,7 @@ def program_setup(configdir, table, rates, drop, destination_hexhash, verbosity, if not RNS.Transport.has_path(destination_hash): RNS.Transport.request_path(destination_hash) - print("Path to "+RNS.prettyhexrep(destination_hash)+" requested ", end=" ") + print(f"Path to {RNS.prettyhexrep(destination_hash)} requested ", end=" ") sys.stdout.flush() i = 0 @@ -352,7 +352,7 @@ def program_setup(configdir, table, rates, drop, destination_hexhash, verbosity, limit = time.time()+timeout while not RNS.Transport.has_path(destination_hash) and time.time() _timeout: time.sleep(0.1) - print(("\b\b"+syms[i]+" "), end="") + print(f"\b\b{syms[i]} ", end="") sys.stdout.flush() i = (i+1)%len(syms) @@ -107,7 +107,7 @@ def program_setup(configdir, destination_hexhash, size=None, full_name = None, v probe = RNS.Packet(request_destination, os.urandom(size)) probe.pack() except OSError: - print("Error: Probe packet size of "+str(len(probe.raw))+" bytes exceed MTU of "+str(RNS.Reticulum.MTU)+" bytes") + print(f"Error: Probe packet size of {len(probe.raw)} bytes exceed MTU of {RNS.Reticulum.MTU} bytes") exit(3) receipt = probe.send() @@ -115,19 +115,19 @@ def program_setup(configdir, destination_hexhash, size=None, full_name = None, v if more_output: nhd = reticulum.get_next_hop(destination_hash) - via_str = " via "+RNS.prettyhexrep(nhd) if nhd != None else "" - if_str = " on "+str(reticulum.get_next_hop_if_name(destination_hash)) if reticulum.get_next_hop_if_name(destination_hash) != "None" else "" + via_str = f" via {RNS.prettyhexrep(nhd)}" if nhd != None else "" + if_str = f" on {reticulum.get_next_hop_if_name(destination_hash)}" if reticulum.get_next_hop_if_name(destination_hash) != "None" else "" more = via_str+if_str else: more = "" - print("\rSent probe "+str(sent)+" ("+str(size)+" bytes) to "+RNS.prettyhexrep(destination_hash)+more+" ", end=" ") + print(f'\rSent probe {sent} ({size} bytes) to {RNS.prettyhexrep(destination_hash)}{more} ', end=" ") _timeout = time.time() + (timeout or DEFAULT_TIMEOUT+reticulum.get_first_hop_timeout(destination_hash)) i = 0 while receipt.status == RNS.PacketReceipt.SENT and not time.time() > _timeout: time.sleep(0.1) - print(("\b\b"+syms[i]+" "), end="") + print(f"\b\b{syms[i]} ", end="") sys.stdout.flush() i = (i+1)%len(syms) @@ -149,10 +149,10 @@ def program_setup(configdir, destination_hexhash, size=None, full_name = None, v rtt = receipt.get_rtt() if (rtt >= 1): rtt = round(rtt, 3) - rttstring = str(rtt)+" seconds" + rttstring = f"{rtt} seconds" else: rtt = round(rtt*1000, 3) - rttstring = str(rtt)+" milliseconds" + rttstring = f"{rtt} milliseconds" reception_stats = "" if reticulum.is_connected_to_shared_instance: @@ -161,28 +161,24 @@ def program_setup(configdir, destination_hexhash, size=None, full_name = None, v reception_q = reticulum.get_packet_q(receipt.proof_packet.packet_hash) if reception_rssi != None: - reception_stats += " [RSSI "+str(reception_rssi)+" dBm]" + reception_stats += f" [RSSI {reception_rssi} dBm]" if reception_snr != None: - reception_stats += " [SNR "+str(reception_snr)+" dB]" + reception_stats += f" [SNR {reception_snr} dB]" if reception_q != None: - reception_stats += " [Link Quality "+str(reception_q)+"%]" + reception_stats += f" [Link Quality {reception_q}%]" else: if receipt.proof_packet != None: if receipt.proof_packet.rssi != None: - reception_stats += " [RSSI "+str(receipt.proof_packet.rssi)+" dBm]" + reception_stats += f" [RSSI {receipt.proof_packet.rssi} dBm]" if receipt.proof_packet.snr != None: - reception_stats += " [SNR "+str(receipt.proof_packet.snr)+" dB]" + reception_stats += f" [SNR {receipt.proof_packet.snr} dB]" print( - "Valid reply from "+ - RNS.prettyhexrep(receipt.destination.hash)+ - "\nRound-trip time is "+rttstring+ - " over "+str(hops)+" hop"+ms+ - reception_stats+"\n" + f"Valid reply from {RNS.prettyhexrep(receipt.destination.hash)}\nRound-trip time is {rttstring} over {hops} hop{ms}{reception_stats}\n" ) else: @@ -207,7 +203,7 @@ def main(): parser.add_argument("-n", "--probes", action="store", default=1, help="number of probes to send", type=int) parser.add_argument("-t", "--timeout", metavar="seconds", action="store", default=None, help="timeout before giving up", type=float) parser.add_argument("-w", "--wait", metavar="seconds", action="store", default=0, help="time between each probe", type=float) - parser.add_argument("--version", action="version", version="rnprobe {version}".format(version=__version__)) + parser.add_argument("--version", action="version", version=f"rnprobe {__version__}") parser.add_argument("full_name", nargs="?", default=None, help="full destination name in dotted notation", type=str) parser.add_argument("destination_hash", nargs="?", default=None, help="hexadecimal hash of the destination", type=str) diff --git a/RNS/Utilities/rnsd.py b/RNS/Utilities/rnsd.py index 6a46e1c..6c75e41 100755 --- a/RNS/Utilities/rnsd.py +++ b/RNS/Utilities/rnsd.py @@ -40,9 +40,9 @@ def program_setup(configdir, verbosity = 0, quietness = 0, service = False): reticulum = RNS.Reticulum(configdir=configdir, verbosity=targetverbosity, logdest=targetlogdest) if reticulum.is_connected_to_shared_instance: - RNS.log("Started rnsd version {version} connected to another shared local instance, this is probably NOT what you want!".format(version=__version__), RNS.LOG_WARNING) + RNS.log(f"Started rnsd version {__version__} connected to another shared local instance, this is probably NOT what you want!", RNS.LOG_WARNING) else: - RNS.log("Started rnsd version {version}".format(version=__version__), RNS.LOG_NOTICE) + RNS.log(f"Started rnsd version {__version__}", RNS.LOG_NOTICE) while True: time.sleep(1) @@ -55,7 +55,7 @@ def main(): parser.add_argument('-q', '--quiet', action='count', default=0) parser.add_argument('-s', '--service', action='store_true', default=False, help="rnsd is running as a service and should log to file") parser.add_argument("--exampleconfig", action='store_true', default=False, help="print verbose configuration example to stdout and exit") - parser.add_argument("--version", action="version", version="rnsd {version}".format(version=__version__)) + parser.add_argument("--version", action="version", version=f"rnsd {__version__}") args = parser.parse_args() diff --git a/RNS/Utilities/rnstatus.py b/RNS/Utilities/rnstatus.py index d6569ec..5e36b7e 100644 --- a/RNS/Utilities/rnstatus.py +++ b/RNS/Utilities/rnstatus.py @@ -42,12 +42,12 @@ def size_str(num, suffix='B'): for unit in units: if abs(num) < 1000.0: if unit == "": - return "%.0f %s%s" % (num, unit, suffix) + return f"{num:.0f} {unit}{suffix}" else: - return "%.2f %s%s" % (num, unit, suffix) + return f"{num:.2f} {unit}{suffix}" num /= 1000.0 - return "%.2f%s%s" % (num, last_unit, suffix) + return f"{num:.2f}{last_unit}{suffix}" request_result = None request_concluded = False @@ -144,7 +144,7 @@ def program_setup(configdir, dispall=False, verbosity=0, name_filter=None, json= try: dest_len = (RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2 if len(remote) != dest_len: - raise ValueError("Destination length is invalid, must be {hex} hexadecimal characters ({byte} bytes).".format(hex=dest_len, byte=dest_len//2)) + raise ValueError(f"Destination length is invalid, must be {dest_len} hexadecimal characters ({dest_len // 2} bytes).") try: identity_hash = bytes.fromhex(remote) destination_hash = RNS.Destination.hash_from_name_and_identity("rnstransport.remote.management", identity_hash) @@ -281,13 +281,13 @@ def program_setup(configdir, dispall=False, verbosity=0, name_filter=None, json= if "ifac_netname" in ifstat and ifstat["ifac_netname"] != None: print(" Network : {nn}".format(nn=ifstat["ifac_netname"])) - print(" Status : {ss}".format(ss=ss)) + print(f" Status : {ss}") if clients != None and clients_string != "": print(" "+clients_string) if not (name.startswith("Shared Instance[") or name.startswith("TCPInterface[Client") or name.startswith("LocalInterface[")): - print(" Mode : {mode}".format(mode=modestr)) + print(f" Mode : {modestr}") if "bitrate" in ifstat and ifstat["bitrate"] != None: print(" Rate : {ss}".format(ss=speed_str(ifstat["bitrate"]))) @@ -489,10 +489,10 @@ def speed_str(num, suffix='bps'): for unit in units: if abs(num) < 1000.0: - return "%3.2f %s%s" % (num, unit, suffix) + return f"{num:3.2f} {unit}{suffix}" num /= 1000.0 - return "%.2f %s%s" % (num, last_unit, suffix) + return f"{num:.2f} {last_unit}{suffix}" if __name__ == "__main__": main() diff --git a/RNS/Utilities/rnx.py b/RNS/Utilities/rnx.py index 2e7ae0c..8d421c6 100644 --- a/RNS/Utilities/rnx.py +++ b/RNS/Utilities/rnx.py @@ -42,7 +42,7 @@ allowed_identity_hashes = [] def prepare_identity(identity_path): global identity if identity_path == None: - identity_path = RNS.Reticulum.identitypath+"/"+APP_NAME + identity_path = f"{RNS.Reticulum.identitypath}/{APP_NAME}" if os.path.isfile(identity_path): identity = RNS.Identity.from_file(identity_path) @@ -62,8 +62,8 @@ def listen(configdir, identitypath = None, verbosity = 0, quietness = 0, allowed destination = RNS.Destination(identity, RNS.Destination.IN, RNS.Destination.SINGLE, APP_NAME, "execute") if print_identity: - print("Identity : "+str(identity)) - print("Listening on : "+RNS.prettyhexrep(destination.hash)) + print(f"Identity : {identity}") + print(f"Listening on : {RNS.prettyhexrep(destination.hash)}") exit(0) if disable_auth: @@ -74,7 +74,7 @@ def listen(configdir, identitypath = None, verbosity = 0, quietness = 0, allowed try: dest_len = (RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2 if len(a) != dest_len: - raise ValueError("Allowed destination length is invalid, must be {hex} hexadecimal characters ({byte} bytes).".format(hex=dest_len, byte=dest_len//2)) + raise ValueError(f"Allowed destination length is invalid, must be {dest_len} hexadecimal characters ({dest_len // 2} bytes).") try: destination_hash = bytes.fromhex(a) allowed_identity_hashes.append(destination_hash) @@ -103,7 +103,7 @@ def listen(configdir, identitypath = None, verbosity = 0, quietness = 0, allowed allow = RNS.Destination.ALLOW_ALL, ) - RNS.log("rnx listening for commands on "+RNS.prettyhexrep(destination.hash)) + RNS.log(f"rnx listening for commands on {RNS.prettyhexrep(destination.hash)}") if not disable_announce: destination.announce() @@ -114,16 +114,16 @@ def listen(configdir, identitypath = None, verbosity = 0, quietness = 0, allowed def command_link_established(link): link.set_remote_identified_callback(initiator_identified) link.set_link_closed_callback(command_link_closed) - RNS.log("Command link "+str(link)+" established") + RNS.log(f"Command link {link} established") def command_link_closed(link): - RNS.log("Command link "+str(link)+" closed") + RNS.log(f"Command link {link} closed") def initiator_identified(link, identity): global allow_all - RNS.log("Initiator of link "+str(link)+" identified as "+RNS.prettyhexrep(identity.hash)) + RNS.log(f"Initiator of link {link} identified as {RNS.prettyhexrep(identity.hash)}") if not allow_all and not identity.hash in allowed_identity_hashes: - RNS.log("Identity "+RNS.prettyhexrep(identity.hash)+" not allowed, tearing down link") + RNS.log(f"Identity {RNS.prettyhexrep(identity.hash)} not allowed, tearing down link") link.teardown() def execute_received_command(path, data, request_id, remote_identity, requested_at): @@ -134,9 +134,9 @@ def execute_received_command(path, data, request_id, remote_identity, requested_ stdin = data[4] # Data passed to stdin if remote_identity != None: - RNS.log("Executing command ["+command+"] for "+RNS.prettyhexrep(remote_identity.hash)) + RNS.log(f"Executing command [{command}] for {RNS.prettyhexrep(remote_identity.hash)}") else: - RNS.log("Executing command ["+command+"] for unknown requestor") + RNS.log(f"Executing command [{command}] for unknown requestor") result = [ False, # 0: Command was executed @@ -178,7 +178,7 @@ def execute_received_command(path, data, request_id, remote_identity, requested_ pass if timeout != None and time.time() > result[6]+timeout: - RNS.log("Command ["+command+"] timed out and is being killed...") + RNS.log(f"Command [{command}] timed out and is being killed...") process.terminate() process.wait() if process.poll() != None: @@ -219,9 +219,9 @@ def execute_received_command(path, data, request_id, remote_identity, requested_ return result if remote_identity != None: - RNS.log("Delivering result of command ["+str(command)+"] to "+RNS.prettyhexrep(remote_identity.hash)) + RNS.log(f"Delivering result of command [{command}] to {RNS.prettyhexrep(remote_identity.hash)}") else: - RNS.log("Delivering result of command ["+str(command)+"] to unknown requestor") + RNS.log(f"Delivering result of command [{command}] to unknown requestor") return result @@ -231,14 +231,14 @@ def spin(until=None, msg=None, timeout=None): if timeout != None: timeout = time.time()+timeout - print(msg+" ", end=" ") + print(f"{msg} ", end=" ") while (timeout == None or time.time() timeout: return False @@ -259,8 +259,8 @@ def spin_stat(until=None, timeout=None): time.sleep(0.1) prg = current_progress percent = round(prg * 100.0, 1) - stat_str = str(percent)+"% - " + size_str(int(prg*response_transfer_size)) + " of " + size_str(response_transfer_size) + " - " +size_str(speed, "b")+"ps" - print("\r \rReceiving result "+syms[i]+" "+stat_str, end=" ") + stat_str = f"{percent}% - {size_str(int(prg * response_transfer_size))} of {size_str(response_transfer_size)} - {size_str(speed, 'b')}ps" + print(f'\r \rReceiving result {syms[i]} {stat_str}', end=" ") sys.stdout.flush() i = (i+1)%len(syms) @@ -303,7 +303,7 @@ def execute(configdir, identitypath = None, verbosity = 0, quietness = 0, detail try: dest_len = (RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2 if len(destination) != dest_len: - raise ValueError("Allowed destination length is invalid, must be {hex} hexadecimal characters ({byte} bytes).".format(hex=dest_len, byte=dest_len//2)) + raise ValueError(f"Allowed destination length is invalid, must be {dest_len} hexadecimal characters ({dest_len // 2} bytes).") try: destination_hash = bytes.fromhex(destination) except Exception as e: @@ -321,7 +321,7 @@ def execute(configdir, identitypath = None, verbosity = 0, quietness = 0, detail if not RNS.Transport.has_path(destination_hash): RNS.Transport.request_path(destination_hash) - if not spin(until=lambda: RNS.Transport.has_path(destination_hash), msg="Path to "+RNS.prettyhexrep(destination_hash)+" requested", timeout=timeout): + if not spin(until=lambda: RNS.Transport.has_path(destination_hash), msg=f"Path to {RNS.prettyhexrep(destination_hash)} requested", timeout=timeout): print("Path not found") exit(242) @@ -339,8 +339,8 @@ def execute(configdir, identitypath = None, verbosity = 0, quietness = 0, detail link = RNS.Link(listener_destination) link.did_identify = False - if not spin(until=lambda: link.status == RNS.Link.ACTIVE, msg="Establishing link with "+RNS.prettyhexrep(destination_hash), timeout=timeout): - print("Could not establish link with "+RNS.prettyhexrep(destination_hash)) + if not spin(until=lambda: link.status == RNS.Link.ACTIVE, msg=f"Establishing link with {RNS.prettyhexrep(destination_hash)}", timeout=timeout): + print(f"Could not establish link with {RNS.prettyhexrep(destination_hash)}") exit(243) if not noid and not link.did_identify: @@ -443,7 +443,7 @@ def execute(configdir, identitypath = None, verbosity = 0, quietness = 0, detail print("\n--- End of remote output, rnx done ---") if started != None and concluded != None: cmd_duration = round(concluded - started, 3) - print("Remote command execution took "+str(cmd_duration)+" seconds") + print(f"Remote command execution took {cmd_duration} seconds") total_size = request_receipt.response_size if request_receipt.request_size != None: @@ -453,27 +453,27 @@ def execute(configdir, identitypath = None, verbosity = 0, quietness = 0, detail if transfer_duration == 1: tdstr = " in 1 second" elif transfer_duration < 10: - tdstr = " in "+str(transfer_duration)+" seconds" + tdstr = f" in {transfer_duration} seconds" else: - tdstr = " in "+pretty_time(transfer_duration) + tdstr = f" in {pretty_time(transfer_duration)}" - spdstr = ", effective rate "+size_str(total_size/transfer_duration, "b")+"ps" + spdstr = f", effective rate {size_str(total_size / transfer_duration, 'b')}ps" - print("Transferred "+size_str(total_size)+tdstr+spdstr) + print(f"Transferred {size_str(total_size)}{tdstr}{spdstr}") if outlen != None and stdout != None: if len(stdout) < outlen: - tstr = ", "+str(len(stdout))+" bytes displayed" + tstr = f", {len(stdout)} bytes displayed" else: tstr = "" - print("Remote wrote "+str(outlen)+" bytes to stdout"+tstr) + print(f"Remote wrote {outlen} bytes to stdout{tstr}") if errlen != None and stderr != None: if len(stderr) < errlen: - tstr = ", "+str(len(stderr))+" bytes displayed" + tstr = f", {len(stderr)} bytes displayed" else: tstr = "" - print("Remote wrote "+str(errlen)+" bytes to stderr"+tstr) + print(f"Remote wrote {errlen} bytes to stderr{tstr}") else: if stdout != None and len(stdout) > 0: @@ -487,9 +487,9 @@ def execute(configdir, identitypath = None, verbosity = 0, quietness = 0, detail sys.stderr.flush() print("\nOutput truncated before being returned:") if len(stdout) != 0 and len(stdout) < outlen: - print(" stdout truncated to "+str(len(stdout))+" bytes") + print(f" stdout truncated to {len(stdout)} bytes") if len(stderr) != 0 and len(stderr) < errlen: - print(" stderr truncated to "+str(len(stderr))+" bytes") + print(f" stderr truncated to {len(stderr)} bytes") else: print("Remote could not execute command") if interactive: @@ -547,7 +547,7 @@ def main(): parser.add_argument("--stdin", action='store', default=None, help="pass input to stdin", type=str) parser.add_argument("--stdout", action='store', default=None, help="max size in bytes of returned stdout", type=int) parser.add_argument("--stderr", action='store', default=None, help="max size in bytes of returned stderr", type=int) - parser.add_argument("--version", action="version", version="rnx {version}".format(version=__version__)) + parser.add_argument("--version", action="version", version=f"rnx {__version__}") args = parser.parse_args() @@ -593,7 +593,7 @@ def main(): while True: try: cstr = str(code) if code and code != 0 else "" - prompt = cstr+"> " + prompt = f"{cstr}> " print(prompt,end="") # cmdbuf = b"" @@ -661,12 +661,12 @@ def size_str(num, suffix='B'): for unit in units: if abs(num) < 1000.0: if unit == "": - return "%.0f %s%s" % (num, unit, suffix) + return f"{num:.0f} {unit}{suffix}" else: - return "%.2f %s%s" % (num, unit, suffix) + return f"{num:.2f} {unit}{suffix}" num /= 1000.0 - return "%.2f%s%s" % (num, last_unit, suffix) + return f"{num:.2f}{last_unit}{suffix}" def pretty_time(time, verbose=False): days = int(time // (24 * 3600)) @@ -684,16 +684,16 @@ def pretty_time(time, verbose=False): components = [] if days > 0: - components.append(str(days)+" day"+sd if verbose else str(days)+"d") + components.append(f"{days} day{sd}" if verbose else f"{days}d") if hours > 0: - components.append(str(hours)+" hour"+sh if verbose else str(hours)+"h") + components.append(f"{hours} hour{sh}" if verbose else f"{hours}h") if minutes > 0: - components.append(str(minutes)+" minute"+sm if verbose else str(minutes)+"m") + components.append(f"{minutes} minute{sm}" if verbose else f"{minutes}m") if seconds > 0: - components.append(str(seconds)+" second"+ss if verbose else str(seconds)+"s") + components.append(f"{seconds} second{ss}" if verbose else f"{seconds}s") i = 0 tstr = "" diff --git a/RNS/__init__.py b/RNS/__init__.py index 8828e48..04ee64e 100755 --- a/RNS/__init__.py +++ b/RNS/__init__.py @@ -147,7 +147,7 @@ def rand(): def trace_exception(e): import traceback exception_info = "".join(traceback.TracebackException.from_exception(e).format()) - log(f"An unhandled {str(type(e))} exception occurred: {str(e)}", LOG_ERROR) + log(f"An unhandled {type(e)} exception occurred: {e}", LOG_ERROR) log(exception_info, LOG_ERROR) def hexrep(data, delimit=True): @@ -159,12 +159,12 @@ def hexrep(data, delimit=True): delimiter = ":" if not delimit: delimiter = "" - hexrep = delimiter.join("{:02x}".format(c) for c in data) + hexrep = delimiter.join(f"{c:02x}" for c in data) return hexrep def prettyhexrep(data): delimiter = "" - hexrep = "<"+delimiter.join("{:02x}".format(c) for c in data)+">" + hexrep = "<"+delimiter.join(f"{c:02x}" for c in data)+">" return hexrep def prettyspeed(num, suffix="b"): @@ -182,12 +182,12 @@ def prettysize(num, suffix='B'): for unit in units: if abs(num) < 1000.0: if unit == "": - return "%.0f %s%s" % (num, unit, suffix) + return f"{num:.0f} {unit}{suffix}" else: - return "%.2f %s%s" % (num, unit, suffix) + return f"{num:.2f} {unit}{suffix}" num /= 1000.0 - return "%.2f%s%s" % (num, last_unit, suffix) + return f"{num:.2f}{last_unit}{suffix}" def prettyfrequency(hz, suffix="Hz"): num = hz*1e6 @@ -196,10 +196,10 @@ def prettyfrequency(hz, suffix="Hz"): for unit in units: if abs(num) < 1000.0: - return "%.2f %s%s" % (num, unit, suffix) + return f"{num:.2f} {unit}{suffix}" num /= 1000.0 - return "%.2f%s%s" % (num, last_unit, suffix) + return f"{num:.2f}{last_unit}{suffix}" def prettydistance(m, suffix="m"): num = m*1e6 @@ -212,10 +212,10 @@ def prettydistance(m, suffix="m"): if unit == "c": divisor = 100 if abs(num) < divisor: - return "%.2f %s%s" % (num, unit, suffix) + return f"{num:.2f} {unit}{suffix}" num /= divisor - return "%.2f %s%s" % (num, last_unit, suffix) + return f"{num:.2f} {last_unit}{suffix}" def prettytime(time, verbose=False, compact=False): days = int(time // (24 * 3600)) diff --git a/RNS/vendor/__init__.py b/RNS/vendor/__init__.py index e3164b0..4fa9d93 100755 --- a/RNS/vendor/__init__.py +++ b/RNS/vendor/__init__.py @@ -1,5 +1,5 @@ import os import glob -modules = glob.glob(os.path.dirname(__file__)+"/*.py") +modules = glob.glob(f"{os.path.dirname(__file__)}/*.py") __all__ = [ os.path.basename(f)[:-3] for f in modules if not f.endswith('__init__.py')] diff --git a/RNS/vendor/configobj.py b/RNS/vendor/configobj.py index e0c01b6..e84fde5 100755 --- a/RNS/vendor/configobj.py +++ b/RNS/vendor/configobj.py @@ -129,7 +129,7 @@ def getObj(s): global compiler if compiler is None: import compiler - s = "a=" + s + s = f"a={s}" p = compiler.parse(s) return p.getChildren()[1].getChildren()[0].getChildren()[1] @@ -138,7 +138,7 @@ class UnknownType(Exception): pass -class Builder(object): +class Builder: def build(self, o): if m is None: @@ -261,7 +261,7 @@ class InterpolationLoopError(InterpolationError): def __init__(self, option): InterpolationError.__init__( self, - 'interpolation loop detected in value "%s".' % option) + f'interpolation loop detected in value "{option}".') class RepeatSectionError(ConfigObjError): @@ -274,7 +274,7 @@ class RepeatSectionError(ConfigObjError): class MissingInterpolationOption(InterpolationError): """A value specified for interpolation was missing.""" def __init__(self, option): - msg = 'missing option "%s" in interpolation.' % option + msg = f'missing option "{option}" in interpolation.' InterpolationError.__init__(self, msg) @@ -283,7 +283,7 @@ class UnreprError(ConfigObjError): -class InterpolationEngine(object): +class InterpolationEngine: """ A helper class to help perform string interpolation. @@ -336,7 +336,7 @@ class InterpolationEngine(object): replacement = recursive_interpolate(k, v, s, backtrail) # Replace the matched string with its final value start, end = match.span() - value = ''.join((value[:start], replacement, value[end:])) + value = f"{value[:start]}{replacement}{value[end:]}" new_search_start = start + len(replacement) # Pick up the next interpolation key, if any, for next time # through the while loop @@ -553,11 +553,11 @@ class Section(dict): """Fetch the item and do string interpolation.""" val = dict.__getitem__(self, key) if self.main.interpolation: - if isinstance(val, six.string_types): + if isinstance(val, str): return self._interpolate(key, val) if isinstance(val, list): def _check(entry): - if isinstance(entry, six.string_types): + if isinstance(entry, str): return self._interpolate(key, entry) return entry new = [_check(entry) for entry in val] @@ -580,8 +580,8 @@ class Section(dict): ``unrepr`` must be set when setting a value to a dictionary, without creating a new sub-section. """ - if not isinstance(key, six.string_types): - raise ValueError('The key "%s" is not a string.' % key) + if not isinstance(key, str): + raise ValueError(f'The key "{key}" is not a string.') # add the comment if key not in self.comments: @@ -614,14 +614,14 @@ class Section(dict): if key not in self: self.scalars.append(key) if not self.main.stringify: - if isinstance(value, six.string_types): + if isinstance(value, str): pass elif isinstance(value, (list, tuple)): for entry in value: - if not isinstance(entry, six.string_types): - raise TypeError('Value is not a string "%s".' % entry) + if not isinstance(entry, str): + raise TypeError(f'Value is not a string "{entry}".') else: - raise TypeError('Value is not a string "%s".' % value) + raise TypeError(f'Value is not a string "{value}".') dict.__setitem__(self, key, value) @@ -728,7 +728,7 @@ class Section(dict): def iterkeys(self): """D.iterkeys() -> an iterator over the keys of D""" - return iter((self.scalars + self.sections)) + return iter(self.scalars + self.sections) __iter__ = iterkeys @@ -745,7 +745,7 @@ class Section(dict): return self[key] except MissingInterpolationOption: return dict.__getitem__(self, key) - return '{%s}' % ', '.join([('%s: %s' % (repr(key), repr(_getval(key)))) + return '{%s}' % ', '.join([f'{key!r}: {_getval(key)!r}' for key in (self.scalars + self.sections)]) __str__ = __repr__ @@ -823,7 +823,7 @@ class Section(dict): elif oldkey in self.sections: the_list = self.sections else: - raise KeyError('Key "%s" not found.' % oldkey) + raise KeyError(f'Key "{oldkey}" not found.') pos = the_list.index(oldkey) # val = self[oldkey] @@ -959,13 +959,13 @@ class Section(dict): return False else: try: - if not isinstance(val, six.string_types): + if not isinstance(val, str): # TODO: Why do we raise a KeyError here? raise KeyError() else: return self.main._bools[val.lower()] except KeyError: - raise ValueError('Value "%s" is neither True nor False' % val) + raise ValueError(f'Value "{val}" is neither True nor False') def as_int(self, key): @@ -1210,7 +1210,7 @@ class ConfigObj(Section): # TODO: check the values too. for entry in options: if entry not in OPTION_DEFAULTS: - raise TypeError('Unrecognised option "%s".' % entry) + raise TypeError(f'Unrecognised option "{entry}".') for entry, value in list(OPTION_DEFAULTS.items()): if entry not in options: options[entry] = value @@ -1230,14 +1230,14 @@ class ConfigObj(Section): def _load(self, infile, configspec): - if isinstance(infile, six.string_types): + if isinstance(infile, str): self.filename = infile if os.path.isfile(infile): with open(infile, 'rb') as h: content = h.readlines() or [] elif self.file_error: # raise an error if the file doesn't exist - raise IOError('Config file not found: "%s".' % self.filename) + raise OSError(f'Config file not found: "{self.filename}".') else: # file doesn't already exist if self.create_empty: @@ -1298,15 +1298,15 @@ class ConfigObj(Section): break break - assert all(isinstance(line, six.string_types) for line in content), repr(content) + assert all(isinstance(line, str) for line in content), repr(content) content = [line.rstrip('\r\n') for line in content] self._parse(content) # if we had any errors, now is the time to raise them if self._errors: - info = "at line %s." % self._errors[0].line_number + info = f"at line {self._errors[0].line_number}." if len(self._errors) > 1: - msg = "Parsing failed with several errors.\nFirst error %s" % info + msg = f"Parsing failed with several errors.\nFirst error {info}" error = ConfigObjError(msg) else: error = self._errors[0] @@ -1363,9 +1363,7 @@ class ConfigObj(Section): return self[key] except MissingInterpolationOption: return dict.__getitem__(self, key) - return ('ConfigObj({%s})' % - ', '.join([('%s: %s' % (repr(key), repr(_getval(key)))) - for key in (self.scalars + self.sections)])) + return ('ConfigObj({%s})' % ', '.join([f'{key!r}: {_getval(key)!r}' for key in (self.scalars + self.sections)])) def _handle_bom(self, infile): @@ -1403,7 +1401,7 @@ class ConfigObj(Section): else: line = infile - if isinstance(line, six.text_type): + if isinstance(line, str): # it's already decoded and there's no need to do anything # else, just use the _decode utility method to handle # listifying appropriately @@ -1448,7 +1446,7 @@ class ConfigObj(Section): # No encoding specified - so we need to check for UTF8/UTF16 for BOM, (encoding, final_encoding) in list(BOMS.items()): - if not isinstance(line, six.binary_type) or not line.startswith(BOM): + if not isinstance(line, bytes) or not line.startswith(BOM): # didn't specify a BOM, or it's not a bytestring continue else: @@ -1464,9 +1462,9 @@ class ConfigObj(Section): else: infile = newline # UTF-8 - if isinstance(infile, six.text_type): + if isinstance(infile, str): return infile.splitlines(True) - elif isinstance(infile, six.binary_type): + elif isinstance(infile, bytes): return infile.decode('utf-8').splitlines(True) else: return self._decode(infile, 'utf-8') @@ -1479,7 +1477,7 @@ class ConfigObj(Section): # returning a bytestring is fine return self._decode(infile, None) # No BOM discovered and no encoding specified, default to UTF-8 - if isinstance(infile, six.binary_type): + if isinstance(infile, bytes): return infile.decode('utf-8').splitlines(True) else: return self._decode(infile, 'utf-8') @@ -1487,7 +1485,7 @@ class ConfigObj(Section): def _a_to_u(self, aString): """Decode ASCII strings to unicode if a self.encoding is specified.""" - if isinstance(aString, six.binary_type) and self.encoding: + if isinstance(aString, bytes) and self.encoding: return aString.decode(self.encoding) else: return aString @@ -1499,9 +1497,9 @@ class ConfigObj(Section): if is a string, it also needs converting to a list. """ - if isinstance(infile, six.string_types): + if isinstance(infile, str): return infile.splitlines(True) - if isinstance(infile, six.binary_type): + if isinstance(infile, bytes): # NOTE: Could raise a ``UnicodeDecodeError`` if encoding: return infile.decode(encoding).splitlines(True) @@ -1510,7 +1508,7 @@ class ConfigObj(Section): if encoding: for i, line in enumerate(infile): - if isinstance(line, six.binary_type): + if isinstance(line, bytes): # NOTE: The isinstance test here handles mixed lists of unicode/string # NOTE: But the decode will break on any non-string values # NOTE: Or could raise a ``UnicodeDecodeError`` @@ -1520,7 +1518,7 @@ class ConfigObj(Section): def _decode_element(self, line): """Decode element to unicode if necessary.""" - if isinstance(line, six.binary_type) and self.default_encoding: + if isinstance(line, bytes) and self.default_encoding: return line.decode(self.default_encoding) else: return line @@ -1532,7 +1530,7 @@ class ConfigObj(Section): Used by ``stringify`` within validate, to turn non-string values into strings. """ - if not isinstance(value, six.string_types): + if not isinstance(value, str): # intentially 'str' because it's just whatever the "normal" # string type is for the python version we're dealing with return str(value) @@ -1627,7 +1625,7 @@ class ConfigObj(Section): mat = self._keyword.match(line) if mat is None: self._handle_error( - 'Invalid line ({0!r}) (matched as neither section nor keyword)'.format(line), + f'Invalid line ({line!r}) (matched as neither section nor keyword)', ParseError, infile, cur_index) else: # is a keyword value @@ -1735,7 +1733,7 @@ class ConfigObj(Section): """ line = infile[cur_index] cur_index += 1 - message = '{0} at line {1}.'.format(text, cur_index) + message = f'{text} at line {cur_index}.' error = ErrorClass(message, cur_index, line) if self.raise_errors: # raise the error - parsing stops here @@ -1783,16 +1781,16 @@ class ConfigObj(Section): if not value: return ',' elif len(value) == 1: - return self._quote(value[0], multiline=False) + ',' + return f"{self._quote(value[0], multiline=False)}," return ', '.join([self._quote(val, multiline=False) for val in value]) - if not isinstance(value, six.string_types): + if not isinstance(value, str): if self.stringify: # intentially 'str' because it's just whatever the "normal" # string type is for the python version we're dealing with value = str(value) else: - raise TypeError('Value "%s" is not a string.' % value) + raise TypeError(f'Value "{value}" is not a string.') if not value: return '""' @@ -1809,7 +1807,7 @@ class ConfigObj(Section): # for normal values either single or double quotes will do elif '\n' in value: # will only happen if multiline is off - e.g. '\n' in key - raise ConfigObjError('Value "%s" cannot be safely quoted.' % value) + raise ConfigObjError(f'Value "{value}" cannot be safely quoted.') elif ((value[0] not in wspace_plus) and (value[-1] not in wspace_plus) and (',' not in value)): @@ -1828,7 +1826,7 @@ class ConfigObj(Section): def _get_single_quote(self, value): if ("'" in value) and ('"' in value): - raise ConfigObjError('Value "%s" cannot be safely quoted.' % value) + raise ConfigObjError(f'Value "{value}" cannot be safely quoted.') elif '"' in value: quot = squot else: @@ -1838,7 +1836,7 @@ class ConfigObj(Section): def _get_triple_quote(self, value): if (value.find('"""') != -1) and (value.find("'''") != -1): - raise ConfigObjError('Value "%s" cannot be safely quoted.' % value) + raise ConfigObjError(f'Value "{value}" cannot be safely quoted.') if value.find('"""') == -1: quot = tdquot else: @@ -1943,9 +1941,9 @@ class ConfigObj(Section): except ConfigObjError as e: # FIXME: Should these errors have a reference # to the already parsed ConfigObj ? - raise ConfigspecError('Parsing configspec failed: %s' % e) - except IOError as e: - raise IOError('Reading configspec failed: %s' % e) + raise ConfigspecError(f'Parsing configspec failed: {e}') + except OSError as e: + raise OSError(f'Reading configspec failed: {e}') self.configspec = configspec @@ -1986,20 +1984,12 @@ class ConfigObj(Section): val = self._decode_element(self._quote(this_entry)) else: val = repr(this_entry) - return '%s%s%s%s%s' % (indent_string, - self._decode_element(self._quote(entry, multiline=False)), - self._a_to_u(' = '), - val, - self._decode_element(comment)) + return f"{indent_string}{self._decode_element(self._quote(entry, multiline=False))}{self._a_to_u(' = ')}{val}{self._decode_element(comment)}" def _write_marker(self, indent_string, depth, entry, comment): """Write a section marker line""" - return '%s%s%s%s%s' % (indent_string, - self._a_to_u('[' * depth), - self._quote(self._decode_element(entry), multiline=False), - self._a_to_u(']' * depth), - self._decode_element(comment)) + return f"{indent_string}{self._a_to_u('[' * depth)}{self._quote(self._decode_element(entry), multiline=False)}{self._a_to_u(']' * depth)}{self._decode_element(comment)}" def _handle_comment(self, comment): @@ -2111,7 +2101,7 @@ class ConfigObj(Section): if not output.endswith(newline): output += newline - if isinstance(output, six.binary_type): + if isinstance(output, bytes): output_bytes = output else: output_bytes = output.encode(self.encoding or @@ -2284,7 +2274,7 @@ class ConfigObj(Section): out[entry] = False else: ret_false = False - msg = 'Value %r was provided as a section' % entry + msg = f'Value {entry!r} was provided as a section' out[entry] = validator.baseErrorClass(msg) for entry in incorrect_sections: ret_true = False @@ -2292,7 +2282,7 @@ class ConfigObj(Section): out[entry] = False else: ret_false = False - msg = 'Section %r was provided as a single value' % entry + msg = f'Section {entry!r} was provided as a single value' out[entry] = validator.baseErrorClass(msg) # Missing sections will have been created as empty ones when the @@ -2353,7 +2343,7 @@ class ConfigObj(Section): This method raises a ``ReloadError`` if the ConfigObj doesn't have a filename attribute pointing to a file. """ - if not isinstance(self.filename, six.string_types): + if not isinstance(self.filename, str): raise ReloadError() filename = self.filename @@ -2372,7 +2362,7 @@ class ConfigObj(Section): -class SimpleVal(object): +class SimpleVal: """ A simple validator. Can be used to check that all members expected are present. diff --git a/RNS/vendor/i2plib/aiosam.py b/RNS/vendor/i2plib/aiosam.py index bbb2c4a..eccff10 100644 --- a/RNS/vendor/i2plib/aiosam.py +++ b/RNS/vendor/i2plib/aiosam.py @@ -11,7 +11,7 @@ def parse_reply(data): try: msg = sam.Message(data.decode().strip()) - logger.debug("SAM reply: "+str(msg)) + logger.debug(f"SAM reply: {msg}") except: raise ConnectionAbortedError("Invalid SAM response") @@ -89,7 +89,7 @@ async def create_session(session_name, sam_address=sam.DEFAULT_ADDRESS, :param options: (optional) A dict object with i2cp options :return: A (reader, writer) pair """ - logger.debug("Creating session {}".format(session_name)) + logger.debug(f"Creating session {session_name}") if destination: if type(destination) == sam.Destination: destination = destination @@ -101,7 +101,7 @@ async def create_session(session_name, sam_address=sam.DEFAULT_ADDRESS, else: dest_string = sam.TRANSIENT_DESTINATION - options = " ".join(["{}={}".format(k, v) for k, v in options.items()]) + options = " ".join([f"{k}={v}" for k, v in options.items()]) reader, writer = await get_sam_socket(sam_address, loop) writer.write(sam.session_create( @@ -113,7 +113,7 @@ async def create_session(session_name, sam_address=sam.DEFAULT_ADDRESS, destination = sam.Destination( reply["DESTINATION"], has_private_key=True) logger.debug(destination.base32) - logger.debug("Session created {}".format(session_name)) + logger.debug(f"Session created {session_name}") return (reader, writer) else: writer.close() @@ -129,7 +129,7 @@ async def stream_connect(session_name, destination, :param loop: (optional) Event loop instance :return: A (reader, writer) pair """ - logger.debug("Connecting stream {}".format(session_name)) + logger.debug(f"Connecting stream {session_name}") if isinstance(destination, str) and not destination.endswith(".i2p"): destination = sam.Destination(destination) elif isinstance(destination, str): @@ -140,7 +140,7 @@ async def stream_connect(session_name, destination, silent="false")) reply = parse_reply(await reader.readline()) if reply.ok: - logger.debug("Stream connected {}".format(session_name)) + logger.debug(f"Stream connected {session_name}") return (reader, writer) else: writer.close() diff --git a/RNS/vendor/i2plib/sam.py b/RNS/vendor/i2plib/sam.py index 1bad75d..dad8b76 100644 --- a/RNS/vendor/i2plib/sam.py +++ b/RNS/vendor/i2plib/sam.py @@ -23,7 +23,7 @@ TRANSIENT_DESTINATION = "TRANSIENT" VALID_BASE32_ADDRESS = re.compile(r"^([a-zA-Z0-9]{52}).b32.i2p$") VALID_BASE64_ADDRESS = re.compile(r"^([a-zA-Z0-9-~=]{516,528})$") -class Message(object): +class Message: """Parse SAM message to an object""" def __init__(self, s): self.opts = {} @@ -51,34 +51,30 @@ class Message(object): # SAM request messages def hello(min_version, max_version): - return "HELLO VERSION MIN={} MAX={}\n".format(min_version, - max_version).encode() + return f"HELLO VERSION MIN={min_version} MAX={max_version}\n".encode() def session_create(style, session_id, destination, options=""): - return "SESSION CREATE STYLE={} ID={} DESTINATION={} {}\n".format( - style, session_id, destination, options).encode() + return f"SESSION CREATE STYLE={style} ID={session_id} DESTINATION={destination} {options}\n".encode() def stream_connect(session_id, destination, silent="false"): - return "STREAM CONNECT ID={} DESTINATION={} SILENT={}\n".format( - session_id, destination, silent).encode() + return f"STREAM CONNECT ID={session_id} DESTINATION={destination} SILENT={silent}\n".encode() def stream_accept(session_id, silent="false"): - return "STREAM ACCEPT ID={} SILENT={}\n".format(session_id, silent).encode() + return f"STREAM ACCEPT ID={session_id} SILENT={silent}\n".encode() def stream_forward(session_id, port, options=""): - return "STREAM FORWARD ID={} PORT={} {}\n".format( - session_id, port, options).encode() + return f"STREAM FORWARD ID={session_id} PORT={port} {options}\n".encode() def naming_lookup(name): - return "NAMING LOOKUP NAME={}\n".format(name).encode() + return f"NAMING LOOKUP NAME={name}\n".encode() def dest_generate(signature_type): - return "DEST GENERATE SIGNATURE_TYPE={}\n".format(signature_type).encode() + return f"DEST GENERATE SIGNATURE_TYPE={signature_type}\n".encode() -class Destination(object): +class Destination: """I2P destination https://geti2p.net/spec/common-structures#destination @@ -101,7 +97,7 @@ class Destination(object): def __init__(self, data=None, path=None, has_private_key=False): #: Binary destination - self.data = bytes() + self.data = b'' #: Base64 encoded destination self.base64 = "" #: :class:`RNS.vendor.i2plib.PrivateKey` instance or None @@ -123,7 +119,7 @@ class Destination(object): self.base64 = data if type(data) == str else i2p_b64encode(data) def __repr__(self): - return "".format(self.base32) + return f"" @property def base32(self): @@ -131,7 +127,7 @@ class Destination(object): desthash = sha256(self.data).digest() return b32encode(desthash).decode()[:52].lower() -class PrivateKey(object): +class PrivateKey: """I2P private key https://geti2p.net/spec/common-structures#keysandcert diff --git a/RNS/vendor/i2plib/tunnel.py b/RNS/vendor/i2plib/tunnel.py index 9418dbe..aeb0f63 100644 --- a/RNS/vendor/i2plib/tunnel.py +++ b/RNS/vendor/i2plib/tunnel.py @@ -18,7 +18,7 @@ async def proxy_data(reader, writer): break writer.write(data) except Exception as e: - logger.debug('proxy_data_task exception {}'.format(e)) + logger.debug(f'proxy_data_task exception {e}') finally: try: writer.close() @@ -26,7 +26,7 @@ async def proxy_data(reader, writer): pass logger.debug('close connection') -class I2PTunnel(object): +class I2PTunnel: """Base I2P Tunnel object, not to be used directly :param local_address: A local address to use for a tunnel. @@ -141,9 +141,8 @@ class ServerTunnel(I2PTunnel): # data and dest may come in one chunk dest, data = incoming.split(b"\n", 1) remote_destination = sam.Destination(dest.decode()) - logger.debug("{} client connected: {}.b32.i2p".format( - self.session_name, remote_destination.base32)) - + logger.debug(f"{self.session_name} client connected: {remote_destination.base32}.b32.i2p") + except Exception as e: self.status["exception"] = e self.status["setup_failed"] = True diff --git a/RNS/vendor/i2plib/utils.py b/RNS/vendor/i2plib/utils.py index 3c59846..15c5c43 100644 --- a/RNS/vendor/i2plib/utils.py +++ b/RNS/vendor/i2plib/utils.py @@ -38,5 +38,5 @@ def generate_session_id(length=6): """Generate random session id""" rand = random.SystemRandom() sid = [rand.choice(string.ascii_letters) for _ in range(length)] - return "reticulum-" + "".join(sid) + return f"reticulum-{''.join(sid)}" diff --git a/RNS/vendor/ifaddr/__init__.py b/RNS/vendor/ifaddr/__init__.py index 7b10423..8ddd028 100644 --- a/RNS/vendor/ifaddr/__init__.py +++ b/RNS/vendor/ifaddr/__init__.py @@ -28,6 +28,6 @@ if os.name == "nt": elif os.name == "posix": from RNS.vendor.ifaddr._posix import get_adapters else: - raise RuntimeError("Unsupported Operating System: %s" % os.name) + raise RuntimeError(f"Unsupported Operating System: {os.name}") __all__ = ['Adapter', 'IP', 'get_adapters'] diff --git a/RNS/vendor/ifaddr/_posix.py b/RNS/vendor/ifaddr/_posix.py index 60ab3f8..bcf2223 100644 --- a/RNS/vendor/ifaddr/_posix.py +++ b/RNS/vendor/ifaddr/_posix.py @@ -79,7 +79,7 @@ def get_adapters(include_unconfigured: bool = False) -> Iterable[shared.Adapter] prefixlen = shared.ipv6_prefixlength(ipaddress.IPv6Address(netmaskStr)) else: assert netmask is not None, f'sockaddr_to_ip({addr[0].ifa_netmask}) returned None' - netmaskStr = str('0.0.0.0/' + netmask) + netmaskStr = str(f"0.0.0.0/{netmask}") prefixlen = ipaddress.IPv4Network(netmaskStr).prefixlen ip = shared.IP(ip_addr, prefixlen, name) add_ip(name, ip) diff --git a/RNS/vendor/ifaddr/_shared.py b/RNS/vendor/ifaddr/_shared.py index 42939d3..53dfc95 100644 --- a/RNS/vendor/ifaddr/_shared.py +++ b/RNS/vendor/ifaddr/_shared.py @@ -26,7 +26,7 @@ import platform from typing import List, Optional, Tuple, Union -class Adapter(object): +class Adapter: """ Represents a network interface device controller (NIC), such as a network card. An adapter can have multiple IPs. @@ -58,9 +58,7 @@ class Adapter(object): self.index = index def __repr__(self) -> str: - return "Adapter(name={name}, nice_name={nice_name}, ips={ips}, index={index})".format( - name=repr(self.name), nice_name=repr(self.nice_name), ips=repr(self.ips), index=repr(self.index) - ) + return f"Adapter(name={self.name!r}, nice_name={self.nice_name!r}, ips={self.ips!r}, index={self.index!r})" # Type of an IPv4 address (a string in "xxx.xxx.xxx.xxx" format) @@ -70,7 +68,7 @@ _IPv4Address = str _IPv6Address = Tuple[str, int, int] -class IP(object): +class IP: """ Represents an IP address of an adapter. """ @@ -112,9 +110,7 @@ class IP(object): return isinstance(self.ip, tuple) def __repr__(self) -> str: - return "IP(ip={ip}, network_prefix={network_prefix}, nice_name={nice_name})".format( - ip=repr(self.ip), network_prefix=repr(self.network_prefix), nice_name=repr(self.nice_name) - ) + return f"IP(ip={self.ip!r}, network_prefix={self.network_prefix!r}, nice_name={self.nice_name!r})" if platform.system() == "Darwin" or "BSD" in platform.system(): diff --git a/RNS/vendor/ifaddr/niwrapper.py b/RNS/vendor/ifaddr/niwrapper.py index 8167dc4..b7fc946 100644 --- a/RNS/vendor/ifaddr/niwrapper.py +++ b/RNS/vendor/ifaddr/niwrapper.py @@ -40,7 +40,7 @@ def ifaddresses(ifname) -> dict: for ip in a.ips: t = {} if ip.is_IPv4: - net = ipaddress.ip_network(str(ip.ip)+"/"+str(ip.network_prefix), strict=False) + net = ipaddress.ip_network(f"{ip.ip}/{ip.network_prefix}", strict=False) t["addr"] = ip.ip t["prefix"] = ip.network_prefix t["broadcast"] = str(net.broadcast_address) diff --git a/RNS/vendor/six.py b/RNS/vendor/six.py index 4e15675..5802034 100644 --- a/RNS/vendor/six.py +++ b/RNS/vendor/six.py @@ -20,7 +20,6 @@ """Utilities for writing code that runs on Python 2 and 3""" -from __future__ import absolute_import import functools import itertools @@ -57,7 +56,7 @@ else: MAXSIZE = int((1 << 31) - 1) else: # It's possible to have sizeof(long) != sizeof(Py_ssize_t). - class X(object): + class X: def __len__(self): return 1 << 31 @@ -88,7 +87,7 @@ def _import_module(name): return sys.modules[name] -class _LazyDescr(object): +class _LazyDescr: def __init__(self, name): self.name = name @@ -108,7 +107,7 @@ class _LazyDescr(object): class MovedModule(_LazyDescr): def __init__(self, name, old, new=None): - super(MovedModule, self).__init__(name) + super().__init__(name) if PY3: if new is None: new = name @@ -129,7 +128,7 @@ class MovedModule(_LazyDescr): class _LazyModule(types.ModuleType): def __init__(self, name): - super(_LazyModule, self).__init__(name) + super().__init__(name) self.__doc__ = self.__class__.__doc__ def __dir__(self): @@ -144,7 +143,7 @@ class _LazyModule(types.ModuleType): class MovedAttribute(_LazyDescr): def __init__(self, name, old_mod, new_mod, old_attr=None, new_attr=None): - super(MovedAttribute, self).__init__(name) + super().__init__(name) if PY3: if new_mod is None: new_mod = name @@ -166,7 +165,7 @@ class MovedAttribute(_LazyDescr): return getattr(module, self.attr) -class _SixMetaPathImporter(object): +class _SixMetaPathImporter: """ A meta path importer to import six.moves and its submodules. @@ -181,10 +180,10 @@ class _SixMetaPathImporter(object): def _add_module(self, mod, *fullnames): for fullname in fullnames: - self.known_modules[self.name + "." + fullname] = mod + self.known_modules[f"{self.name}.{fullname}"] = mod def _get_module(self, fullname): - return self.known_modules[self.name + "." + fullname] + return self.known_modules[f"{self.name}.{fullname}"] def find_module(self, fullname, path=None): if fullname in self.known_modules: @@ -200,7 +199,7 @@ class _SixMetaPathImporter(object): try: return self.known_modules[fullname] except KeyError: - raise ImportError("This loader does not know module " + fullname) + raise ImportError(f"This loader does not know module {fullname}") def load_module(self, fullname): try: @@ -312,9 +311,9 @@ _moved_attributes = [ MovedModule("tkinter_messagebox", "tkMessageBox", "tkinter.messagebox"), MovedModule("tkinter_tksimpledialog", "tkSimpleDialog", "tkinter.simpledialog"), - MovedModule("urllib_parse", __name__ + ".moves.urllib_parse", "urllib.parse"), - MovedModule("urllib_error", __name__ + ".moves.urllib_error", "urllib.error"), - MovedModule("urllib", __name__ + ".moves.urllib", __name__ + ".moves.urllib"), + MovedModule("urllib_parse", f"{__name__}.moves.urllib_parse", "urllib.parse"), + MovedModule("urllib_error", f"{__name__}.moves.urllib_error", "urllib.error"), + MovedModule("urllib", f"{__name__}.moves.urllib", f"{__name__}.moves.urllib"), MovedModule("urllib_robotparser", "robotparser", "urllib.robotparser"), MovedModule("xmlrpc_client", "xmlrpclib", "xmlrpc.client"), MovedModule("xmlrpc_server", "SimpleXMLRPCServer", "xmlrpc.server"), @@ -328,12 +327,12 @@ if sys.platform == "win32": for attr in _moved_attributes: setattr(_MovedItems, attr.name, attr) if isinstance(attr, MovedModule): - _importer._add_module(attr, "moves." + attr.name) + _importer._add_module(attr, f"moves.{attr.name}") del attr _MovedItems._moved_attributes = _moved_attributes -moves = _MovedItems(__name__ + ".moves") +moves = _MovedItems(f"{__name__}.moves") _importer._add_module(moves, "moves") @@ -375,7 +374,7 @@ del attr Module_six_moves_urllib_parse._moved_attributes = _urllib_parse_moved_attributes -_importer._add_module(Module_six_moves_urllib_parse(__name__ + ".moves.urllib_parse"), +_importer._add_module(Module_six_moves_urllib_parse(f"{__name__}.moves.urllib_parse"), "moves.urllib_parse", "moves.urllib.parse") @@ -395,7 +394,7 @@ del attr Module_six_moves_urllib_error._moved_attributes = _urllib_error_moved_attributes -_importer._add_module(Module_six_moves_urllib_error(__name__ + ".moves.urllib.error"), +_importer._add_module(Module_six_moves_urllib_error(f"{__name__}.moves.urllib.error"), "moves.urllib_error", "moves.urllib.error") @@ -447,7 +446,7 @@ del attr Module_six_moves_urllib_request._moved_attributes = _urllib_request_moved_attributes -_importer._add_module(Module_six_moves_urllib_request(__name__ + ".moves.urllib.request"), +_importer._add_module(Module_six_moves_urllib_request(f"{__name__}.moves.urllib.request"), "moves.urllib_request", "moves.urllib.request") @@ -468,7 +467,7 @@ del attr Module_six_moves_urllib_response._moved_attributes = _urllib_response_moved_attributes -_importer._add_module(Module_six_moves_urllib_response(__name__ + ".moves.urllib.response"), +_importer._add_module(Module_six_moves_urllib_response(f"{__name__}.moves.urllib.response"), "moves.urllib_response", "moves.urllib.response") @@ -486,7 +485,7 @@ del attr Module_six_moves_urllib_robotparser._moved_attributes = _urllib_robotparser_moved_attributes -_importer._add_module(Module_six_moves_urllib_robotparser(__name__ + ".moves.urllib.robotparser"), +_importer._add_module(Module_six_moves_urllib_robotparser(f"{__name__}.moves.urllib.robotparser"), "moves.urllib_robotparser", "moves.urllib.robotparser") @@ -503,7 +502,7 @@ class Module_six_moves_urllib(types.ModuleType): def __dir__(self): return ['parse', 'error', 'request', 'response', 'robotparser'] -_importer._add_module(Module_six_moves_urllib(__name__ + ".moves.urllib"), +_importer._add_module(Module_six_moves_urllib(f"{__name__}.moves.urllib"), "moves.urllib") @@ -520,7 +519,7 @@ def remove_move(name): try: del moves.__dict__[name] except KeyError: - raise AttributeError("no such move, %r" % (name,)) + raise AttributeError(f"no such move, {name!r}") if PY3: @@ -576,7 +575,7 @@ else: def create_unbound_method(func, cls): return types.MethodType(func, None, cls) - class Iterator(object): + class Iterator: def next(self): return type(self).__next__(self) @@ -910,7 +909,7 @@ def ensure_binary(s, encoding='utf-8', errors='strict'): return s if isinstance(s, text_type): return s.encode(encoding, errors) - raise TypeError("not expecting type '%s'" % type(s)) + raise TypeError(f"not expecting type '{type(s)}'") def ensure_str(s, encoding='utf-8', errors='strict'): @@ -932,7 +931,7 @@ def ensure_str(s, encoding='utf-8', errors='strict'): elif PY3 and isinstance(s, binary_type): return s.decode(encoding, errors) elif not isinstance(s, (text_type, binary_type)): - raise TypeError("not expecting type '%s'" % type(s)) + raise TypeError(f"not expecting type '{type(s)}'") return s @@ -952,7 +951,7 @@ def ensure_text(s, encoding='utf-8', errors='strict'): elif isinstance(s, text_type): return s else: - raise TypeError("not expecting type '%s'" % type(s)) + raise TypeError(f"not expecting type '{type(s)}'") def python_2_unicode_compatible(klass): @@ -965,9 +964,7 @@ def python_2_unicode_compatible(klass): """ if PY2: if '__str__' not in klass.__dict__: - raise ValueError("@python_2_unicode_compatible cannot be applied " - "to %s because it doesn't define __str__()." % - klass.__name__) + raise ValueError(f"@python_2_unicode_compatible cannot be applied to {klass.__name__} because it doesn't define __str__().") klass.__unicode__ = klass.__str__ klass.__str__ = lambda self: self.__unicode__().encode('utf-8') return klass diff --git a/RNS/vendor/umsgpack.py b/RNS/vendor/umsgpack.py index c6fa1e7..939a6eb 100644 --- a/RNS/vendor/umsgpack.py +++ b/RNS/vendor/umsgpack.py @@ -52,7 +52,7 @@ import io if sys.version_info[0:2] >= (3, 3): from collections.abc import Hashable else: - from collections import Hashable + from collections.abc import Hashable __version__ = "2.7.1" "Module version string" @@ -66,7 +66,7 @@ version = (2, 7, 1) ############################################################################## # Extension type for application-defined types and data -class Ext(object): +class Ext: """ The Ext class facilitates creating a serializable extension object to store an application-defined type and data byte array. @@ -100,7 +100,7 @@ class Ext(object): if not isinstance(type, int): raise TypeError("ext type is not type integer") elif not (-2**7 <= type <= 2**7 - 1): - raise ValueError("ext type value {:d} is out of range (-128 to 127)".format(type)) + raise ValueError(f"ext type value {type} is out of range (-128 to 127)") # Check data is type bytes or str elif sys.version_info[0] == 3 and not isinstance(data, bytes): raise TypeError("ext data is not type \'bytes\'") @@ -127,8 +127,8 @@ class Ext(object): """ String representation of this Ext object. """ - s = "Ext Object (Type: {:d}, Data: ".format(self.type) - s += " ".join(["0x{:02}".format(ord(self.data[i:i + 1])) + s = f"Ext Object (Type: {self.type}, Data: " + s += " ".join([f"0x{ord(self.data[i:i + 1]):02}" for i in xrange(min(len(self.data), 8))]) if len(self.data) > 8: s += " ..." @@ -177,11 +177,11 @@ def ext_serializable(ext_type): if not isinstance(ext_type, int): raise TypeError("Ext type is not type integer") elif not (-2**7 <= ext_type <= 2**7 - 1): - raise ValueError("Ext type value {:d} is out of range of -128 to 127".format(ext_type)) + raise ValueError(f"Ext type value {ext_type} is out of range of -128 to 127") elif ext_type in _ext_type_to_class: - raise ValueError("Ext type {:d} already registered with class {:s}".format(ext_type, repr(_ext_type_to_class[ext_type]))) + raise ValueError(f"Ext type {ext_type} already registered with class {_ext_type_to_class[ext_type]!r}") elif cls in _ext_class_to_type: - raise ValueError("Class {:s} already registered with Ext type {:d}".format(repr(cls), ext_type)) + raise ValueError(f"Class {cls!r} already registered with Ext type {ext_type}") _ext_type_to_class[ext_type] = cls _ext_class_to_type[cls] = ext_type @@ -495,7 +495,7 @@ def _pack2(obj, fp, **options): try: _pack_ext(Ext(_ext_class_to_type[obj.__class__], obj.packb()), fp, options) except AttributeError: - raise NotImplementedError("Ext serializable class {:s} is missing implementation of packb()".format(repr(obj.__class__))) + raise NotImplementedError(f"Ext serializable class {obj.__class__!r} is missing implementation of packb()") elif isinstance(obj, bool): _pack_boolean(obj, fp, options) elif isinstance(obj, (int, long)): @@ -525,7 +525,7 @@ def _pack2(obj, fp, **options): _pack_ext(ext_handlers[t](obj), fp, options) else: raise UnsupportedTypeException( - "unsupported type: {:s}".format(str(type(obj)))) + f"unsupported type: {type(obj)}") elif _ext_class_to_type: # Linear search for superclass t = next((t for t in _ext_class_to_type if isinstance(obj, t)), None) @@ -533,11 +533,11 @@ def _pack2(obj, fp, **options): try: _pack_ext(Ext(_ext_class_to_type[t], obj.packb()), fp, options) except AttributeError: - raise NotImplementedError("Ext serializable class {:s} is missing implementation of packb()".format(repr(t))) + raise NotImplementedError(f"Ext serializable class {t!r} is missing implementation of packb()") else: - raise UnsupportedTypeException("unsupported type: {:s}".format(str(type(obj)))) + raise UnsupportedTypeException(f"unsupported type: {type(obj)}") else: - raise UnsupportedTypeException("unsupported type: {:s}".format(str(type(obj)))) + raise UnsupportedTypeException(f"unsupported type: {type(obj)}") # Pack for Python 3, with unicode 'str' type, 'bytes' type, and no 'long' type @@ -582,7 +582,7 @@ def _pack3(obj, fp, **options): try: _pack_ext(Ext(_ext_class_to_type[obj.__class__], obj.packb()), fp, options) except AttributeError: - raise NotImplementedError("Ext serializable class {:s} is missing implementation of packb()".format(repr(obj.__class__))) + raise NotImplementedError(f"Ext serializable class {obj.__class__!r} is missing implementation of packb()") elif isinstance(obj, bool): _pack_boolean(obj, fp, options) elif isinstance(obj, int): @@ -612,7 +612,7 @@ def _pack3(obj, fp, **options): _pack_ext(ext_handlers[t](obj), fp, options) else: raise UnsupportedTypeException( - "unsupported type: {:s}".format(str(type(obj)))) + f"unsupported type: {type(obj)}") elif _ext_class_to_type: # Linear search for superclass t = next((t for t in _ext_class_to_type if isinstance(obj, t)), None) @@ -620,12 +620,12 @@ def _pack3(obj, fp, **options): try: _pack_ext(Ext(_ext_class_to_type[t], obj.packb()), fp, options) except AttributeError: - raise NotImplementedError("Ext serializable class {:s} is missing implementation of packb()".format(repr(t))) + raise NotImplementedError(f"Ext serializable class {t!r} is missing implementation of packb()") else: - raise UnsupportedTypeException("unsupported type: {:s}".format(str(type(obj)))) + raise UnsupportedTypeException(f"unsupported type: {type(obj)}") else: raise UnsupportedTypeException( - "unsupported type: {:s}".format(str(type(obj)))) + f"unsupported type: {type(obj)}") def _packb2(obj, **options): @@ -737,21 +737,21 @@ def _unpack_integer(code, fp, options): return struct.unpack(">I", _read_except(fp, 4))[0] elif code == b'\xcf': return struct.unpack(">Q", _read_except(fp, 8))[0] - raise Exception("logic error, not int: 0x{:02x}".format(ord(code))) + raise Exception(f"logic error, not int: 0x{ord(code):02x}") def _unpack_reserved(code, fp, options): if code == b'\xc1': raise ReservedCodeException( - "encountered reserved code: 0x{:02x}".format(ord(code))) + f"encountered reserved code: 0x{ord(code):02x}") raise Exception( - "logic error, not reserved code: 0x{:02x}".format(ord(code))) + f"logic error, not reserved code: 0x{ord(code):02x}") def _unpack_nil(code, fp, options): if code == b'\xc0': return None - raise Exception("logic error, not nil: 0x{:02x}".format(ord(code))) + raise Exception(f"logic error, not nil: 0x{ord(code):02x}") def _unpack_boolean(code, fp, options): @@ -759,7 +759,7 @@ def _unpack_boolean(code, fp, options): return False elif code == b'\xc3': return True - raise Exception("logic error, not boolean: 0x{:02x}".format(ord(code))) + raise Exception(f"logic error, not boolean: 0x{ord(code):02x}") def _unpack_float(code, fp, options): @@ -767,7 +767,7 @@ def _unpack_float(code, fp, options): return struct.unpack(">f", _read_except(fp, 4))[0] elif code == b'\xcb': return struct.unpack(">d", _read_except(fp, 8))[0] - raise Exception("logic error, not float: 0x{:02x}".format(ord(code))) + raise Exception(f"logic error, not float: 0x{ord(code):02x}") def _unpack_string(code, fp, options): @@ -780,7 +780,7 @@ def _unpack_string(code, fp, options): elif code == b'\xdb': length = struct.unpack(">I", _read_except(fp, 4))[0] else: - raise Exception("logic error, not string: 0x{:02x}".format(ord(code))) + raise Exception(f"logic error, not string: 0x{ord(code):02x}") # Always return raw bytes in compatibility mode global compatibility @@ -804,7 +804,7 @@ def _unpack_binary(code, fp, options): elif code == b'\xc6': length = struct.unpack(">I", _read_except(fp, 4))[0] else: - raise Exception("logic error, not binary: 0x{:02x}".format(ord(code))) + raise Exception(f"logic error, not binary: 0x{ord(code):02x}") return _read_except(fp, length) @@ -827,7 +827,7 @@ def _unpack_ext(code, fp, options): elif code == b'\xc9': length = struct.unpack(">I", _read_except(fp, 4))[0] else: - raise Exception("logic error, not ext: 0x{:02x}".format(ord(code))) + raise Exception(f"logic error, not ext: 0x{ord(code):02x}") ext_type = struct.unpack("b", _read_except(fp, 1))[0] ext_data = _read_except(fp, length) @@ -842,7 +842,7 @@ def _unpack_ext(code, fp, options): try: return _ext_type_to_class[ext_type].unpackb(ext_data) except AttributeError: - raise NotImplementedError("Ext serializable class {:s} is missing implementation of unpackb()".format(repr(_ext_type_to_class[ext_type]))) + raise NotImplementedError(f"Ext serializable class {_ext_type_to_class[ext_type]!r} is missing implementation of unpackb()") # Timestamp extension if ext_type == -1: @@ -868,7 +868,7 @@ def _unpack_ext_timestamp(ext_data, options): microseconds = struct.unpack(">I", ext_data[0:4])[0] // 1000 else: raise UnsupportedTimestampException( - "unsupported timestamp with data length {:d}".format(len(ext_data))) + f"unsupported timestamp with data length {len(ext_data)}") return _epoch + datetime.timedelta(seconds=seconds, microseconds=microseconds) @@ -882,10 +882,10 @@ def _unpack_array(code, fp, options): elif code == b'\xdd': length = struct.unpack(">I", _read_except(fp, 4))[0] else: - raise Exception("logic error, not array: 0x{:02x}".format(ord(code))) + raise Exception(f"logic error, not array: 0x{ord(code):02x}") if options.get('use_tuple'): - return tuple((_unpack(fp, options) for i in xrange(length))) + return tuple(_unpack(fp, options) for i in xrange(length)) return [_unpack(fp, options) for i in xrange(length)] @@ -904,7 +904,7 @@ def _unpack_map(code, fp, options): elif code == b'\xdf': length = struct.unpack(">I", _read_except(fp, 4))[0] else: - raise Exception("logic error, not map: 0x{:02x}".format(ord(code))) + raise Exception(f"logic error, not map: 0x{ord(code):02x}") d = {} if not options.get('use_ordered_dict') else collections.OrderedDict() for _ in xrange(length): @@ -916,10 +916,10 @@ def _unpack_map(code, fp, options): k = _deep_list_to_tuple(k) elif not isinstance(k, Hashable): raise UnhashableKeyException( - "encountered unhashable key: \"{:s}\" ({:s})".format(str(k), str(type(k)))) + f"encountered unhashable key: \"{k}\" ({type(k)})") elif k in d: raise DuplicateKeyException( - "encountered duplicate key: \"{:s}\" ({:s})".format(str(k), str(type(k)))) + f"encountered duplicate key: \"{k}\" ({type(k)})") # Unpack value v = _unpack(fp, options) @@ -928,7 +928,7 @@ def _unpack_map(code, fp, options): d[k] = v except TypeError: raise UnhashableKeyException( - "encountered unhashable key: \"{:s}\"".format(str(k))) + f"encountered unhashable key: \"{k}\"") return d diff --git a/docs/source/conf.py b/docs/source/conf.py index 00bff97..3b0d583 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -13,12 +13,12 @@ project = 'Reticulum Network Stack' copyright = '2023, Mark Qvist' author = 'Mark Qvist' -exec(open("../../RNS/_version.py", "r").read()) +exec(open("../../RNS/_version.py").read()) version = __version__ # The full version, including alpha/beta/rc tags import RNS -release = RNS._version.__version__+" beta" +release = f"{RNS._version.__version__} beta" # -- General configuration --------------------------------------------------- extensions = [ diff --git a/setup.py b/setup.py index 7fca04f..f3c1a5c 100644 --- a/setup.py +++ b/setup.py @@ -9,14 +9,14 @@ if '--pure' in sys.argv: sys.argv.remove('--pure') print("Building pure-python wheel") -exec(open("RNS/_version.py", "r").read()) -with open("README.md", "r") as fh: +exec(open("RNS/_version.py").read()) +with open("README.md") as fh: long_description = fh.read() if pure_python: pkg_name = "rnspure" requirements = [] - long_description = long_description.replace("

", "

"+pure_notice) + long_description = long_description.replace("

", f"

{pure_notice}") else: pkg_name = "rns" requirements = ['cryptography>=3.4.7', 'pyserial>=3.5'] diff --git a/tests/channel.py b/tests/channel.py index d74434e..85e7217 100644 --- a/tests/channel.py +++ b/tests/channel.py @@ -145,7 +145,7 @@ class SystemMessage(MessageBase): MSGTYPE = 0xf000 def pack(self) -> bytes: - return bytes() + return b'' def unpack(self, raw): pass @@ -160,7 +160,7 @@ class ProtocolHarness(contextlib.AbstractContextManager): def cleanup(self): self.channel._shutdown() - def __exit__(self, __exc_type: typing.Type[BaseException], __exc_value: BaseException, + def __exit__(self, __exc_type: type[BaseException], __exc_value: BaseException, __traceback: types.TracebackType) -> bool: # self._log.debug(f"__exit__({__exc_type}, {__exc_value}, {__traceback})") self.cleanup() @@ -431,7 +431,7 @@ class TestChannel(unittest.TestCase): self.assertEqual(len(data), count) read_finished = False - result = bytes() + result = b'' def read_thread(): nonlocal read_finished, result diff --git a/tests/hashes.py b/tests/hashes.py index eb9f2e2..0ef349a 100644 --- a/tests/hashes.py +++ b/tests/hashes.py @@ -11,22 +11,22 @@ class TestSHA256(unittest.TestCase): def test_empty(self): self.assertEqual( - self.f(''.encode("utf-8")), + self.f(b''), bytes.fromhex("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855")) def test_less_than_block_length(self): self.assertEqual( - self.f('abc'.encode("utf-8")), + self.f(b'abc'), bytes.fromhex("ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad")) def test_block_length(self): self.assertEqual( - self.f('a'.encode("utf-8")*64), + self.f(b'a'*64), bytes.fromhex("ffe054fe7ae0cb6dc65c3af9b61d5209f439851db43d0ba5997337df154668eb")) def test_several_blocks(self): self.assertEqual( - self.f('a'.encode("utf-8")*1000000), + self.f(b'a'*1000000), bytes.fromhex("cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0")) def test_random_blocks(self): @@ -49,10 +49,10 @@ class TestSHA256(unittest.TestCase): if (i%1000 == 0): gbytes = round(b/1000000000,3) mbps = round((b*8/1000000)/(time.time()-start), 2) - print(str(i)+" rounds OK, total data: "+str(gbytes)+"GB, "+str(mbps)+"mbps") + print(f"{i} rounds OK, total data: {gbytes}GB, {mbps}mbps") if not ok: - print("Failed at round "+str(i)) + print(f"Failed at round {i}") else: print("SHA-256 test OK") @@ -65,25 +65,25 @@ class TestSHA512(unittest.TestCase): def test_empty(self): self.assertEqual( - self.f(''.encode("utf-8")), + self.f(b''), bytes.fromhex( 'cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce'+ '47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e')) def test_less_than_block_length(self): - self.assertEqual(self.f('abc'.encode("utf-8")), + self.assertEqual(self.f(b'abc'), bytes.fromhex( 'ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a'+ '2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f')) def test_block_length(self): - self.assertEqual(self.f('a'.encode("utf-8")*128), + self.assertEqual(self.f(b'a'*128), bytes.fromhex( 'b73d1929aa615934e61a871596b3f3b33359f42b8175602e89f7e06e5f658a24'+ '3667807ed300314b95cacdd579f3e33abdfbe351909519a846d465c59582f321')) def test_several_blocks(self): - self.assertEqual(self.f('a'.encode("utf-8")*1000000), + self.assertEqual(self.f(b'a'*1000000), bytes.fromhex( 'e718483d0ce769644e2e42c7bc15b4638e1f98b13b2044285632a803afa973eb'+ 'de0ff244877ea60a4cb0432ce577c31beb009c5c2c49aa2e4eadb217ad8cc09b')) @@ -108,10 +108,10 @@ class TestSHA512(unittest.TestCase): if (i%1000 == 0): gbytes = round(b/1000000000,3) mbps = round((b*8/1000000)/(time.time()-start), 2) - print(str(i)+" rounds OK, total data: "+str(gbytes)+"GB, "+str(mbps)+"mbps") + print(f"{i} rounds OK, total data: {gbytes}GB, {mbps}mbps") if not ok: - print("Failed at round "+str(i)) + print(f"Failed at round {i}") else: print("SHA-512 test OK") diff --git a/tests/identity.py b/tests/identity.py index af9230e..9f66a10 100644 --- a/tests/identity.py +++ b/tests/identity.py @@ -62,8 +62,8 @@ class TestIdentity(unittest.TestCase): tmdev = tmax - tmin mpct = (tmax/tmed)*100 print("Random messages:") - print(" Signature timing min/avg/med/max/mdev: "+str(round(tmin, 3))+"/"+str(round(tmean, 3))+"/"+str(round(tmed, 3))+"/"+str(round(tmax, 3))+"/"+str(round(tmdev, 3))) - print(" Max deviation from median: "+str(round(mpct, 1))+"%") + print(f" Signature timing min/avg/med/max/mdev: {round(tmin, 3)}/{round(tmean, 3)}/{round(tmed, 3)}/{round(tmax, 3)}/{round(tmdev, 3)}") + print(f" Max deviation from median: {round(mpct, 1)}%") print() id1 = RNS.Identity() @@ -85,8 +85,8 @@ class TestIdentity(unittest.TestCase): tmdev = tmax - tmin mpct = (tmax/tmed)*100 print("All 0xff messages:") - print(" Signature timing min/avg/med/max/mdev: "+str(round(tmin, 3))+"/"+str(round(tmean, 3))+"/"+str(round(tmed, 3))+"/"+str(round(tmax, 3))+"/"+str(round(tmdev, 3))) - print(" Max deviation from median: "+str(round(mpct, 1))+"%") + print(f" Signature timing min/avg/med/max/mdev: {round(tmin, 3)}/{round(tmean, 3)}/{round(tmed, 3)}/{round(tmax, 3)}/{round(tmdev, 3)}") + print(f" Max deviation from median: {round(mpct, 1)}%") print() id1 = RNS.Identity() @@ -108,8 +108,8 @@ class TestIdentity(unittest.TestCase): tmdev = tmax - tmin mpct = (tmax/tmed)*100 print("All 0x00 messages:") - print(" Signature timing min/avg/med/max/mdev: "+str(round(tmin, 3))+"/"+str(round(tmean, 3))+"/"+str(round(tmed, 3))+"/"+str(round(tmax, 3))+"/"+str(round(tmdev, 3))) - print(" Max deviation from median: "+str(round(mpct, 1))+"%") + print(f" Signature timing min/avg/med/max/mdev: {round(tmin, 3)}/{round(tmean, 3)}/{round(tmed, 3)}/{round(tmax, 3)}/{round(tmdev, 3)}") + print(f" Max deviation from median: {round(mpct, 1)}%") print() b = 0 @@ -127,7 +127,7 @@ class TestIdentity(unittest.TestCase): self.assertEqual(True, id2.validate(signature, msg)) t += time.time() - start - print("Sign/validate chunks < MTU: "+self.size_str(b/t, "b")+"ps") + print(f"Sign/validate chunks < MTU: {self.size_str(b / t, 'b')}ps") for i in range(1, 500): mlen = 16*1024 @@ -142,7 +142,7 @@ class TestIdentity(unittest.TestCase): self.assertEqual(True, id2.validate(signature, msg)) t += time.time() - start - print("Sign/validate 16KB chunks: "+self.size_str(b/t, "b")+"ps") + print(f"Sign/validate 16KB chunks: {self.size_str(b / t, 'b')}ps") def test_2_encrypt(self): @@ -176,8 +176,8 @@ class TestIdentity(unittest.TestCase): self.assertEqual(msg, decrypted) d_t += time.time() - d_start - print("Encrypt chunks < MTU: "+self.size_str(b/e_t, "b")+"ps") - print("Decrypt chunks < MTU: "+self.size_str(b/d_t, "b")+"ps") + print(f"Encrypt chunks < MTU: {self.size_str(b / e_t, 'b')}ps") + print(f"Decrypt chunks < MTU: {self.size_str(b / d_t, 'b')}ps") print("") # Test encrypt and decrypt of large chunks @@ -203,8 +203,8 @@ class TestIdentity(unittest.TestCase): self.assertEqual(msg, id1.decrypt(token)) d_t += time.time() - d_start - print("Encrypt "+self.size_str(mlen)+" chunks: "+self.size_str(b/e_t, "b")+"ps") - print("Decrypt "+self.size_str(mlen)+" chunks: "+self.size_str(b/d_t, "b")+"ps") + print(f"Encrypt {self.size_str(mlen)} chunks: {self.size_str(b / e_t, 'b')}ps") + print(f"Decrypt {self.size_str(mlen)} chunks: {self.size_str(b / d_t, 'b')}ps") def size_str(self, num, suffix='B'): units = ['','K','M','G','T','P','E','Z'] @@ -218,12 +218,12 @@ class TestIdentity(unittest.TestCase): for unit in units: if abs(num) < 1000.0: if unit == "": - return "%.0f %s%s" % (num, unit, suffix) + return f"{num:.0f} {unit}{suffix}" else: - return "%.2f %s%s" % (num, unit, suffix) + return f"{num:.2f} {unit}{suffix}" num /= 1000.0 - return "%.2f%s%s" % (num, last_unit, suffix) + return f"{num:.2f}{last_unit}{suffix}" if __name__ == '__main__': unittest.main(verbosity=2) diff --git a/tests/link.py b/tests/link.py index 5cc8ca3..1713df7 100644 --- a/tests/link.py +++ b/tests/link.py @@ -28,7 +28,7 @@ BUFFER_TEST_TARGET = 32000 def targets_job(caller): cmd = "python -c \"from tests.link import targets; targets()\"" - print("Opening subprocess for "+str(cmd)+"...", RNS.LOG_VERBOSE) + print(f"Opening subprocess for {cmd}...", RNS.LOG_VERBOSE) ppath = os.getcwd() try: @@ -144,7 +144,7 @@ class TestLink(unittest.TestCase): packet_size = RNS.Link.MDU pstart = time.time() - print("Sending "+str(num_packets)+" link packets of "+str(packet_size)+" bytes...") + print(f"Sending {num_packets} link packets of {packet_size} bytes...") for i in range(0, num_packets): time.sleep(0.003) b += packet_size @@ -154,7 +154,7 @@ class TestLink(unittest.TestCase): receipts.append(p.send()) pr_t += time.time() - start - print("Sent "+self.size_str(b)+", "+self.size_str(b/pr_t, "b")+"ps") + print(f"Sent {self.size_str(b)}, {self.size_str(b / pr_t, 'b')}ps") print("Checking receipts...", end=" ") all_ok = False @@ -175,11 +175,11 @@ class TestLink(unittest.TestCase): if n_failed > 0: ns = "s" if n_failed != 1 else "" - print("Failed to receive proof for "+str(n_failed)+" packet"+ns) + print(f"Failed to receive proof for {n_failed} packet{ns}") self.assertEqual(all_ok, True) print("OK!") - print("Single packet and proof round-trip throughput is "+self.size_str(b/pduration, "b")+"ps") + print(f"Single packet and proof round-trip throughput is {self.size_str(b / pduration, 'b')}ps") l1.teardown() time.sleep(0.5) @@ -209,7 +209,7 @@ class TestLink(unittest.TestCase): resource_timeout = 120 resource_size = 128 data = os.urandom(resource_size) - print("Sending "+self.size_str(resource_size)+" resource...") + print(f"Sending {self.size_str(resource_size)} resource...") resource = RNS.Resource(data, l1, timeout=resource_timeout) start = time.time() @@ -219,7 +219,7 @@ class TestLink(unittest.TestCase): t = time.time() - start self.assertEqual(resource.status, RNS.Resource.COMPLETE) - print("Resource completed at "+self.size_str(resource_size/t, "b")+"ps") + print(f"Resource completed at {self.size_str(resource_size / t, 'b')}ps") l1.teardown() time.sleep(0.5) @@ -249,7 +249,7 @@ class TestLink(unittest.TestCase): resource_timeout = 120 resource_size = 256*1000 data = os.urandom(resource_size) - print("Sending "+self.size_str(resource_size)+" resource...") + print(f"Sending {self.size_str(resource_size)} resource...") resource = RNS.Resource(data, l1, timeout=resource_timeout) start = time.time() @@ -259,7 +259,7 @@ class TestLink(unittest.TestCase): t = time.time() - start self.assertEqual(resource.status, RNS.Resource.COMPLETE) - print("Resource completed at "+self.size_str(resource_size/t, "b")+"ps") + print(f"Resource completed at {self.size_str(resource_size / t, 'b')}ps") l1.teardown() time.sleep(0.5) @@ -288,7 +288,7 @@ class TestLink(unittest.TestCase): resource_timeout = 120 resource_size = 1000*1000 data = os.urandom(resource_size) - print("Sending "+self.size_str(resource_size)+" resource...") + print(f"Sending {self.size_str(resource_size)} resource...") resource = RNS.Resource(data, l1, timeout=resource_timeout) start = time.time() @@ -298,7 +298,7 @@ class TestLink(unittest.TestCase): t = time.time() - start self.assertEqual(resource.status, RNS.Resource.COMPLETE) - print("Resource completed at "+self.size_str(resource_size/t, "b")+"ps") + print(f"Resource completed at {self.size_str(resource_size / t, 'b')}ps") l1.teardown() time.sleep(0.5) @@ -332,7 +332,7 @@ class TestLink(unittest.TestCase): resource_timeout = 120 resource_size = 5*1000*1000 data = os.urandom(resource_size) - print("Sending "+self.size_str(resource_size)+" resource...") + print(f"Sending {self.size_str(resource_size)} resource...") resource = RNS.Resource(data, l1, timeout=resource_timeout) start = time.time() @@ -342,7 +342,7 @@ class TestLink(unittest.TestCase): t = time.time() - start self.assertEqual(resource.status, RNS.Resource.COMPLETE) - print("Resource completed at "+self.size_str(resource_size/t, "b")+"ps") + print(f"Resource completed at {self.size_str(resource_size / t, 'b')}ps") l1.teardown() time.sleep(0.5) @@ -379,7 +379,7 @@ class TestLink(unittest.TestCase): resource_timeout = 120 resource_size = 50*1000*1000 data = os.urandom(resource_size) - print("Sending "+self.size_str(resource_size)+" resource...") + print(f"Sending {self.size_str(resource_size)} resource...") resource = RNS.Resource(data, l1, timeout=resource_timeout, callback=self.lr_callback) start = time.time() @@ -389,7 +389,7 @@ class TestLink(unittest.TestCase): t = time.time() - start self.assertEqual(TestLink.large_resource_status, RNS.Resource.COMPLETE) - print("Resource completed at "+self.size_str(resource_size/t, "b")+"ps") + print(f"Resource completed at {self.size_str(resource_size / t, 'b')}ps") l1.teardown() time.sleep(0.5) @@ -478,7 +478,7 @@ class TestLink(unittest.TestCase): channel = l1.get_channel() buffer = RNS.Buffer.create_bidirectional_buffer(0, 0, channel, handle_data) - buffer.write("Hi there".encode("utf-8")) + buffer.write(b"Hi there") buffer.flush() time.sleep(0.5) @@ -508,7 +508,7 @@ class TestLink(unittest.TestCase): if local_bitrate is not None: local_interface.bitrate = local_bitrate local_interface._force_bitrate = True - print("Forcing local bitrate of " + str(local_bitrate) + " bps (" + str(round(local_bitrate/8, 0)) + " B/s)") + print(f"Forcing local bitrate of {local_bitrate} bps ({round(local_bitrate / 8, 0)} B/s)") # TODO: Load this from public bytes only id1 = RNS.Identity.from_bytes(bytes.fromhex(fixed_keys[0][0])) @@ -525,7 +525,7 @@ class TestLink(unittest.TestCase): # delay a reasonable time for link to come up at current bitrate link_sleep = max(RNS.Link.MDU * 3 / local_interface.bitrate * 8, 2) timeout_at = time.time() + link_sleep - print("Waiting " + str(round(link_sleep, 1)) + " sec for link to come up") + print(f"Waiting {round(link_sleep, 1)} sec for link to come up") while l1.status != RNS.Link.ACTIVE and time.time() < timeout_at: time.sleep(0.01) @@ -564,14 +564,14 @@ class TestLink(unittest.TestCase): expected_rx_message = b"" for i in range(0, len(message)): if i > 0 and (i % StreamDataMessage.MAX_DATA_LEN) == 0: - expected_rx_message += " back at you".encode("utf-8") + expected_rx_message += b" back at you" expected_rx_message += bytes([message[i]]) - expected_rx_message += " back at you".encode("utf-8") + expected_rx_message += b" back at you" # since the segments will be received at max length for a # StreamDataMessage, the appended text will end up in a # separate packet. - print("Sending " + str(len(message)) + " bytes, receiving " + str(len(expected_rx_message)) + " bytes, ") + print(f"Sending {len(message)} bytes, receiving {len(expected_rx_message)} bytes, ") buffer.write(message) buffer.flush() @@ -621,12 +621,12 @@ class TestLink(unittest.TestCase): for unit in units: if abs(num) < 1000.0: if unit == "": - return "%.0f %s%s" % (num, unit, suffix) + return f"{num:.0f} {unit}{suffix}" else: - return "%.2f %s%s" % (num, unit, suffix) + return f"{num:.2f} {unit}{suffix}" num /= 1000.0 - return "%.2f%s%s" % (num, last_unit, suffix) + return f"{num:.2f}{last_unit}{suffix}" if __name__ == '__main__': unittest.main(verbosity=1) @@ -650,16 +650,16 @@ def targets(yp=False): threads = yappi.get_thread_stats() for thread in threads: print( - "Function stats for (%s) (%d)" % (thread.name, thread.id) + f"Function stats for ({thread.name}) ({int(thread.id)})" ) # it is the Thread.__class__.__name__ - yappi.get_func_stats(ctx_id=thread.id).save("receiver_thread_"+str(thread.id)+".data", type="pstat") + yappi.get_func_stats(ctx_id=thread.id).save(f"receiver_thread_{thread.id}.data", type="pstat") except Exception as e: - print("Error: "+str(e)) + print(f"Error: {e}") if hasattr(resource.link.attached_interface, "rxptime"): rx_pr = (resource.link.attached_interface.rxb*8)/resource.link.attached_interface.rxptime - print("Average RX proccessing rate: "+size_str(rx_pr, "b")+"ps") + print(f"Average RX proccessing rate: {size_str(rx_pr, 'b')}ps") def link_established(link): print("Link established") @@ -670,7 +670,7 @@ def targets(yp=False): def handle_message(message): if isinstance(message, MessageTest): - message.data = message.data + " back" + message.data = f"{message.data} back" channel.send(message) channel.register_message_type(MessageTest) @@ -685,17 +685,17 @@ def targets(yp=False): buffer_read_len += len(data) response_data.append(data) - if data == "Hi there".encode("utf-8"): + if data == b"Hi there": RNS.log("Sending response") for data in response_data: - buffer.write(data + " back at you".encode("utf-8")) + buffer.write(data + b" back at you") buffer.flush() buffer_read_len = 0 if buffer_read_len == BUFFER_TEST_TARGET: RNS.log("Sending response") for data in response_data: - buffer.write(data + " back at you".encode("utf-8")) + buffer.write(data + b" back at you") buffer.flush() buffer_read_len = 0 @@ -745,7 +745,7 @@ def resource_profiling(): resource_timeout = 120 resource_size = 5*1000*1000 data = os.urandom(resource_size) - print("Sending "+size_str(resource_size)+" resource...") + print(f"Sending {size_str(resource_size)} resource...") import yappi yappi.start() @@ -759,22 +759,22 @@ def resource_profiling(): time.sleep(0.01) t = time.time() - start - print("Resource completed at "+size_str(resource_size/t, "b")+"ps") + print(f"Resource completed at {size_str(resource_size / t, 'b')}ps") yappi.get_func_stats().save("sender_main_calls.data", type="pstat") threads = yappi.get_thread_stats() for thread in threads: print( - "Function stats for (%s) (%d)" % (thread.name, thread.id) + f"Function stats for ({thread.name}) ({int(thread.id)})" ) # it is the Thread.__class__.__name__ - yappi.get_func_stats(ctx_id=thread.id).save("sender_thread_"+str(thread.id)+".data", type="pstat") + yappi.get_func_stats(ctx_id=thread.id).save(f"sender_thread_{thread.id}.data", type="pstat") # t_pstats = yappi.convert2pstats(tstats) # t_pstats.save("resource_tstat.data", type="pstat") if hasattr(resource.link.attached_interface, "rxptime"): rx_pr = (resource.link.attached_interface.rxb*8)/resource.link.attached_interface.rxptime - print("Average RX proccessing rate: "+size_str(rx_pr, "b")+"ps") + print(f"Average RX proccessing rate: {size_str(rx_pr, 'b')}ps") l1.teardown() time.sleep(0.5) @@ -791,9 +791,9 @@ def size_str(num, suffix='B'): for unit in units: if abs(num) < 1000.0: if unit == "": - return "%.0f %s%s" % (num, unit, suffix) + return f"{num:.0f} {unit}{suffix}" else: - return "%.2f %s%s" % (num, unit, suffix) + return f"{num:.2f} {unit}{suffix}" num /= 1000.0 - return "%.2f%s%s" % (num, last_unit, suffix) \ No newline at end of file + return f"{num:.2f}{last_unit}{suffix}" \ No newline at end of file