From 1d98dbeddfaa5abb374b702e7a60864c3d1d0ded Mon Sep 17 00:00:00 2001 From: Andrew Williams Date: Sat, 16 Aug 2025 12:06:25 +0100 Subject: [PATCH] Modernise Python support --- Makefile | 4 +- ohayodash/base.py | 98 ++++++++++++++++++++++++----------------------- pyproject.toml | 1 - uv.lock | 11 ------ 4 files changed, 54 insertions(+), 60 deletions(-) diff --git a/Makefile b/Makefile index b65fc97..94c7874 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,6 @@ .PHONY: lint lint: uv run --dev ruff check --output-format=github --select=E9,F63,F7,F82 --target-version=py39 . - uv run --dev -m ruff check --output-format=github --target-version=py39 . \ No newline at end of file + uv run --dev -m ruff check --output-format=github --target-version=py39 . +serve: + uv run --dev -m flask --app ohayodash.app:app run \ No newline at end of file diff --git a/ohayodash/base.py b/ohayodash/base.py index 02f55a7..2065dbc 100644 --- a/ohayodash/base.py +++ b/ohayodash/base.py @@ -1,15 +1,15 @@ +import importlib.resources import os import kubernetes -import pkg_resources import yaml from flask import Blueprint, jsonify, render_template -ANNOTATION_BASE = 'ohayodash.github.io' +ANNOTATION_BASE = "ohayodash.github.io" -base = Blueprint('base', __name__, template_folder='templates') +base = Blueprint("base", __name__, template_folder="templates") -if 'KUBERNETES_SERVICE_HOST' in os.environ: +if "KUBERNETES_SERVICE_HOST" in os.environ: kubernetes.config.load_incluster_config() else: kubernetes.config.load_kube_config() @@ -17,8 +17,8 @@ else: def check_tags(tag, kubeobj): # Skip if we're limited to a tag, and the CM has tags but not that one. - tags = kubeobj.metadata.annotations.get('{0}/tags'.format(ANNOTATION_BASE), '') - obj_tags = {tagname for tagname in tags.split(',') if tagname != ''} + tags = kubeobj.metadata.annotations.get("{0}/tags".format(ANNOTATION_BASE), "") + obj_tags = {tagname for tagname in tags.split(",") if tagname != ""} # If its not tagged, allow if not obj_tags: @@ -28,18 +28,17 @@ def check_tags(tag, kubeobj): return tag in obj_tags -def get_k8s_applications(tag: str = None) -> list: +def get_k8s_applications(tag: str | None = None) -> list: """Get all ingresses from the cluster and produce a application list.""" api = kubernetes.client.NetworkingV1Api() applications = [] for ingress in api.list_ingress_for_all_namespaces(watch=False).items: - # Skip if not enabled - enable_annotation = '{0}/enable'.format(ANNOTATION_BASE) + enable_annotation = "{0}/enable".format(ANNOTATION_BASE) if enable_annotation not in ingress.metadata.annotations: continue - if ingress.metadata.annotations[enable_annotation] == 'false': + if ingress.metadata.annotations[enable_annotation] == "false": continue # Skip if we're limited to a tag, and the Ingress has tags but not that one. @@ -48,23 +47,23 @@ def get_k8s_applications(tag: str = None) -> list: # Set to some basic values from the ingress application_values = { - 'name': ingress.metadata.name, - 'namespace': ingress.metadata.namespace, - 'url': 'https://{0}'.format(ingress.spec.rules[0].host), - 'show_url': False, + "name": ingress.metadata.name, + "namespace": ingress.metadata.namespace, + "url": "https://{0}".format(ingress.spec.rules[0].host), + "show_url": False, } # Read annotations and override the values if defined for key, value in ingress.metadata.annotations.items(): if key.startswith(ANNOTATION_BASE): - annotation_key = key.split('/')[1] + annotation_key = key.split("/")[1] application_values[annotation_key] = value applications.append(application_values) - return sorted(applications, key=lambda item: item['name']) + return sorted(applications, key=lambda item: item["name"]) -def get_bookmarks(tag: str = None) -> list: +def get_bookmarks(tag: str | None = None) -> list: """Get all 'bookmark' ConfigMaps from the cluster and produce a bookmark list.""" v1 = kubernetes.client.CoreV1Api() ret = v1.list_config_map_for_all_namespaces(watch=False) @@ -76,7 +75,7 @@ def get_bookmarks(tag: str = None) -> list: continue # Skip if its not tagged as bookmark CM - if '{0}/bookmarks'.format(ANNOTATION_BASE) not in cm.metadata.annotations: + if "{0}/bookmarks".format(ANNOTATION_BASE) not in cm.metadata.annotations: continue # Skip if we're limited to a tag, and the CM has tags but not that one. @@ -84,27 +83,27 @@ def get_bookmarks(tag: str = None) -> list: continue # Load bookmark data - bookmark_data = yaml.safe_load(cm.data['bookmarks']) + bookmark_data = yaml.safe_load(cm.data["bookmarks"]) # Iterate each bookmark for bookmark in bookmark_data: - if 'group' not in bookmark: - group = 'default' + if "group" not in bookmark: + group = "default" else: - group = bookmark['group'].lower() + group = bookmark["group"].lower() # Find category dict and append or create for cat in bookmarks: - if cat['category'] == group: - cat['links'].append(bookmark) + if cat["category"] == group: + cat["links"].append(bookmark) break else: - bookmarks.append({'category': group, 'links': [bookmark]}) + bookmarks.append({"category": group, "links": [bookmark]}) return bookmarks -def get_providers(tag: str = None) -> list: +def get_providers(tag: str | None = None) -> list: """Get all 'provider' ConfigMaps from the cluster and produce a provider list.""" v1 = kubernetes.client.CoreV1Api() ret = v1.list_config_map_for_all_namespaces(watch=False) @@ -116,47 +115,52 @@ def get_providers(tag: str = None) -> list: continue # Skip if its not tagged as bookmark CM - if '{0}/providers'.format(ANNOTATION_BASE) not in cm.metadata.annotations: + if "{0}/providers".format(ANNOTATION_BASE) not in cm.metadata.annotations: continue # Skip if we're limited to a tag, and the CM has tags but not that one. if not check_tags(tag, cm): continue - provider_data = yaml.safe_load(cm.data['providers']) + provider_data = yaml.safe_load(cm.data["providers"]) providers.extend(provider_data) return providers -@base.route('/') -@base.route('//') +@base.route("/") +@base.route("//") def index(tag=None): - return render_template('index.j2') + return render_template("index.j2") -@base.route('/providers.json') -@base.route('//providers.json') +@base.route("/providers.json") +@base.route("//providers.json") def providers(tag=None): k8s_providers = get_providers(tag) if not k8s_providers: - data_file = pkg_resources.resource_filename(__name__, 'data/providers.yaml') - with open(data_file, 'r') as fobj: - k8s_providers.extend(yaml.safe_load(fobj)) - return jsonify({'providers': k8s_providers}) + data_file = importlib.resources.files(__name__) / "data/providers.yaml" + with importlib.resources.as_file(data_file) as path: + with path.open("r") as fobj: + k8s_providers.extend(yaml.safe_load(fobj)) + return jsonify({"providers": k8s_providers}) -@base.route('/apps.json') -@base.route('//apps.json') +@base.route("/apps.json") +@base.route("//apps.json") def applications(tag=None): - return jsonify({ - 'apps': get_k8s_applications(tag), - }) + return jsonify( + { + "apps": get_k8s_applications(tag), + } + ) -@base.route('/links.json') -@base.route('//links.json') +@base.route("/links.json") +@base.route("//links.json") def bookmarks(tag=None): - return jsonify({ - 'bookmarks': get_bookmarks(tag), - }) + return jsonify( + { + "bookmarks": get_bookmarks(tag), + } + ) diff --git a/pyproject.toml b/pyproject.toml index 88e466f..60608ab 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -10,7 +10,6 @@ dependencies = [ "gunicorn>=23.0.0", "kubernetes>=33.1.0", "pyyaml>=6.0.2", - "setuptools>=80.9.0", ] [dependency-groups] diff --git a/uv.lock b/uv.lock index 608e51b..1274385 100644 --- a/uv.lock +++ b/uv.lock @@ -240,7 +240,6 @@ dependencies = [ { name = "gunicorn" }, { name = "kubernetes" }, { name = "pyyaml" }, - { name = "setuptools" }, ] [package.dev-dependencies] @@ -255,7 +254,6 @@ requires-dist = [ { name = "gunicorn", specifier = ">=23.0.0" }, { name = "kubernetes", specifier = ">=33.1.0" }, { name = "pyyaml", specifier = ">=6.0.2" }, - { name = "setuptools", specifier = ">=80.9.0" }, ] [package.metadata.requires-dev] @@ -423,15 +421,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ac/fd/669816bc6b5b93b9586f3c1d87cd6bc05028470b3ecfebb5938252c47a35/ruff-0.12.9-py3-none-win_arm64.whl", hash = "sha256:63c8c819739d86b96d500cce885956a1a48ab056bbcbc61b747ad494b2485089", size = 11949623, upload-time = "2025-08-14T16:08:52.233Z" }, ] -[[package]] -name = "setuptools" -version = "80.9.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/18/5d/3bf57dcd21979b887f014ea83c24ae194cfcd12b9e0fda66b957c69d1fca/setuptools-80.9.0.tar.gz", hash = "sha256:f36b47402ecde768dbfafc46e8e4207b4360c654f1f3bb84475f0a28628fb19c", size = 1319958, upload-time = "2025-05-27T00:56:51.443Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a3/dc/17031897dae0efacfea57dfd3a82fdd2a2aeb58e0ff71b77b87e44edc772/setuptools-80.9.0-py3-none-any.whl", hash = "sha256:062d34222ad13e0cc312a4c02d73f059e86a4acbfbdea8f8f76b28c99f306922", size = 1201486, upload-time = "2025-05-27T00:56:49.664Z" }, -] - [[package]] name = "six" version = "1.17.0"