From 997828795abdf6f00e6aa06b0ceca37ac46c58c8 Mon Sep 17 00:00:00 2001 From: Nathan Woodburn Date: Tue, 2 Sep 2025 15:48:21 +1000 Subject: [PATCH] feat: Add ruff linting --- .gitea/workflows/test.yml | 13 ++++--- account.py | 71 ++++++++++++++++++++------------------- domainLookup.py | 5 ++- main.py | 32 +++++++++--------- plugins/automations.py | 1 - plugins/batching.py | 2 -- plugins/customPlugins.py | 2 -- plugins/renewal.py | 2 -- render.py | 46 ++++++++++++------------- server.py | 5 ++- 10 files changed, 86 insertions(+), 93 deletions(-) diff --git a/.gitea/workflows/test.yml b/.gitea/workflows/test.yml index a4f4c92..40fe5ac 100644 --- a/.gitea/workflows/test.yml +++ b/.gitea/workflows/test.yml @@ -9,14 +9,14 @@ jobs: container: catthehacker/ubuntu:act-latest strategy: matrix: - python-version: ['3.8', '3.10', '3.13'] + python-version: ['3.10', '3.11', '3.13'] fail-fast: false steps: - name: Checkout uses: actions/checkout@v3 - - name: Set up Python ${{ matrix.python-version }} + - name: Set up Python uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} @@ -27,9 +27,14 @@ jobs: if [ -f requirements.txt ]; then pip install -r requirements.txt fi - pip install pytest + pip install pytest ruff - name: Run tests run: | echo "Testing with Python ${{ matrix.python-version }}" - python -m pytest main.py \ No newline at end of file + python -m pytest main.py + + - name: Lint with ruff + run: | + echo "Linting with Python ${{ matrix.python-version }}" + ruff check \ No newline at end of file diff --git a/account.py b/account.py index 10a370d..ed41e18 100644 --- a/account.py +++ b/account.py @@ -130,7 +130,7 @@ def check_password(cookie: str|None, password: str|None): password = "" account = check_account(cookie) - if account == False: + if not account: return False # Check if the password is valid @@ -638,7 +638,7 @@ def check_address(address: str, allow_name: bool = True, return_address: bool = return False return 'Invalid address' - if response['result']['isvalid'] == True: + if response['result']['isvalid']: if return_address: return address return 'Valid address' @@ -788,7 +788,7 @@ def getAddressFromCoin(coinhash: str, coinindex = 0): # Get the address from the hash response = requests.get(get_node_api_url(f"coin/{coinhash}/{coinindex}")) if response.status_code != 200: - print(f"Error getting address from coin") + print("Error getting address from coin") return "No Owner" data = response.json() if 'address' not in data: @@ -801,7 +801,7 @@ def renewDomain(account, domain): account_name = check_account(account) password = ":".join(account.split(":")[1:]) - if account_name == False: + if not account_name: return { "error": { "message": "Invalid account" @@ -834,7 +834,7 @@ def getDNS(domain: str): return { "error": "No DNS records" } - if response['result'] == None: + if response['result'] is None: return [] if 'records' not in response['result']: @@ -846,7 +846,7 @@ def setDNS(account, domain, records): account_name = check_account(account) password = ":".join(account.split(":")[1:]) - if account_name == False: + if not account_name: return { "error": { "message": "Invalid account" @@ -918,7 +918,7 @@ def getNodeSync(): def getWalletStatus(): response = hsw.rpc_getWalletInfo() - if 'error' in response and response['error'] != None: + if 'error' in response and response['error'] is not None: return "Error" # return response @@ -967,7 +967,7 @@ def getPendingReveals(account): if bid['name'] == domain['name']: state_found = False for reveal in reveals: - if reveal['own'] == True: + if reveal['own']: if bid['value'] == reveal['value']: state_found = True @@ -997,8 +997,8 @@ def getPendingRedeems(account, password): pending.append(nameHash) else: pending.append(name['result']) - except: - print("Failed to parse redeems") + except Exception as e: + print(f"Failed to parse redeems: {str(e)}") return pending @@ -1008,7 +1008,7 @@ def getPendingRegisters(account): domains = getDomains(account, False) pending = [] for domain in domains: - if domain['state'] == "CLOSED" and domain['registered'] == False: + if domain['state'] == "CLOSED" and not domain['registered']: for bid in bids: if bid['name'] == domain['name']: if bid['value'] == domain['highest']: @@ -1026,9 +1026,9 @@ def getPendingFinalizes(account, password): pending = [] try: for output in tx['outputs']: - if type(output) != dict: + if type(output) is not dict: continue - if not 'covenant' in output: + if 'covenant' not in output: continue if output['covenant'].get("type") != 10: continue @@ -1041,8 +1041,8 @@ def getPendingFinalizes(account, password): pending.append(nameHash) else: pending.append(name['result']) - except: - print("Failed to parse finalizes") + except Exception as e: + print(f"Failed to parse finalizes: {str(e)}") return pending @@ -1065,7 +1065,7 @@ def revealAuction(account, domain): account_name = check_account(account) password = ":".join(account.split(":")[1:]) - if account_name == False: + if not account_name: return { "error": { "message": "Invalid account" @@ -1085,7 +1085,7 @@ def revealAll(account): account_name = check_account(account) password = ":".join(account.split(":")[1:]) - if account_name == False: + if not account_name: return { "error": { "message": "Invalid account" @@ -1119,7 +1119,7 @@ def redeemAll(account): account_name = check_account(account) password = ":".join(account.split(":")[1:]) - if account_name == False: + if not account_name: return { "error": { "message": "Invalid account" @@ -1151,9 +1151,8 @@ def redeemAll(account): def registerAll(account): account_name = check_account(account) - password = ":".join(account.split(":")[1:]) - if account_name == False: + if not account_name: return { "error": { "message": "Invalid account" @@ -1176,9 +1175,8 @@ def registerAll(account): def finalizeAll(account): account_name = check_account(account) - password = ":".join(account.split(":")[1:]) - if account_name == False: + if not account_name: return { "error": { "message": "Invalid account" @@ -1211,7 +1209,7 @@ def bid(account, domain, bid, blind): account_name = check_account(account) password = ":".join(account.split(":")[1:]) - if account_name == False: + if not account_name: return { "error": { "message": "Invalid account" @@ -1236,7 +1234,7 @@ def openAuction(account, domain): account_name = check_account(account) password = ":".join(account.split(":")[1:]) - if account_name == False: + if not account_name: return { "error": { "message": "Invalid account" @@ -1258,7 +1256,7 @@ def transfer(account, domain, address): account_name = check_account(account) password = ":".join(account.split(":")[1:]) - if account_name == False: + if not account_name: return { "error": { "message": "Invalid account" @@ -1280,7 +1278,7 @@ def finalize(account, domain): account_name = check_account(account) password = ":".join(account.split(":")[1:]) - if account_name == False: + if not account_name: return { "error": { "message": "Invalid account" @@ -1317,7 +1315,7 @@ def cancelTransfer(account, domain): account_name = check_account(account) password = ":".join(account.split(":")[1:]) - if account_name == False: + if not account_name: return { "error": { "message": "Invalid account" @@ -1354,7 +1352,7 @@ def revoke(account, domain): account_name = check_account(account) password = ":".join(account.split(":")[1:]) - if account_name == False: + if not account_name: return { "error": { "message": "Invalid account" @@ -1391,7 +1389,7 @@ def sendBatch(account, batch): account_name = check_account(account) password = ":".join(account.split(":")[1:]) - if account_name == False: + if not account_name: return { "error": { "message": "Invalid account" @@ -1440,7 +1438,7 @@ def createBatch(account, batch): account_name = check_account(account) password = ":".join(account.split(":")[1:]) - if account_name == False: + if not account_name: return { "error": { "message": "Invalid account" @@ -1589,7 +1587,7 @@ def zapTXs(account): account_name = check_account(account) - if account_name == False: + if not account_name: return { "error": { "message": "Invalid account" @@ -1615,7 +1613,7 @@ def getxPub(account): if account.count(":") > 0: account_name = check_account(account) - if account_name == False: + if not account_name: return { "error": { "message": "Invalid account" @@ -1643,7 +1641,7 @@ def signMessage(account, domain, message): account_name = check_account(account) password = ":".join(account.split(":")[1:]) - if account_name == False: + if not account_name: return { "error": { "message": "Invalid account" @@ -1683,6 +1681,7 @@ def verifyMessageWithName(domain, signature, message): return response['result'] return False except Exception as e: + print(f"Error verifying message with name: {str(e)}") return False @@ -1693,6 +1692,7 @@ def verifyMessage(address, signature, message): return response['result'] return False except Exception as e: + print(f"Error verifying message: {str(e)}") return False # endregion @@ -1739,7 +1739,7 @@ def get_node_api_url(path=''): base_url = f"http://x:{HSD_API}@{HSD_IP}:{HSD_NODE_PORT}" if isSPV() and any(path.startswith(route) for route in SPV_EXTERNAL_ROUTES): # If in SPV mode and the path is one of the external routes, use the external API - base_url = f"https://hsd.hns.au/api/v1" + base_url = "https://hsd.hns.au/api/v1" if path: # Ensure path starts with a slash if it's not empty @@ -1945,7 +1945,8 @@ def hsdStart(): try: signal.signal(signal.SIGINT, lambda s, f: (hsdStop(), sys.exit(0))) signal.signal(signal.SIGTERM, lambda s, f: (hsdStop(), sys.exit(0))) - except: + except Exception as e: + print(f"Failed to set signal handlers: {str(e)}") pass diff --git a/domainLookup.py b/domainLookup.py index 353a61e..ad0ab3c 100644 --- a/domainLookup.py +++ b/domainLookup.py @@ -11,7 +11,6 @@ import dns.query import dns.rdatatype import httpx from requests_doh import DNSOverHTTPSSession, add_dns_provider -import requests import urllib3 from cryptography.x509.oid import ExtensionOID @@ -172,11 +171,11 @@ def resolve_TLSA_with_doh(query_name, doh_url="https://hnsdoh.com/dns-query"): def emoji_to_punycode(emoji): try: return emoji.encode("idna").decode("ascii") - except Exception as e: + except Exception: return emoji def punycode_to_emoji(punycode): try: return punycode.encode("ascii").decode("idna") - except Exception as e: + except Exception: return punycode \ No newline at end of file diff --git a/main.py b/main.py index 55f78bd..6c77bfa 100644 --- a/main.py +++ b/main.py @@ -12,11 +12,9 @@ import re from flask_qrcode import QRcode import domainLookup import urllib.parse -import importlib import plugin as plugins_module import gitinfo import datetime -import functools import time dotenv.load_dotenv() @@ -196,7 +194,7 @@ def send(): content = f"Are you sure you want to send {amount} HNS to {toAddress}

" content += f"This will cost {amount} HNS + mining fees and is not able to be undone." - cancel = f"/send" + cancel = "/send" confirm = f"/send/confirm?address={address}&amount={amount}" @@ -645,9 +643,9 @@ def revokeInit(domain: str): domain = domain.lower() content = f"Are you sure you want to revoke {domain}/?
" - content += f"This will return the domain to the auction pool and you will lose any funds spent on the domain.
" - content += f"This cannot be undone after the transaction is sent.

" - content += f"Please enter your password to confirm." + content += "This will return the domain to the auction pool and you will lose any funds spent on the domain.
" + content += "This cannot be undone after the transaction is sent.

" + content += "Please enter your password to confirm." cancel = f"/manage/{domain}" confirm = f"/manage/{domain}/revoke/confirm" @@ -820,7 +818,7 @@ def transfer(domain): action = f"Send {domain}/ to {request.form.get('address')}" content = f"Are you sure you want to send {domain}/ to {toAddress}

" - content += f"This requires sending a finalize transaction 2 days after the transfer is initiated." + content += "This requires sending a finalize transaction 2 days after the transfer is initiated." cancel = f"/manage/{domain}?address={address}" confirm = f"/manage/{domain}/transfer/confirm?address={address}" @@ -918,7 +916,7 @@ def auction(domain): if domainInfo['info'] is None: if 'registered' in domainInfo and domainInfo['registered'] == False and 'expired' in domainInfo and domainInfo['expired'] == False: # Needs to be registered - next_action = f'ERROR GETTING NEXT STATE' + next_action = 'ERROR GETTING NEXT STATE' else: next_action = f'Open Auction' return render_template("auction.html", account=account, @@ -965,7 +963,7 @@ def auction(domain): elif stats['blocksUntilReveal'] == 2: next += "
LAST CHANCE TO BID" elif stats['blocksUntilReveal'] == 3: - next += f"
Next block is last chance to bid" + next += "
Next block is last chance to bid" elif stats['blocksUntilReveal'] < 6: next += f"
Last chance to bid in {stats['blocksUntilReveal']-2} blocks" @@ -1229,7 +1227,7 @@ def settings_action(action): @app.route('/settings/upload', methods=['POST']) def upload_image(): - if not 'account' in request.cookies: + if 'account' not in request.cookies: return redirect("/login?message=Not logged in") account = request.cookies.get("account") @@ -1253,7 +1251,7 @@ def upload_image(): return redirect("/settings?error=An error occurred") def latestVersion(branch): - result = requests.get(f"https://git.woodburn.au/api/v1/repos/nathanwoodburn/firewalletbrowser/branches") + result = requests.get("https://git.woodburn.au/api/v1/repos/nathanwoodburn/firewalletbrowser/branches") if result.status_code != 200: return "Error" @@ -1628,7 +1626,7 @@ def api_hsd(function): elif stats['blocksUntilReveal'] == 2: next += "
LAST CHANCE TO BID" elif stats['blocksUntilReveal'] == 3: - next += f"
Next block is last chance to bid" + next += "
Next block is last chance to bid" elif stats['blocksUntilReveal'] < 6: next += f"
Last chance to bid in {stats['blocksUntilReveal']-2} blocks" @@ -1783,9 +1781,9 @@ def api_wallet(function): if function == "icon": # Check if there is an icon - if not os.path.exists(f'user_data/images'): + if not os.path.exists('user_data/images'): return send_file('templates/assets/img/HNS.png') - files = os.listdir(f'user_data/images') + files = os.listdir('user_data/images') for file in files: if file.startswith(account): return send_file(f'user_data/images/{file}') @@ -1820,9 +1818,9 @@ def api_wallet_mobile(function): @app.route('/api/v1/icon/') def api_icon(account): - if not os.path.exists(f'user_data/images'): + if not os.path.exists('user_data/images'): return send_file('templates/assets/img/HNS.png') - files = os.listdir(f'user_data/images') + files = os.listdir('user_data/images') for file in files: if file.startswith(account): return send_file(f'user_data/images/{file}') @@ -1854,7 +1852,7 @@ def renderDomain(name: str) -> str: return f"{rendered}/ ({name})" - except Exception as e: + except Exception: return f"{name}/" #endregion diff --git a/plugins/automations.py b/plugins/automations.py index b062015..3452f21 100644 --- a/plugins/automations.py +++ b/plugins/automations.py @@ -1,4 +1,3 @@ -import json import account import requests import threading diff --git a/plugins/batching.py b/plugins/batching.py index 9dc6663..17d97ac 100644 --- a/plugins/batching.py +++ b/plugins/batching.py @@ -1,7 +1,5 @@ -import json import account import requests -import os diff --git a/plugins/customPlugins.py b/plugins/customPlugins.py index 0f2a09c..65308a7 100644 --- a/plugins/customPlugins.py +++ b/plugins/customPlugins.py @@ -1,6 +1,4 @@ import json -import account -import requests import os # Plugin Data diff --git a/plugins/renewal.py b/plugins/renewal.py index 9819e8b..2adc2b0 100644 --- a/plugins/renewal.py +++ b/plugins/renewal.py @@ -1,7 +1,5 @@ -import json import account import requests -import os # Plugin Data info = { diff --git a/render.py b/render.py index e48ec3f..a9fea93 100644 --- a/render.py +++ b/render.py @@ -2,9 +2,7 @@ import datetime import json import urllib.parse from flask import render_template -from domainLookup import punycode_to_emoji import os -from handywrapper import api import threading import requests @@ -182,7 +180,7 @@ def transactions(txs): elif amount > 0: amount = f"+{amount:,.2f}" else: - amount = f"0.00" + amount = "0.00" # hash = f"{hash[:8]}..." @@ -261,7 +259,7 @@ def txs(data): html_output += f"{amount:,.2f} + {blind:,.2f} HNS\n" html_output += f"{timestamp_to_readable_time(entry['time'])}\n" - html_output += f"\n" + html_output += "\n" return html_output @@ -316,13 +314,13 @@ def bids(bids,reveals): html += f"{value:,.2f} HNS" html += f"{bidValue:,.2f} HNS" else: - html += f"Hidden until reveal" - html += f"Hidden until reveal" + html += "Hidden until reveal" + html += "Hidden until reveal" if bid['own']: html += "You" else: - html += f"Unknown" + html += "Unknown" html += f"Bid TX 🔗" html += "" @@ -410,22 +408,22 @@ def plugin_functions(functions, pluginName): functionType = functions[function]["type"] - html += f'
' - html += f'
' + html += '
' + html += '
' html += f'

{name}

' html += f'
{description}
' html += f'
Function type: {functionType.capitalize()}
' if functionType != "default": html += f'

Returns: {returns}

' - html += f'
' - html += f'
' + html += '
' + html += '
' continue # Form html += f'
' for param in params: - html += f'
' + html += '
' paramName = params[param]["name"] paramType = params[param]["type"] if paramType == "text": @@ -449,14 +447,14 @@ def plugin_functions(functions, pluginName): - html += f'
' + html += '
' - html += f'' - html += f'
' + html += '' + html += '' # For debugging html += f'

Returns: {returns}

' - html += f'' - html += f'' + html += '' + html += '' return html @@ -468,16 +466,16 @@ def plugin_output(outputs, returns): for returnOutput in returns: if returnOutput not in outputs: continue - html += f'
' - html += f'
' + html += '
' + html += '
' html += f'

{returns[returnOutput]["name"]}

' output = outputs[returnOutput] if returns[returnOutput]["type"] == "list": - html += f'
    ' + html += '
      ' for item in output: html += f'
    • {item}
    • ' - html += f'
    ' + html += '
' elif returns[returnOutput]["type"] == "text": html += f'

{output}

' elif returns[returnOutput]["type"] == "tx": @@ -487,8 +485,8 @@ def plugin_output(outputs, returns): html += render_template('components/dns-output.html', dns=dns(output)) - html += f'
' - html += f'
' + html += '
' + html += '
' return html def plugin_output_dash(outputs, returns): @@ -517,7 +515,7 @@ def renderDomain(name: str) -> str: return f"{rendered}/ ({name})" - except Exception as e: + except Exception: return f"{name}/" def renderDomainAsync(namehash: str) -> None: diff --git a/server.py b/server.py index f8e1153..53d6e12 100644 --- a/server.py +++ b/server.py @@ -1,4 +1,3 @@ -import os import sys import platform from main import app @@ -39,6 +38,6 @@ if __name__ == '__main__': sys.exit() print(f'Starting server with Waitress on {platform.system()} with {threads} threads...', flush=True) - print(f'Press Ctrl+C to stop the server', flush=True) - print(f'Serving on http://0.0.0.0:5000/', flush=True) + print('Press Ctrl+C to stop the server', flush=True) + print('Serving on http://0.0.0.0:5000/', flush=True) serve(app, host="0.0.0.0", port=5000, threads=threads)