From 1cd51b349db8613056b4b066869a5b32e559512c Mon Sep 17 00:00:00 2001
From: beauagainagainagainagainagain
<152763000+beauagainagainagainagainagain@users.noreply.github.com>
Date: Sun, 15 Dec 2024 15:01:51 +1100
Subject: [PATCH 1/4] Create pylint.yml
---
.github/workflows/pylint.yml | 23 +++++++++++++++++++++++
1 file changed, 23 insertions(+)
create mode 100644 .github/workflows/pylint.yml
diff --git a/.github/workflows/pylint.yml b/.github/workflows/pylint.yml
new file mode 100644
index 000000000000..c73e032c0f3f
--- /dev/null
+++ b/.github/workflows/pylint.yml
@@ -0,0 +1,23 @@
+name: Pylint
+
+on: [push]
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ python-version: ["3.8", "3.9", "3.10"]
+ steps:
+ - uses: actions/checkout@v4
+ - name: Set up Python ${{ matrix.python-version }}
+ uses: actions/setup-python@v3
+ with:
+ python-version: ${{ matrix.python-version }}
+ - name: Install dependencies
+ run: |
+ python -m pip install --upgrade pip
+ pip install pylint
+ - name: Analysing the code with pylint
+ run: |
+ pylint $(git ls-files '*.py')
From 856635a76081442fe1cffee9585bb4938f1d43bd Mon Sep 17 00:00:00 2001
From: beauagainagainagainagainagain
<152763000+beauagainagainagainagainagain@users.noreply.github.com>
Date: Sat, 6 Sep 2025 04:15:57 +1000
Subject: [PATCH 2/4] Fix formatting in requirements
---
requirements.txt | 2 +
sustainability/__init__.py | 1 +
sustainability/ctrl_compliance_dashboard.py | 178 ++++++++++++++++++++
3 files changed, 181 insertions(+)
create mode 100644 sustainability/__init__.py
create mode 100644 sustainability/ctrl_compliance_dashboard.py
diff --git a/requirements.txt b/requirements.txt
index 4cc83f44987d..35972adf23dc 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,12 +1,14 @@
beautifulsoup4
fake_useragent
imageio
+jinja2
keras
lxml
matplotlib
numpy
opencv-python
pandas
+pdfkit
pillow
requests
rich
diff --git a/sustainability/__init__.py b/sustainability/__init__.py
new file mode 100644
index 000000000000..70713738e630
--- /dev/null
+++ b/sustainability/__init__.py
@@ -0,0 +1 @@
+"""Sustainability compliance tools for CTRL Environmental."""
diff --git a/sustainability/ctrl_compliance_dashboard.py b/sustainability/ctrl_compliance_dashboard.py
new file mode 100644
index 000000000000..317739b80239
--- /dev/null
+++ b/sustainability/ctrl_compliance_dashboard.py
@@ -0,0 +1,178 @@
+"""Generate a sustainability compliance dashboard for CTRL Environmental.
+
+The script reads inspection data from CSV or Excel files, categorizes findings
+into environmental topics, flags non-compliances with traffic light colours,
+and exports the results to a styled HTML report. Optional PDF export is
+attempted if a suitable backend is available. The layout follows a black,
+red, and white palette reminiscent of Berlin poster aesthetics and includes
+placeholders for the CTRL logo and report metadata.
+"""
+
+from __future__ import annotations
+
+import argparse
+from dataclasses import dataclass
+from datetime import UTC, datetime
+from pathlib import Path
+
+import pandas as pd
+from jinja2 import Environment
+
+try:
+ import pdfkit # type: ignore[import-not-found]
+except ImportError:
+ pdfkit = None # type: ignore[assignment]
+
+try:
+ from weasyprint import HTML # type: ignore[import-not-found]
+except ImportError:
+ HTML = None # type: ignore[assignment]
+
+CATEGORY_KEYWORDS = {
+ "Waste": ["waste", "trash", "garbage", "recycle"],
+ "Water": ["water", "effluent", "sewage", "storm"],
+ "Air": ["air", "emission", "dust", "smoke"],
+ "Chemicals": ["chemical", "hazard", "solvent", "acid", "alkali"],
+ "ESG": ["esg", "governance", "social", "sustainability", "diversity"],
+}
+
+
+@dataclass
+class Metadata:
+ """Metadata describing the inspection report."""
+
+ site: str
+ client: str
+ inspector: str
+ date: str
+
+
+def read_inspection_data(path: str) -> pd.DataFrame:
+ """Read inspection data from a CSV or Excel file."""
+
+ ext = Path(path).suffix.lower()
+ if ext in {".xls", ".xlsx"}:
+ return pd.read_excel(path)
+ return pd.read_csv(path)
+
+
+def categorize_finding(text: str) -> str:
+ """Return the category that best matches *text*."""
+
+ lowered = text.lower()
+ for category, keywords in CATEGORY_KEYWORDS.items():
+ if any(word in lowered for word in keywords):
+ return category
+ return "Other"
+
+
+def traffic_light(status: str) -> str:
+ """Return a CSS colour for a traffic light style status."""
+
+ lowered = status.lower()
+ if any(word in lowered for word in ["non", "major", "fail", "nc"]):
+ return "#d50000" # red
+ if any(word in lowered for word in ["minor", "obs", "warning"]):
+ return "#ffab00" # amber
+ return "#00c853" # green
+
+
+def build_table(df: pd.DataFrame) -> str:
+ """Return an HTML table with traffic light styling."""
+
+ styled = (
+ df.style.applymap(
+ lambda v: f"background-color:{traffic_light(v)}", subset=["Status"]
+ )
+ .set_table_styles(
+ [
+ {
+ "selector": "th, td",
+ "props": [("border", "1px solid black"), ("padding", "4px")],
+ }
+ ]
+ )
+ .hide_index()
+ )
+ return styled.to_html()
+
+
+TEMPLATE = """
+
+
+
+
+CTRL Environmental Compliance Report
+
+
+
+
+
+{{ table | safe }}
+
+
+
+"""
+
+
+def render_report(
+ df: pd.DataFrame, meta: Metadata, logo: str, html_path: str, pdf_path: str | None
+) -> None:
+ """Render *df* to HTML and optionally PDF."""
+
+ table_html = build_table(df)
+ env = Environment(autoescape=True)
+ template = env.from_string(TEMPLATE)
+ html_content = template.render(table=table_html, meta=meta, logo=logo)
+ Path(html_path).write_text(html_content, encoding="utf-8")
+
+ if pdf_path:
+ if pdfkit is not None:
+ pdfkit.from_string(html_content, pdf_path) # type: ignore[no-untyped-call]
+ elif HTML is not None:
+ HTML(string=html_content).write_pdf(pdf_path) # type: ignore[no-untyped-call]
+ else:
+ print("PDF output requested but no PDF backend is installed.")
+
+
+def main() -> None:
+ """Command line interface for the compliance dashboard."""
+
+ parser = argparse.ArgumentParser(description=__doc__)
+ parser.add_argument("input", help="CSV or Excel file containing inspection data")
+ parser.add_argument("--html", default="report.html", help="Output HTML report path")
+ parser.add_argument("--pdf", help="Optional output PDF path")
+ parser.add_argument(
+ "--logo", default="logo_placeholder.png", help="Path to CTRL logo image"
+ )
+ parser.add_argument("--site", default="Unknown Site")
+ parser.add_argument("--client", default="Unknown Client")
+ parser.add_argument("--inspector", default="Unknown Inspector")
+ parser.add_argument("--date", default=datetime.now(tz=UTC).date().isoformat())
+ args = parser.parse_args()
+
+ data = read_inspection_data(args.input)
+ if "Category" not in data.columns and "Finding" in data.columns:
+ data["Category"] = data["Finding"].map(categorize_finding)
+
+ meta = Metadata(args.site, args.client, args.inspector, args.date)
+ render_report(data, meta, args.logo, args.html, args.pdf)
+ print(f"Report written to {args.html}")
+
+
+if __name__ == "__main__":
+ main()
From 1b8189b277a81fe4300826c347d71f116d8425c7 Mon Sep 17 00:00:00 2001
From: beauagainagainagainagainagain
Date: Fri, 5 Sep 2025 18:16:11 +0000
Subject: [PATCH 3/4] updating DIRECTORY.md
---
DIRECTORY.md | 3 +++
1 file changed, 3 insertions(+)
diff --git a/DIRECTORY.md b/DIRECTORY.md
index d234d366df06..dae381649571 100644
--- a/DIRECTORY.md
+++ b/DIRECTORY.md
@@ -1331,6 +1331,9 @@
* [Word Patterns](strings/word_patterns.py)
* [Z Function](strings/z_function.py)
+## Sustainability
+ * [Ctrl Compliance Dashboard](sustainability/ctrl_compliance_dashboard.py)
+
## Web Programming
* [Co2 Emission](web_programming/co2_emission.py)
* [Covid Stats Via Xpath](web_programming/covid_stats_via_xpath.py)
From 19d29e7fcf0267306ace3e919106c639aef8b701 Mon Sep 17 00:00:00 2001
From: beauagainagainagainagainagain
<152763000+beauagainagainagainagainagain@users.noreply.github.com>
Date: Thu, 18 Sep 2025 01:40:08 +1000
Subject: [PATCH 4/4] Add script to refresh local git repositories
---
scripts/daily_refresh.py | 257 +++++++++++++++++++++++++++++++++++++++
1 file changed, 257 insertions(+)
create mode 100644 scripts/daily_refresh.py
diff --git a/scripts/daily_refresh.py b/scripts/daily_refresh.py
new file mode 100644
index 000000000000..2ad1f8194453
--- /dev/null
+++ b/scripts/daily_refresh.py
@@ -0,0 +1,257 @@
+"""Utilities for refreshing multiple Git repositories at once.
+
+This module provides a small command line application that searches for Git
+repositories under a given directory and executes ``git fetch --all --prune``
+for each of them. The goal is to make it easy to plug the script into a cron
+job (or any other scheduler) so that a server can refresh all of its local
+checkouts on a daily basis.
+
+Example usage that fetches every repository under ``/srv/git``::
+
+ $ python -m scripts.daily_refresh /srv/git
+
+For safety the script performs fast-forward pulls only when the
+``--pull`` flag is supplied. The ``--dry-run`` option can be used to inspect
+the commands that would be executed without touching the repositories.
+"""
+
+from __future__ import annotations
+
+import argparse
+import logging
+import shlex
+import subprocess
+from collections.abc import Iterable, Sequence
+from dataclasses import dataclass
+from pathlib import Path
+
+
+LOG_FORMAT = "%(asctime)s | %(levelname)-8s | %(message)s"
+
+
+@dataclass(slots=True)
+class RefreshResult:
+ """Container describing the outcome of refreshing a repository."""
+
+ repository: Path
+ command: Sequence[str]
+ returncode: int
+ stdout: str
+ stderr: str
+
+ @property
+ def succeeded(self) -> bool:
+ """Return ``True`` when the git command was successful."""
+
+ return self.returncode == 0
+
+
+def _discover_repositories(root: Path, excluded: set[Path]) -> list[Path]:
+ """Return every Git repository rooted at ``root``.
+
+ Parameters
+ ----------
+ root:
+ Directory that should be scanned. The path is resolved to avoid
+ surprises with symbolic links.
+ excluded:
+ Absolute paths that should not be traversed while searching. A
+ directory is considered excluded when it is equal to one of the
+ supplied paths or when it is a child of one.
+ """
+
+ repositories: list[Path] = []
+ root = root.resolve()
+
+ def is_excluded(path: Path) -> bool:
+ return any(path == item or item in path.parents for item in excluded)
+
+ def walk(directory: Path) -> None:
+ if is_excluded(directory):
+ logging.debug("Skipping excluded directory %s", directory)
+ return
+
+ git_directory = directory / ".git"
+ if git_directory.is_dir():
+ repositories.append(directory)
+ logging.debug("Found git repository in %s", directory)
+ return
+
+ for child in directory.iterdir():
+ if not child.is_dir() or child.is_symlink():
+ continue
+ walk(child)
+
+ walk(root)
+ return repositories
+
+
+def _run_git_command(
+ repository: Path, command: Sequence[str], *, dry_run: bool
+) -> RefreshResult:
+ full_command = ("git", "-C", str(repository), *command)
+ if dry_run:
+ logging.info("DRY-RUN %s", shlex.join(full_command))
+ return RefreshResult(repository, full_command, 0, "", "")
+
+ logging.info("Running %s", shlex.join(full_command))
+ process = subprocess.run( # noqa: S603, S607 - `git` is a trusted command.
+ full_command,
+ capture_output=True,
+ text=True,
+ check=False,
+ )
+ return RefreshResult(
+ repository,
+ full_command,
+ process.returncode,
+ process.stdout.strip(),
+ process.stderr.strip(),
+ )
+
+
+def refresh_repository(repository: Path, *, pull: bool, dry_run: bool) -> bool:
+ """Refresh ``repository`` by fetching and (optionally) pulling updates.
+
+ Parameters
+ ----------
+ repository:
+ Path to a directory containing a Git checkout.
+ pull:
+ When ``True`` the script performs a fast-forward pull after fetching.
+ dry_run:
+ When ``True`` the underlying git commands are not executed.
+ """
+
+ commands: Iterable[Sequence[str]] = [("fetch", "--all", "--prune")]
+ if pull:
+ commands = (*commands, ("pull", "--ff-only"))
+
+ for command in commands:
+ result = _run_git_command(repository, command, dry_run=dry_run)
+ if not result.succeeded:
+ logging.error(
+ "Failed to refresh %s with %s (exit code %s)",
+ repository,
+ shlex.join(result.command),
+ result.returncode,
+ )
+ if result.stdout:
+ logging.error("stdout: %s", result.stdout)
+ if result.stderr:
+ logging.error("stderr: %s", result.stderr)
+ return False
+
+ if result.stdout:
+ logging.debug("%s", result.stdout)
+ if result.stderr:
+ logging.debug("%s", result.stderr)
+
+ return True
+
+
+def _parse_arguments() -> argparse.Namespace:
+ parser = argparse.ArgumentParser(
+ description="Refresh every git repository found under a directory.",
+ )
+ parser.add_argument(
+ "root",
+ type=Path,
+ nargs="?",
+ default=Path.cwd(),
+ help="Directory that should be scanned for repositories.",
+ )
+ parser.add_argument(
+ "-e",
+ "--exclude",
+ action="append",
+ default=[],
+ metavar="PATH",
+ help=(
+ "Directory names (relative to ROOT) or absolute paths that should "
+ "be skipped while searching for repositories. The option can be "
+ "provided multiple times."
+ ),
+ )
+ parser.add_argument(
+ "-p",
+ "--pull",
+ action="store_true",
+ help="Perform a fast-forward pull after fetching.",
+ )
+ parser.add_argument(
+ "-n",
+ "--dry-run",
+ action="store_true",
+ help="Print the git commands without executing them.",
+ )
+ parser.add_argument(
+ "-v",
+ "--verbose",
+ action="count",
+ default=0,
+ help="Increase logging verbosity (can be supplied multiple times).",
+ )
+ parser.add_argument(
+ "-q",
+ "--quiet",
+ action="store_true",
+ help="Silence informational output.",
+ )
+ return parser.parse_args()
+
+
+def _prepare_excluded(root: Path, entries: list[str]) -> set[Path]:
+ excluded: set[Path] = set()
+ for entry in entries:
+ path = Path(entry)
+ if not path.is_absolute():
+ path = (root / path).resolve()
+ else:
+ path = path.resolve()
+ excluded.add(path)
+ return excluded
+
+
+def main() -> int:
+ args = _parse_arguments()
+
+ log_level = logging.INFO
+ if args.quiet:
+ log_level = logging.WARNING
+ elif args.verbose >= 2:
+ log_level = logging.DEBUG
+
+ logging.basicConfig(level=log_level, format=LOG_FORMAT)
+
+ root = args.root.resolve()
+ if not root.is_dir():
+ logging.error("%s is not a directory", root)
+ return 1
+
+ excluded = _prepare_excluded(root, args.exclude)
+ repositories = _discover_repositories(root, excluded)
+
+ if not repositories:
+ logging.warning("No Git repositories found under %s", root)
+ return 0
+
+ logging.info(
+ "Refreshing %s repositories under %s", len(repositories), root
+ )
+
+ failures = 0
+ for repository in repositories:
+ if not refresh_repository(repository, pull=args.pull, dry_run=args.dry_run):
+ failures += 1
+
+ if failures:
+ logging.error("Failed to refresh %s repositories", failures)
+ return 1
+
+ logging.info("Successfully refreshed all repositories")
+ return 0
+
+
+if __name__ == "__main__": # pragma: no cover - CLI entry point.
+ raise SystemExit(main())