Compare commits

..

3 Commits

2 changed files with 55 additions and 11 deletions

View File

@ -64,3 +64,6 @@ class Config():
def to_file(self, path: str) -> None: def to_file(self, path: str) -> None:
with open(path, 'w') as f: with open(path, 'w') as f:
yaml.dump(asdict(self), f) yaml.dump(asdict(self), f)
def asdict(self) -> dict[str, Any]:
return asdict(self)

View File

@ -1,10 +1,14 @@
""" """
Module implementing message related functions and classes. Module implementing message related functions and classes.
""" """
from typing import Type, TypeVar import pathlib
from typing import Type, TypeVar, Optional, Any
from dataclasses import dataclass, asdict
from .tags import Tag
QuestionInst = TypeVar('QuestionInst', bound='Question') QuestionInst = TypeVar('QuestionInst', bound='Question')
AnswerInst = TypeVar('AnswerInst', bound='Answer') AnswerInst = TypeVar('AnswerInst', bound='Answer')
MessageInst = TypeVar('MessageInst', bound='Message')
class MessageError(Exception): class MessageError(Exception):
@ -39,16 +43,16 @@ def source_code(text: str, include_delims: bool = False) -> list[str]:
class Question(str): class Question(str):
""" """
A single question with a defined prefix. A single question with a defined header.
""" """
prefix = '=== QUESTION ===' header = '=== QUESTION ==='
def __new__(cls: Type[QuestionInst], string: str) -> QuestionInst: def __new__(cls: Type[QuestionInst], string: str) -> QuestionInst:
""" """
Make sure the question string does not contain the prefix. Make sure the question string does not contain the header.
""" """
if cls.prefix in string: if cls.header in string:
raise MessageError(f"Question '{string}' contains the prefix '{cls.prefix}'") raise MessageError(f"Question '{string}' contains the header '{cls.header}'")
instance = super().__new__(cls, string) instance = super().__new__(cls, string)
return instance return instance
@ -61,16 +65,16 @@ class Question(str):
class Answer(str): class Answer(str):
""" """
A single answer with a defined prefix. A single answer with a defined header.
""" """
prefix = '=== ANSWER ===' header = '=== ANSWER ==='
def __new__(cls: Type[AnswerInst], string: str) -> AnswerInst: def __new__(cls: Type[AnswerInst], string: str) -> AnswerInst:
""" """
Make sure the answer string does not contain the prefix. Make sure the answer string does not contain the header.
""" """
if cls.prefix in string: if cls.header in string:
raise MessageError(f"Answer '{string}' contains the prefix '{cls.prefix}'") raise MessageError(f"Answer '{string}' contains the header '{cls.header}'")
instance = super().__new__(cls, string) instance = super().__new__(cls, string)
return instance return instance
@ -79,3 +83,40 @@ class Answer(str):
Extract and return all source code sections. Extract and return all source code sections.
""" """
return source_code(self, include_delims) return source_code(self, include_delims)
@dataclass
class Message():
"""
Single message. Consists of a question and optionally an answer, a set of tags
and a file path.
"""
question: Question
answer: Optional[Answer]
tags: Optional[set[Tag]]
path: Optional[pathlib.Path]
# @classmethod
# def from_file(cls: Type[MessageInst], path: str) -> MessageInst:
# """
# Create a Message from the given file. Expects the following file structure:
# * TagLine (from 'self.tags')
# * Question.Header
# * Question
# * Answer.Header
# """
# pass
def to_file(self, path: str) -> None:
"""
Write Message to the given file. Creates the following file structure:
* TagLine (from 'self.tags')
* Question.Header
* Question
* Answer.Header
* Answer
"""
pass
def asdict(self) -> dict[str, Any]:
return asdict(self)