Make it work on 3.9 again

turns out I have some systems where I care about that :)
This commit is contained in:
Jeff Epler 2023-11-26 17:12:46 -06:00
parent 14f284defc
commit 5daf7e7d2a
No known key found for this signature in database
GPG key ID: D5BF15AB975AB4DE
5 changed files with 22 additions and 19 deletions

View file

@ -20,13 +20,14 @@ name="chap"
authors = [{name = "Jeff Epler", email = "jepler@gmail.com"}] authors = [{name = "Jeff Epler", email = "jepler@gmail.com"}]
description = "Interact with the OpenAI ChatGPT API (and other text generators)" description = "Interact with the OpenAI ChatGPT API (and other text generators)"
dynamic = ["readme","version","dependencies"] dynamic = ["readme","version","dependencies"]
requires-python = ">=3.10" requires-python = ">=3.9"
keywords = ["llm", "tui", "chatgpt"] keywords = ["llm", "tui", "chatgpt"]
classifiers = [ classifiers = [
"Development Status :: 3 - Alpha", "Development Status :: 3 - Alpha",
"License :: OSI Approved :: MIT License", "License :: OSI Approved :: MIT License",
"Operating System :: OS Independent", "Operating System :: OS Independent",
"Programming Language :: Python :: 3", "Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.12",

View file

@ -4,7 +4,7 @@
import asyncio import asyncio
import sys import sys
from typing import Iterable, Protocol from typing import Iterable, Optional, Protocol
import click import click
import rich import rich
@ -40,7 +40,7 @@ class DumbPrinter:
class WrappingPrinter: class WrappingPrinter:
def __init__(self, width: int | None = None) -> None: def __init__(self, width: Optional[int] = None) -> None:
self._width = width or rich.get_console().width self._width = width or rich.get_console().width
self._column = 0 self._column = 0
self._line = "" self._line = ""

View file

@ -5,7 +5,7 @@
import asyncio import asyncio
import subprocess import subprocess
import sys import sys
from typing import Any, cast from typing import Any, Optional, cast
from markdown_it import MarkdownIt from markdown_it import MarkdownIt
from textual import work from textual import work
@ -63,7 +63,7 @@ class Tui(App[None]):
] ]
def __init__( def __init__(
self, api: Backend | None = None, session: Session | None = None self, api: Optional[Backend] = None, session: Optional[Session] = None
) -> None: ) -> None:
super().__init__() super().__init__()
self.api = api or get_api("lorem") self.api = api or get_api("lorem")

View file

@ -11,8 +11,7 @@ import pathlib
import pkgutil import pkgutil
import subprocess import subprocess
from dataclasses import MISSING, dataclass, fields from dataclasses import MISSING, dataclass, fields
from types import UnionType from typing import Any, AsyncGenerator, Callable, Optional, Union, cast
from typing import Any, AsyncGenerator, Callable, cast
import click import click
import platformdirs import platformdirs
@ -22,6 +21,9 @@ from typing_extensions import Protocol
from . import backends, commands # pylint: disable=no-name-in-module from . import backends, commands # pylint: disable=no-name-in-module
from .session import Message, Session, System, session_from_file from .session import Message, Session, System, session_from_file
# 3.9 compatible version of `from types import UnionType`
UnionType = type(Union[int, list])
conversations_path = platformdirs.user_state_path("chap") / "conversations" conversations_path = platformdirs.user_state_path("chap") / "conversations"
conversations_path.mkdir(parents=True, exist_ok=True) conversations_path.mkdir(parents=True, exist_ok=True)
@ -54,14 +56,14 @@ class AutoAskMixin: # pylint: disable=too-few-public-methods
return "".join(tokens) return "".join(tokens)
def last_session_path() -> pathlib.Path | None: def last_session_path() -> Optional[pathlib.Path]:
result = max( result = max(
conversations_path.glob("*.json"), key=lambda p: p.stat().st_mtime, default=None conversations_path.glob("*.json"), key=lambda p: p.stat().st_mtime, default=None
) )
return result return result
def new_session_path(opt_path: pathlib.Path | None = None) -> pathlib.Path: def new_session_path(opt_path: Optional[pathlib.Path] = None) -> pathlib.Path:
return opt_path or conversations_path / ( return opt_path or conversations_path / (
datetime.datetime.now().isoformat().replace(":", "_") + ".json" datetime.datetime.now().isoformat().replace(":", "_") + ".json"
) )
@ -95,7 +97,7 @@ def get_api(name: str = "openai_chatgpt") -> Backend:
def do_session_continue( def do_session_continue(
ctx: click.Context, param: click.Parameter, value: pathlib.Path | None ctx: click.Context, param: click.Parameter, value: Optional[pathlib.Path]
) -> None: ) -> None:
if value is None: if value is None:
return return
@ -293,18 +295,18 @@ def version_callback( # pylint: disable=unused-argument
@dataclass @dataclass
class Obj: class Obj:
api: Backend | None = None api: Optional[Backend] = None
system_message: str | None = None system_message: Optional[str] = None
session: list[Message] | None = None session: Optional[list[Message]] = None
session_filename: pathlib.Path | None = None session_filename: Optional[pathlib.Path] = None
class MyCLI(click.MultiCommand): class MyCLI(click.MultiCommand):
def make_context( def make_context(
self, self,
info_name: str | None, info_name: Optional[str],
args: list[str], args: list[str],
parent: click.Context | None = None, parent: Optional[click.Context] = None,
**extra: Any, **extra: Any,
) -> click.Context: ) -> click.Context:
result = super().make_context(info_name, args, parent, obj=Obj(), **extra) result = super().make_context(info_name, args, parent, obj=Obj(), **extra)

View file

@ -7,7 +7,7 @@ from __future__ import annotations
import json import json
import pathlib import pathlib
from dataclasses import asdict, dataclass from dataclasses import asdict, dataclass
from typing import cast from typing import Union, cast
from typing_extensions import TypedDict from typing_extensions import TypedDict
@ -65,11 +65,11 @@ def session_from_json(data: str) -> Session:
return [Message(**mapping) for mapping in j] return [Message(**mapping) for mapping in j]
def session_from_file(path: pathlib.Path | str) -> Session: def session_from_file(path: Union[pathlib.Path, str]) -> Session:
with open(path, "r", encoding="utf-8") as f: with open(path, "r", encoding="utf-8") as f:
return session_from_json(f.read()) return session_from_json(f.read())
def session_to_file(session: Session, path: pathlib.Path | str) -> None: def session_to_file(session: Session, path: Union[pathlib.Path, str]) -> None:
with open(path, "w", encoding="utf-8") as f: with open(path, "w", encoding="utf-8") as f:
f.write(session_to_json(session)) f.write(session_to_json(session))