diff --git a/snakemd/document.py b/snakemd/document.py
index 25bb777..41d4a4f 100644
--- a/snakemd/document.py
+++ b/snakemd/document.py
@@ -23,7 +23,13 @@
Raw,
Table,
)
-from .templates import TableOfContents, Template
+from .templates import (
+ Alert,
+ CSVTable,
+ Template,
+ Checklist,
+ TableOfContents,
+)
logger = logging.getLogger(__name__)
@@ -263,7 +269,7 @@ def add_unordered_list(self, items: Iterable[str]) -> MDList:
logger.info("Added unordered list to document: %r", md_list)
return md_list
- def add_checklist(self, items: Iterable[str]) -> MDList:
+ def add_checklist(self, items: Iterable[str]) -> Checklist:
"""
A convenience method which adds a checklist to the document.
@@ -271,7 +277,7 @@ def add_checklist(self, items: Iterable[str]) -> MDList:
>>> doc = snakemd.new_doc()
>>> doc.add_checklist(["Okabe", "Mayuri", "Kurisu"])
- MDList(items=[...], ordered=False, checked=False)
+ Checklist(items=[...], checked=False)
>>> print(doc)
- [ ] Okabe
- [ ] Mayuri
@@ -282,10 +288,10 @@ def add_checklist(self, items: Iterable[str]) -> MDList:
:return:
the :class:`MDList` added to this Document
"""
- md_checklist = MDList(items, checked=False)
- self._elements.append(md_checklist)
- logger.info("Added checklist to document: %r", md_checklist)
- return md_checklist
+ checklist = Checklist(items, checked=False)
+ self._elements.append(checklist)
+ logger.info("Added checklist to document: %r", checklist)
+ return checklist
def add_table(
self,
@@ -330,6 +336,33 @@ def add_table(
logger.info("Added table to document: %r", table)
return table
+ def add_table_from_csv(self, path: os.PathLike) -> CSVTable:
+ """
+ A convenience method which adds a table from a CSV file to
+ the document:
+
+ .. doctest:: document
+
+ >>> doc = snakemd.new_doc()
+ >>> doc.add_table_from_csv("../tests/resources/python-support.csv")
+ Table(header=[...], body=[...], align=None, indent=0)
+ >>> print(doc) # doctest: +NORMALIZE_WHITESPACE
+ | Python | 3.11 | 3.10 | 3.9 | 3.8 |
+ | ------------------- | ---- | ---- | --- | --- |
+ | SnakeMD >= 2.0 | Yes | Yes | Yes | Yes |
+ | SnakeMD 0.12 - 0.15 | Yes | Yes | Yes | Yes |
+ | SnakeMD < 0.12 | | Yes | Yes | Yes |
+
+ :param os.PathLike path:
+ a path to a CSV file
+ :return:
+ the :class:`Table` added to this Document
+ """
+ table = CSVTable(path)
+ self._elements.append(table)
+ logger.info("Added table to document: %r", table)
+ return table
+
def add_code(self, code: str, lang: str = "generic") -> Code:
"""
A convenience method which adds a code block to the document:
@@ -433,6 +466,31 @@ def add_table_of_contents(self, levels: range = range(2, 3)) -> TableOfContents:
logger.info("Added table of contents to document: %r", toc)
return toc
+ def add_alert(self, message: str, kind: Alert.Kind = Alert.Kind.NOTE) -> Alert:
+ """
+ A convenience method which adds an alert to the document:
+
+ .. doctest:: document
+
+ >>> doc = snakemd.new_doc()
+ >>> doc.add_alert("Please subscribe")
+ Quote(content=[Raw(text='[!NOTE]'), Raw(text='Please subscribe')])
+ >>> print(doc)
+ > [!NOTE]
+ > Please subscribe
+
+ :param str message:
+ a message that you want to stand out in your document
+ :param Kind kind:
+ the kind of alert; see :class:`snakemd.Alerts.Kind` for details
+ :return:
+ the :class:`Alert` added to this Document
+ """
+ alert = Alert(message, kind)
+ self._elements.append(alert)
+ logger.info("Added alert to document: %r", alert)
+ return alert
+
def scramble(self) -> None:
"""
A silly method which mixes all of the blocks in this document in
diff --git a/snakemd/elements.py b/snakemd/elements.py
index c6a034c..c3c9921 100644
--- a/snakemd/elements.py
+++ b/snakemd/elements.py
@@ -108,7 +108,8 @@ class Inline(Element):
the line break state of the inline text
- defaults to :code:`False`
- - set to :code:`True` to add a line break to the end of the element (i.e., `
`)
+ - set to :code:`True` to add a line break to the
+ end of the element (i.e., `
`)
"""
def __init__(
@@ -385,7 +386,7 @@ def uncode(self) -> Inline:
"""
self._code = False
return self
-
+
def breakline(self) -> Inline:
"""
Adds a linebreak to self.
@@ -401,7 +402,7 @@ def breakline(self) -> Inline:
"""
self._linebreak = True
return self
-
+
def unbreakline(self) -> Inline:
"""
Removes linebreak from self.
@@ -481,7 +482,7 @@ def reset(self) -> Inline:
self._bold = False
self._strikethrough = False
return self
-
+
def _apply_styles_from(self, text: Inline) -> Inline:
"""
A helper method that applies text styling to self from another
@@ -862,8 +863,9 @@ def __init__(
checked if checked is None or isinstance(checked, bool) else list(checked)
)
self._space = ""
- if isinstance(self._checked, list) and MDList._top_level_count(self._items) != len(
- self._checked
+ if (
+ isinstance(self._checked, list)
+ and MDList._top_level_count(self._items) != len(self._checked)
):
raise ValueError(
"Number of top-level elements in checklist does not "
@@ -1117,28 +1119,27 @@ def _replace_any(self, target: str, text: Inline, count: int = -1) -> Paragraph:
if not inline_text.is_text() or target not in inline_text.get_text():
content.append(inline_text)
continue
- # Split the inline element into pieces and reapply styles
- else:
- # Redistributes styles
- items = [
- Inline(item)._apply_styles_from(inline_text)
- for item in inline_text.get_text().split(target, count)
- ]
-
- # Adds text back in with appropriate style information
- for item in items:
- content.append(item)
- content.append(text._apply_styles_from(inline_text))
+
+ # Split the inline element into pieces
+ items = [
+ Inline(item)._apply_styles_from(inline_text)
+ for item in inline_text.get_text().split(target, count)
+ ]
+
+ # Adds text back in with appropriate style information
+ for item in items:
+ content.append(item)
+ content.append(text._apply_styles_from(inline_text))
+ content.pop()
+
+ # Trim empty strings from edges
+ if content[-1].get_text() == "":
content.pop()
-
- # Trim empty strings from edges
- if content[-1].get_text() == "":
- content.pop()
- if content[0].get_text() == "":
- content = content[1:]
-
- # Remove line breaks that may have been distributed by applying styles
- content[:-1] = map(lambda item: item.unbreakline(), content[:-1])
+ if content[0].get_text() == "":
+ content = content[1:]
+
+ # Remove line breaks that may have been distributed by applying styles
+ content[:-1] = map(lambda item: item.unbreakline(), content[:-1])
self._content = content
return self
diff --git a/snakemd/templates.py b/snakemd/templates.py
index 266a66b..fe755c1 100644
--- a/snakemd/templates.py
+++ b/snakemd/templates.py
@@ -55,9 +55,9 @@ def load(self, elements: list[Element]) -> None:
self._elements = elements
-class Alerts(Template):
+class Alert(Template):
"""
- Alerts are a wrapper of the Quote object to provide
+ Alert is a wrapper of the Quote object to provide
support for the alerts Markdown extension. While
quotes can be nested in each other, alerts cannot.
@@ -77,6 +77,11 @@ class Alerts(Template):
"""
class Kind(Enum):
+ """
+ Kind is an enum representing the different
+ kinds of alerts that you might place in a
+ document.
+ """
NOTE = auto()
TIP = auto()
IMPORTANT = auto()
@@ -85,8 +90,8 @@ class Kind(Enum):
def __init__(
self,
- kind: Kind,
- message: str | Iterable[str | Inline | Block]
+ message: str | Iterable[str | Inline | Block],
+ kind: Kind
) -> None:
super().__init__()
self._kind = kind
@@ -154,8 +159,9 @@ def __init__(
checked, bool) else list(checked)
)
self._space = ""
- if isinstance(self._checked, list) and MDList._top_level_count(self._items) != len(
- self._checked
+ if (
+ isinstance(self._checked, list)
+ and MDList._top_level_count(self._items) != len(self._checked)
):
raise ValueError(
"Number of top-level elements in checklist does not "
diff --git a/tests/templates/test_alerts.py b/tests/templates/test_alerts.py
index 4679448..56a6b0b 100644
--- a/tests/templates/test_alerts.py
+++ b/tests/templates/test_alerts.py
@@ -1,26 +1,26 @@
from snakemd.elements import Inline
-from snakemd.templates import Alerts
+from snakemd.templates import Alert
-def test_alerts_note():
- alert = Alerts(Alerts.Kind.NOTE, "Hello, World!")
+def test_alert_note():
+ alert = Alert("Hello, World!", Alert.Kind.NOTE)
assert str(alert) == "> [!NOTE]\n> Hello, World!"
-def test_alerts_tip():
- alert = Alerts(Alerts.Kind.TIP, "Hello, World!")
+def test_alert_tip():
+ alert = Alert("Hello, World!", Alert.Kind.TIP)
assert str(alert) == "> [!TIP]\n> Hello, World!"
-def test_alerts_important():
- alert = Alerts(Alerts.Kind.IMPORTANT, "Hello, World!")
+def test_alert_important():
+ alert = Alert("Hello, World!", Alert.Kind.IMPORTANT)
assert str(alert) == "> [!IMPORTANT]\n> Hello, World!"
-def test_alerts_warning():
- alert = Alerts(Alerts.Kind.WARNING, "Hello, World!")
+def test_alert_warning():
+ alert = Alert("Hello, World!", Alert.Kind.WARNING)
assert str(alert) == "> [!WARNING]\n> Hello, World!"
-def test_alerts_caution():
- alert = Alerts(Alerts.Kind.CAUTION, "Hello, World!")
+def test_alert_caution():
+ alert = Alert("Hello, World!", Alert.Kind.CAUTION, )
assert str(alert) == "> [!CAUTION]\n> Hello, World!"
-def test_alerts_inline():
- alert = Alerts(Alerts.Kind.NOTE, Inline("Hello, World!", italics=True))
+def test_alert_inline():
+ alert = Alert(Inline("Hello, World!", italics=True), Alert.Kind.NOTE)
assert str(alert) == "> [!NOTE]\n> _Hello, World!_"