From 8021e12aaafdb452c9efd7b8571690f94efd579b Mon Sep 17 00:00:00 2001 From: Simon Willison Date: Fri, 26 Jan 2024 16:24:58 -0800 Subject: [PATCH] Windows readline fix, plus run CI against macOS and Windows * Run CI on Windows and macOS as well as Ubuntu, refs #407 * Use pyreadline3 on win32 * Back to fail-fast since we have a bigger matrix now * Mark some tests as xfail on windows --- .github/workflows/test.yml | 13 +++++++++---- docs/changelog.md | 5 +++++ setup.py | 3 ++- tests/test_chat.py | 5 +++++ tests/test_embed_cli.py | 2 ++ tests/test_keys.py | 3 +++ tests/test_llm.py | 2 ++ 7 files changed, 28 insertions(+), 5 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 133f3735..9d6a34d1 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -7,16 +7,16 @@ permissions: jobs: test: - runs-on: ubuntu-latest + runs-on: ${{ matrix.os }} strategy: - fail-fast: false matrix: + os: [ubuntu-latest, macos-latest, windows-latest] python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"] pydantic: ["==1.10.2", ">=2.0.0"] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} cache: pip @@ -29,20 +29,25 @@ jobs: run: | pytest - name: Check if cog needs to be run + if: matrix.os != 'windows-latest' run: | cog --check \ -p "import sys, os; sys._called_from_test=True; os.environ['LLM_USER_PATH'] = '/tmp'" \ docs/**/*.md docs/*.md - name: Run Black + if: matrix.os != 'windows-latest' run: | black --check . - name: Run mypy + if: matrix.os != 'windows-latest' run: | mypy llm - name: Run ruff + if: matrix.os != 'windows-latest' run: | ruff . - name: Run test-llm-load-plugins.sh + if: matrix.os != 'windows-latest' run: | llm install llm-cluster llm-mistral ./tests/test-llm-load-plugins.sh diff --git a/docs/changelog.md b/docs/changelog.md index ac5ffd59..a83635d3 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -1,5 +1,10 @@ # Changelog +(v0_13_1)= +## 0.13.1 (2024-01-26) + +- Fix for `No module named 'readline'` error on Windows. [#407](https://github.com/simonw/llm/issues/407) + (v0_13)= ## 0.13 (2024-01-26) diff --git a/setup.py b/setup.py index 4ab1c811..2ad17a89 100644 --- a/setup.py +++ b/setup.py @@ -1,7 +1,7 @@ from setuptools import setup, find_packages import os -VERSION = "0.13" +VERSION = "0.13.1" def get_long_description(): @@ -47,6 +47,7 @@ def get_long_description(): "python-ulid", "setuptools", "pip", + "pyreadline3; sys_platform == 'win32'", ], extras_require={ "test": [ diff --git a/tests/test_chat.py b/tests/test_chat.py index ab50f4aa..cf7ddeff 100644 --- a/tests/test_chat.py +++ b/tests/test_chat.py @@ -2,6 +2,7 @@ import llm.cli from unittest.mock import ANY import pytest +import sys def test_mock_model(mock_model): @@ -16,6 +17,7 @@ def test_mock_model(mock_model): assert response2.text() == "second" +@pytest.mark.xfail(sys.platform == "win32", reason="Expected to fail on Windows") def test_chat_basic(mock_model, logs_db): runner = CliRunner() mock_model.enqueue(["one world"]) @@ -112,6 +114,7 @@ def test_chat_basic(mock_model, logs_db): ] +@pytest.mark.xfail(sys.platform == "win32", reason="Expected to fail on Windows") def test_chat_system(mock_model, logs_db): runner = CliRunner() mock_model.enqueue(["I am mean"]) @@ -148,6 +151,7 @@ def test_chat_system(mock_model, logs_db): ] +@pytest.mark.xfail(sys.platform == "win32", reason="Expected to fail on Windows") def test_chat_options(mock_model, logs_db): runner = CliRunner() mock_model.enqueue(["Some text"]) @@ -175,6 +179,7 @@ def test_chat_options(mock_model, logs_db): ] +@pytest.mark.xfail(sys.platform == "win32", reason="Expected to fail on Windows") @pytest.mark.parametrize( "input,expected", ( diff --git a/tests/test_embed_cli.py b/tests/test_embed_cli.py index e9f3d2d9..007aac5d 100644 --- a/tests/test_embed_cli.py +++ b/tests/test_embed_cli.py @@ -5,6 +5,7 @@ import pathlib import pytest import sqlite_utils +import sys from unittest.mock import ANY @@ -422,6 +423,7 @@ def multi_files(tmpdir): return db_path, tmpdir / "files" +@pytest.mark.xfail(sys.platform == "win32", reason="Expected to fail on Windows") @pytest.mark.parametrize("scenario", ("single", "multi")) def test_embed_multi_files(multi_files, scenario): db_path, files = multi_files diff --git a/tests/test_keys.py b/tests/test_keys.py index b172664c..5c1d7d5a 100644 --- a/tests/test_keys.py +++ b/tests/test_keys.py @@ -3,8 +3,10 @@ from llm.cli import cli import pathlib import pytest +import sys +@pytest.mark.xfail(sys.platform == "win32", reason="Expected to fail on Windows") @pytest.mark.parametrize("env", ({}, {"LLM_USER_PATH": "/tmp/llm-keys-test"})) def test_keys_in_user_path(monkeypatch, env, user_path): for key, value in env.items(): @@ -19,6 +21,7 @@ def test_keys_in_user_path(monkeypatch, env, user_path): assert result.output.strip() == expected +@pytest.mark.xfail(sys.platform == "win32", reason="Expected to fail on Windows") def test_keys_set(monkeypatch, tmpdir): user_path = tmpdir / "user/keys" monkeypatch.setenv("LLM_USER_PATH", str(user_path)) diff --git a/tests/test_llm.py b/tests/test_llm.py index 9f8457ab..acfdc2bc 100644 --- a/tests/test_llm.py +++ b/tests/test_llm.py @@ -8,6 +8,7 @@ import pytest import re import sqlite_utils +import sys from ulid import ULID from unittest import mock @@ -96,6 +97,7 @@ def test_logs_json(n, log_path): assert len(logs) == expected_length +@pytest.mark.xfail(sys.platform == "win32", reason="Expected to fail on Windows") @pytest.mark.parametrize("env", ({}, {"LLM_USER_PATH": "/tmp/llm-user-path"})) def test_logs_path(monkeypatch, env, user_path): for key, value in env.items():