Make it work on 3.9 again
turns out I have some systems where I care about that :)
This commit is contained in:
parent
14f284defc
commit
5daf7e7d2a
5 changed files with 22 additions and 19 deletions
|
|
@ -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",
|
||||||
|
|
|
||||||
|
|
@ -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 = ""
|
||||||
|
|
|
||||||
|
|
@ -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")
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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))
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue