.github,tests: use macos-15 in GitHub Actions
- ID
6cf02ef- date
2025-10-03 20:33:20+00:00- author
Alex Chan <alex@alexwlchan.net>- parent
b9daafd- message
.github,tests: use macos-15 in GitHub Actions This patch updates to the latest version of macOS, and precompiles the `get_live_text` binary to fix an error "IOServiceMatchingfailed for: AppleM2ScalerParavirtDriver" which is only occurring in CI. Fixes #2- changed files
6 files, 130 additions, 115 deletions
Changed files
.github/workflows/test.yml (630) → .github/workflows/test.yml (502)
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 5ab3260..ad016be 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -11,9 +11,7 @@ on:
jobs:
test:
- # I'm trying pinning this to an older version to see if it fixes
- # https://github.com/alexwlchan/get_live_text/issues/2
- runs-on: macos-13
+ runs-on: macos-15
steps:
- uses: actions/checkout@v5
@@ -21,7 +19,7 @@ jobs:
- name: Set up Python
uses: actions/setup-python@v6
with:
- python-version: "3.12"
+ python-version: "3.13"
cache: 'pip'
cache-dependency-path: 'dev_requirements.txt'
.github/workflows/upload_binaries.yml (1283) → .github/workflows/upload_binaries.yml (1098)
diff --git a/.github/workflows/upload_binaries.yml b/.github/workflows/upload_binaries.yml
index 57a6175..42a47f2 100644
--- a/.github/workflows/upload_binaries.yml
+++ b/.github/workflows/upload_binaries.yml
@@ -21,13 +21,11 @@ jobs:
upload-assets:
strategy:
matrix:
-
- # See https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners/about-github-hosted-runners#standard-github-hosted-runners-for-public-repositories
include:
- target: aarch64-apple-darwin
os: macos-latest
- target: x86_64-apple-darwin
- os: macos-13
+ os: macos-latest
runs-on: ${{ matrix.os }}
dev_requirements.txt (557) → dev_requirements.txt (437)
diff --git a/dev_requirements.txt b/dev_requirements.txt
index f166961..5ab423a 100644
--- a/dev_requirements.txt
+++ b/dev_requirements.txt
@@ -1,16 +1,14 @@
# This file was autogenerated by uv via the following command:
# uv pip compile dev_requirements.in --output-file dev_requirements.txt
-exceptiongroup==1.3.0
- # via pytest
execnet==2.1.1
# via pytest-xdist
-iniconfig==2.0.0
+iniconfig==2.1.0
# via pytest
-packaging==24.0
+packaging==25.0
# via pytest
-pluggy==1.5.0
+pluggy==1.6.0
# via pytest
-pygments==2.19.1
+pygments==2.19.2
# via pytest
pytest==8.4.2
# via
@@ -18,7 +16,3 @@ pytest==8.4.2
# pytest-xdist
pytest-xdist==3.8.0
# via -r dev_requirements.in
-tomli==2.2.1
- # via pytest
-typing-extensions==4.13.2
- # via exceptiongroup
tests/conftest.py (0) → tests/conftest.py (473)
diff --git a/tests/conftest.py b/tests/conftest.py
new file mode 100644
index 0000000..6a5c720
--- /dev/null
+++ b/tests/conftest.py
@@ -0,0 +1,20 @@
+import os
+import subprocess
+
+import pytest
+
+
+@pytest.fixture(scope="session")
+def bin_path(tmp_path_factory: pytest.TempPathFactory) -> str:
+ """
+ Compiles a new `get_live_text` binary, and returns a path to the binary.
+ """
+ p = tmp_path_factory.mktemp("bin") / "get_live_text"
+ p.parent.mkdir(exist_ok=True)
+
+ subprocess.check_call(
+ ["swiftc", os.path.abspath("get_live_text.swift")], cwd=p.parent
+ )
+ assert p.exists()
+
+ return str(p)
tests/test_get_live_text.py (1979) → tests/test_get_live_text.py (3206)
diff --git a/tests/test_get_live_text.py b/tests/test_get_live_text.py
index 62719ed..d2d1124 100755
--- a/tests/test_get_live_text.py
+++ b/tests/test_get_live_text.py
@@ -1,79 +1,119 @@
#!/usr/bin/env python3
import os
-import pathlib
-import plistlib
+from pathlib import Path
import re
+import subprocess
import pytest
-from utils import get_live_text
-
-def test_gets_empty_result_if_no_text() -> None:
- result = get_live_text(["tests/fixtures/checkerboard.png"])
-
- assert result == {
- "returncode": 0,
- "stdout": "\n",
- "stderr": None,
- }
-
-
-def test_gets_text_from_image() -> None:
- result = get_live_text(["tests/fixtures/with_text.png"])
-
- assert result == {
- "returncode": 0,
- "stdout": "This is an image with more than one block of text\n",
- "stderr": None,
- }
-
-
-def test_gives_useful_error_if_no_such_file() -> None:
- result = get_live_text(["tests/fixtures/doesnotexist.gif"])
-
- assert result == {
- "returncode": 1,
- "stdout": None,
- "stderr": "Cannot find file at path: tests/fixtures/doesnotexist.gif\n",
- }
-
-
-def test_gives_useful_error_if_cannot_recognize_image(tmp_path: pathlib.Path) -> None:
- with open(tmp_path / "broken.tif", "wb") as outfile:
- outfile.write(b"helloworld")
-
- result = get_live_text([str(tmp_path / "broken.tif")])
-
- assert result["returncode"] == 1
- assert result["stdout"] is None
- assert result["stderr"].startswith("Unable to recognise text:")
+def test_gets_empty_result_if_no_text(bin_path: Path) -> None:
+ """
+ If you pass an image without any text, you get empty output.
+ """
+ proc = subprocess.Popen(
+ [bin_path, "tests/fixtures/checkerboard.png"],
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ )
+ stdout, stderr = proc.communicate()
+
+ assert proc.returncode == 0
+ assert stdout == b"\n"
+
+ if os.environ.get("GITHUB_ACTIONS") != "true":
+ assert stderr == b""
+
+
+def test_gets_text_from_image(bin_path: Path) -> None:
+ """
+ If you pass an image that contains text, it gets printed to stdout.
+ """
+ proc = subprocess.Popen(
+ [bin_path, "tests/fixtures/with_text.png"],
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ )
+ stdout, stderr = proc.communicate()
+
+ assert proc.returncode == 0
+ assert stdout == b"This is an image with more than one block of text\n"
+
+ if os.environ.get("GITHUB_ACTIONS") != "true":
+ assert stderr == b""
+
+
+def test_gives_useful_error_if_no_such_file(bin_path: Path) -> None:
+ """
+ If you pass a path that doesn't exist, you get a useful error.
+ """
+ proc = subprocess.Popen(
+ [bin_path, "tests/fixtures/doesnotexist.gif"],
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ )
+ stdout, stderr = proc.communicate()
+
+ assert proc.returncode == 1
+ assert stdout == b""
+ assert stderr == b"Cannot find file at path: tests/fixtures/doesnotexist.gif\n"
+
+
+def test_gives_useful_error_if_cannot_recognize_image(bin_path: Path) -> None:
+ """
+ If you pass a path that doesn't look like an image, you get a useful error.
+ """
+ proc = subprocess.Popen(
+ [bin_path, "README.md"],
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ )
+ stdout, stderr = proc.communicate()
+
+ assert proc.returncode == 1
+ assert stdout == b""
+ assert stderr.startswith(b"Unable to recognise text:")
@pytest.mark.parametrize(
"argv",
[
pytest.param([], id="no_arguments"),
- pytest.param(["example.png", "example.gif", "--debug"], id="too_many_arguments"),
+ pytest.param(
+ ["example.png", "example.gif", "--debug"], id="too_many_arguments"
+ ),
],
)
-def test_it_fails_if_you_supply_the_wrong_arguments(argv: list[str]) -> None:
- result = get_live_text(argv)
-
- assert result == {
- "returncode": 1,
- "stdout": None,
- "stderr": "Usage: get_live_text.swift <PATH>\n",
- }
-
-
-
-def test_prints_the_version() -> None:
- result = get_live_text(["--version"])
-
- assert result["returncode"] == 0
- assert result["stderr"] is None
- assert re.match(
- r"^get_live_text.swift [0-9]+\.[0-9]+\.[0-9]+\n$", result["stdout"]
- ), result["stdout"]
+def test_it_fails_if_you_supply_the_wrong_arguments(
+ bin_path: Path, argv: list[str]
+) -> None:
+ """
+ If you pass the wrong arguments, you get an error explaining how to use it.
+ """
+ proc = subprocess.Popen(
+ [bin_path] + argv,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ )
+ stdout, stderr = proc.communicate()
+
+ assert proc.returncode == 1
+ assert stdout == b""
+ assert stderr.startswith(b"Usage:")
+
+
+def test_prints_the_version(bin_path: Path) -> None:
+ """
+ If you run it with the --version flag, it prints the version number.
+ """
+ proc = subprocess.Popen(
+ [bin_path, "--version"],
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ )
+ stdout, stderr = proc.communicate()
+
+ assert proc.returncode == 0
+ assert re.match(r"get_live_text [0-9]+\.[0-9]+\.[0-9]+\n$", stdout.decode("utf8"))
+ assert stderr == b""
tests/utils.py (794) → tests/utils.py (0)
diff --git a/tests/utils.py b/tests/utils.py
deleted file mode 100644
index 3b10776..0000000
--- a/tests/utils.py
+++ /dev/null
@@ -1,35 +0,0 @@
-import pathlib
-import subprocess
-import typing
-
-
-class CommandOutput(typing.TypedDict):
- returncode: int
- stdout: str | None
- stderr: str | None
-
-
-def get_live_text(argv: list[str | pathlib.Path]) -> CommandOutput:
- """
- Run the ``get_live_text.swift`` script and return the result.
- """
- cmd = ["swift", "get_live_text.swift"] + [str(av) for av in argv]
-
- proc = subprocess.Popen(
- cmd,
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE,
- )
- stdout, stderr = proc.communicate()
-
- if stdout is not None:
- stdout = stdout.decode("utf8")
-
- if stderr is not None:
- stderr = stderr.decode("utf8")
-
- return CommandOutput(
- returncode=proc.returncode,
- stdout=stdout or None,
- stderr=stderr or None,
- )