Compare commits

..

8 Commits

2 changed files with 58 additions and 10 deletions

View File

@ -1,5 +1,5 @@
""" """
Module implementing the 'Chat' class and functions for managing a chat history. Module implementing various chat classes and functions for managing a chat history.
""" """
import pathlib import pathlib
from dataclasses import dataclass from dataclasses import dataclass
@ -7,6 +7,7 @@ from typing import TypeVar, Type, Optional
from .message import Message, MessageFilter, MessageError from .message import Message, MessageFilter, MessageError
ChatInst = TypeVar('ChatInst', bound='Chat') ChatInst = TypeVar('ChatInst', bound='Chat')
ChatDirInst = TypeVar('ChatDirInst', bound='ChatDir')
class ChatError(Exception): class ChatError(Exception):
@ -16,22 +17,45 @@ class ChatError(Exception):
@dataclass @dataclass
class Chat: class Chat:
""" """
Class containing a complete chat history. A class containing a complete chat history.
""" """
messages: list[Message] messages: list[Message]
def filter(self, mfilter: MessageFilter) -> None:
"""
Use 'Message.match(mfilter) to remove all messages that
don't fulfill the filter requirements.
"""
self.messages = [m for m in self.messages if m.match(mfilter)]
@dataclass
class ChatDir:
"""
A Chat class that is bound to a given directory. Supports reading
and writing messages from / to that directory.
"""
messages: list[Message]
directory: pathlib.Path
# a MessageFilter that all messages must match (if given)
mfilter: Optional[MessageFilter] = None
# set containing all file names of the current messages
message_files: set[str] = set()
@classmethod @classmethod
def from_dir(cls: Type[ChatInst], def from_dir(cls: Type[ChatDirInst],
path: pathlib.Path, path: pathlib.Path,
glob: Optional[str] = None, glob: Optional[str] = None,
mfilter: Optional[MessageFilter] = None) -> ChatInst: mfilter: Optional[MessageFilter] = None) -> ChatDirInst:
""" """
Create a Chat instance from the message in the given directory. Create a ChatDir instance from the given directory. If 'glob' is specified,
If glob is specified, files will be filtered using path.glob(), files will be filtered using 'path.glob()', otherwise it uses 'path.iterdir()'.
otherwise it uses path.iterdir(). Messages are created using Messages are created using 'Message.from_file()' and the optional MessageFilter.
Message.from_file() and the optional MessageFilter.
""" """
messages: list[Message] = [] messages: list[Message] = []
message_files: set[str] = set()
file_iter = path.glob(glob) if glob else path.iterdir() file_iter = path.glob(glob) if glob else path.iterdir()
for file_path in file_iter: for file_path in file_iter:
if file_path.is_file(): if file_path.is_file():
@ -39,6 +63,30 @@ class Chat:
message = Message.from_file(file_path, mfilter) message = Message.from_file(file_path, mfilter)
if message: if message:
messages.append(message) messages.append(message)
message_files.add(file_path.name)
except MessageError as e: except MessageError as e:
print(f"Error processing message in '{file_path}': {str(e)}") print(f"Error processing message in '{file_path}': {str(e)}")
return cls(messages) return cls(messages, path, mfilter, message_files)
@classmethod
def from_messages(cls: Type[ChatDirInst],
path: pathlib.Path,
messages: list[Message],
mfilter: Optional[MessageFilter]) -> ChatDirInst:
"""
Create a ChatDir instance from the given message list.
Note that the next call to 'dump()' will write all files
in order to synchronize the messages. 'update()' is not
supported until after the first 'dump()'.
"""
return cls(messages, path, mfilter)
# def dump(self) -> None:
# """
# Writes all messages to the bound directory. If a message has no file_path,
# it will create a new one.
# """
# for message in self.messages:
# # TODO: determine file name if message does not have one
# if message.file_path.name() not in self.message_files:
# message.to_file()

View File

@ -326,7 +326,7 @@ class Message():
data[cls.file_yaml_key] = file_path data[cls.file_yaml_key] = file_path
return cls.from_dict(data) return cls.from_dict(data)
def to_file(self, file_path: Optional[pathlib.Path]) -> None: # noqa: 11 def to_file(self, file_path: Optional[pathlib.Path]=None) -> None: # noqa: 11
""" """
Write a Message to the given file. Type is determined based on the suffix. Write a Message to the given file. Type is determined based on the suffix.
Currently supported suffixes: ['.txt', '.yaml'] Currently supported suffixes: ['.txt', '.yaml']