Compare commits
7 Commits
4c674b80a6
...
5e818d4af7
| Author | SHA1 | Date | |
|---|---|---|---|
| 5e818d4af7 | |||
| ea617282b1 | |||
| d5099cf37a | |||
| d5326b7874 | |||
| 176c1b634d | |||
| 03304bdbc6 | |||
| 57de2415ee |
@ -3,32 +3,19 @@ Module implementing message related functions and classes.
|
||||
"""
|
||||
import pathlib
|
||||
import yaml
|
||||
from typing import Type, TypeVar, ClassVar, Optional, Any, Union
|
||||
from typing import Type, TypeVar, ClassVar, Optional, Any
|
||||
from dataclasses import dataclass, asdict
|
||||
from .tags import Tag, TagLine
|
||||
|
||||
QuestionInst = TypeVar('QuestionInst', bound='Question')
|
||||
AnswerInst = TypeVar('AnswerInst', bound='Answer')
|
||||
MessageInst = TypeVar('MessageInst', bound='Message')
|
||||
YamlDict = dict[str, Union[QuestionInst, AnswerInst, set[Tag]]]
|
||||
|
||||
|
||||
class MessageError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
def str_presenter(dumper: yaml.Dumper, data: str) -> yaml.ScalarNode:
|
||||
"""
|
||||
Changes the YAML dump style to multiline syntax for multiline strings.
|
||||
"""
|
||||
if len(data.splitlines()) > 1:
|
||||
return dumper.represent_scalar('tag:yaml.org,2002:str', data, style='|')
|
||||
return dumper.represent_scalar('tag:yaml.org,2002:str', data)
|
||||
|
||||
|
||||
yaml.add_representer(str, str_presenter)
|
||||
|
||||
|
||||
def source_code(text: str, include_delims: bool = False) -> list[str]:
|
||||
"""
|
||||
Extract all source code sections from the given text, i. e. all lines
|
||||
@ -167,9 +154,7 @@ class Message():
|
||||
* Question
|
||||
* Answer.Header
|
||||
For '.yaml':
|
||||
* question: single or multiline string
|
||||
* answer: single or multiline string
|
||||
* tags: list of strings
|
||||
TODO
|
||||
"""
|
||||
if not file_path.exists():
|
||||
raise MessageError(f"Message file '{file_path}' does not exist")
|
||||
@ -190,6 +175,7 @@ class Message():
|
||||
return cls(question, answer, tags, file_path)
|
||||
else: # '.yaml'
|
||||
with open(file_path, "r") as fd:
|
||||
# FIXME: use the actual YAML format
|
||||
data = yaml.load(fd, Loader=yaml.FullLoader)
|
||||
data['file_path'] = file_path
|
||||
return cls.from_dict(data)
|
||||
@ -204,9 +190,7 @@ class Message():
|
||||
* Answer.Header
|
||||
* Answer
|
||||
For '.yaml':
|
||||
* question: single or multiline string
|
||||
* answer: single or multiline string
|
||||
* tags: list of strings
|
||||
TODO
|
||||
"""
|
||||
if file_path:
|
||||
self.file_path = file_path
|
||||
@ -220,14 +204,7 @@ class Message():
|
||||
fd.write(f'{TagLine.from_set(msg_tags)}\n')
|
||||
fd.write(f'{Question.header}\n{self.question}\n')
|
||||
fd.write(f'{Answer.header}\n{self.answer}\n')
|
||||
elif self.file_path.suffix == '.yaml':
|
||||
with open(self.file_path, "w") as fd:
|
||||
data: YamlDict = {'question': str(self.question)}
|
||||
if self.answer:
|
||||
data['answer'] = str(self.answer)
|
||||
if self.tags:
|
||||
data['tags'] = sorted([str(tag) for tag in self.tags])
|
||||
yaml.dump(data, fd)
|
||||
# FIXME: write YAML format
|
||||
|
||||
def as_dict(self) -> dict[str, Any]:
|
||||
return asdict(self)
|
||||
|
||||
@ -86,8 +86,8 @@ class MessageToFileTxtTestCase(CmmTestCase):
|
||||
def setUp(self) -> None:
|
||||
self.file = tempfile.NamedTemporaryFile(delete=False, suffix='.txt')
|
||||
self.file_path = pathlib.Path(self.file.name)
|
||||
self.message = Message(Question('This is a question.'),
|
||||
Answer('This is an answer.'),
|
||||
self.message = Message(Question('This is a question'),
|
||||
Answer('This is an answer'),
|
||||
{Tag('tag1'), Tag('tag2')},
|
||||
self.file_path)
|
||||
|
||||
@ -100,12 +100,7 @@ class MessageToFileTxtTestCase(CmmTestCase):
|
||||
|
||||
with open(self.file_path, "r") as fd:
|
||||
content = fd.read()
|
||||
expected_content = """TAGS: tag1 tag2
|
||||
=== QUESTION ===
|
||||
This is a question.
|
||||
=== ANSWER ===
|
||||
This is an answer.
|
||||
"""
|
||||
expected_content = "TAGS: tag1 tag2\n=== QUESTION ===\nThis is a question\n=== ANSWER ===\nThis is an answer\n"
|
||||
self.assertEqual(content, expected_content)
|
||||
|
||||
def test_to_file_unsupported_file_type(self) -> None:
|
||||
@ -127,55 +122,12 @@ This is an answer.
|
||||
self.message.file_path = self.file_path
|
||||
|
||||
|
||||
class MessageToFileYamlTestCase(CmmTestCase):
|
||||
def setUp(self) -> None:
|
||||
self.file = tempfile.NamedTemporaryFile(delete=False, suffix='.yaml')
|
||||
self.file_path = pathlib.Path(self.file.name)
|
||||
self.message = Message(Question('This is a question.'),
|
||||
Answer('This is an answer.'),
|
||||
{Tag('tag1'), Tag('tag2')},
|
||||
self.file_path)
|
||||
self.message_multiline = Message(Question('This is a\nmultiline question.'),
|
||||
Answer('This is a\nmultiline answer.'),
|
||||
{Tag('tag1'), Tag('tag2')},
|
||||
self.file_path)
|
||||
|
||||
def tearDown(self) -> None:
|
||||
self.file.close()
|
||||
self.file_path.unlink()
|
||||
|
||||
def test_to_file_yaml(self) -> None:
|
||||
self.message.to_file(self.file_path)
|
||||
|
||||
with open(self.file_path, "r") as fd:
|
||||
content = fd.read()
|
||||
expected_content = "answer: This is an answer.\nquestion: This is a question.\ntags:\n- tag1\n- tag2\n"
|
||||
self.assertEqual(content, expected_content)
|
||||
|
||||
def test_to_file_yaml_multiline(self) -> None:
|
||||
self.message_multiline.to_file(self.file_path)
|
||||
|
||||
with open(self.file_path, "r") as fd:
|
||||
content = fd.read()
|
||||
expected_content = """answer: |-
|
||||
This is a
|
||||
multiline answer.
|
||||
question: |-
|
||||
This is a
|
||||
multiline question.
|
||||
tags:
|
||||
- tag1
|
||||
- tag2
|
||||
"""
|
||||
self.assertEqual(content, expected_content)
|
||||
|
||||
|
||||
class MessageFromFileTxtTestCase(CmmTestCase):
|
||||
def setUp(self) -> None:
|
||||
self.file = tempfile.NamedTemporaryFile(delete=False, suffix='.txt')
|
||||
self.file_path = pathlib.Path(self.file.name)
|
||||
with open(self.file_path, "w") as fd:
|
||||
fd.write("TAGS: tag1 tag2\n=== QUESTION ===\nThis is a question.\n=== ANSWER ===\nThis is an answer.\n")
|
||||
fd.write("TAGS: tag1 tag2\n=== QUESTION ===\nThis is a question\n=== ANSWER ===\nThis is an answer\n")
|
||||
|
||||
def tearDown(self) -> None:
|
||||
self.file.close()
|
||||
@ -184,39 +136,13 @@ class MessageFromFileTxtTestCase(CmmTestCase):
|
||||
def test_from_file_txt(self) -> None:
|
||||
message = Message.from_file(self.file_path)
|
||||
self.assertIsInstance(message, Message)
|
||||
self.assertEqual(message.question, 'This is a question.')
|
||||
self.assertEqual(message.answer, 'This is an answer.')
|
||||
self.assertEqual(message.question, 'This is a question')
|
||||
self.assertEqual(message.answer, 'This is an answer')
|
||||
self.assertSetEqual(cast(set[Tag], message.tags), {Tag('tag1'), Tag('tag2')})
|
||||
self.assertEqual(message.file_path, self.file_path)
|
||||
|
||||
def test_from_file_not_exists(self) -> None:
|
||||
file_not_exists = pathlib.Path("example.txt")
|
||||
with self.assertRaises(MessageError) as cm:
|
||||
Message.from_file(file_not_exists)
|
||||
self.assertEqual(str(cm.exception), f"Message file '{file_not_exists}' does not exist")
|
||||
|
||||
|
||||
class MessageFromFileYamlTestCase(CmmTestCase):
|
||||
def setUp(self) -> None:
|
||||
self.file = tempfile.NamedTemporaryFile(delete=False, suffix='.yaml')
|
||||
self.file_path = pathlib.Path(self.file.name)
|
||||
with open(self.file_path, "w") as fd:
|
||||
fd.write("question: |-\n This is a question.\nanswer: |-\n This is an answer.\ntags:\n- tag1\n- tag2")
|
||||
|
||||
def tearDown(self) -> None:
|
||||
self.file.close()
|
||||
self.file_path.unlink()
|
||||
|
||||
def test_from_file_yaml(self) -> None:
|
||||
message = Message.from_file(self.file_path)
|
||||
self.assertIsInstance(message, Message)
|
||||
self.assertEqual(message.question, 'This is a question.')
|
||||
self.assertEqual(message.answer, 'This is an answer.')
|
||||
self.assertSetEqual(cast(set[Tag], message.tags), {Tag('tag1'), Tag('tag2')})
|
||||
self.assertEqual(message.file_path, self.file_path)
|
||||
|
||||
def test_from_file_not_exists(self) -> None:
|
||||
file_not_exists = pathlib.Path("example.yaml")
|
||||
file_not_exists = pathlib.Path("example.doc")
|
||||
with self.assertRaises(MessageError) as cm:
|
||||
Message.from_file(file_not_exists)
|
||||
self.assertEqual(str(cm.exception), f"Message file '{file_not_exists}' does not exist")
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user