From 29dae91f459f4b3b77fa3a8fe845693086a67260 Mon Sep 17 00:00:00 2001
From: jrg94 <11050412+jrg94@users.noreply.github.com>
Date: Mon, 20 Oct 2025 22:03:16 -0400
Subject: [PATCH 1/5] Added the add_alert method to document
---
snakemd/document.py | 38 ++++++++++++++++++++++++++++------
snakemd/templates.py | 4 ++--
tests/templates/test_alerts.py | 12 +++++------
3 files changed, 40 insertions(+), 14 deletions(-)
diff --git a/snakemd/document.py b/snakemd/document.py
index 25bb777..1008aac 100644
--- a/snakemd/document.py
+++ b/snakemd/document.py
@@ -23,7 +23,12 @@
Raw,
Table,
)
-from .templates import TableOfContents, Template
+from .templates import (
+ Alerts,
+ Template,
+ Checklist,
+ TableOfContents,
+)
logger = logging.getLogger(__name__)
@@ -263,7 +268,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.
@@ -282,10 +287,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,
@@ -432,6 +437,27 @@ def add_table_of_contents(self, levels: range = range(2, 3)) -> TableOfContents:
self._elements.append(toc)
logger.info("Added table of contents to document: %r", toc)
return toc
+
+ def add_alert(self, message: str, kind: Alerts.Kind = Alerts.Kind.NOTE) -> Alerts:
+ """
+ A convenience method which adds an alert to the document:
+
+ .. doctest:: document
+
+ >>> doc = snakemd.new_doc()
+ >>> doc.add_alert("Please subscribe")
+ Alert(message="Please subscribe", kind=Kind.NOTE)
+ >>> print(doc)
+ >> ![NOTE]\n>> 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
+ """
+ alert = Alerts(message, kind)
+ self._elements.append(alert)
+ logger.info("Added alert to document: %r", alert)
def scramble(self) -> None:
"""
diff --git a/snakemd/templates.py b/snakemd/templates.py
index 266a66b..06af2af 100644
--- a/snakemd/templates.py
+++ b/snakemd/templates.py
@@ -85,8 +85,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
diff --git a/tests/templates/test_alerts.py b/tests/templates/test_alerts.py
index 4679448..97581b5 100644
--- a/tests/templates/test_alerts.py
+++ b/tests/templates/test_alerts.py
@@ -2,25 +2,25 @@
from snakemd.templates import Alerts
def test_alerts_note():
- alert = Alerts(Alerts.Kind.NOTE, "Hello, World!")
+ alert = Alerts("Hello, World!", Alerts.Kind.NOTE)
assert str(alert) == "> [!NOTE]\n> Hello, World!"
def test_alerts_tip():
- alert = Alerts(Alerts.Kind.TIP, "Hello, World!")
+ alert = Alerts("Hello, World!", Alerts.Kind.TIP)
assert str(alert) == "> [!TIP]\n> Hello, World!"
def test_alerts_important():
- alert = Alerts(Alerts.Kind.IMPORTANT, "Hello, World!")
+ alert = Alerts("Hello, World!", Alerts.Kind.IMPORTANT)
assert str(alert) == "> [!IMPORTANT]\n> Hello, World!"
def test_alerts_warning():
- alert = Alerts(Alerts.Kind.WARNING, "Hello, World!")
+ alert = Alerts("Hello, World!", Alerts.Kind.WARNING)
assert str(alert) == "> [!WARNING]\n> Hello, World!"
def test_alerts_caution():
- alert = Alerts(Alerts.Kind.CAUTION, "Hello, World!")
+ alert = Alerts("Hello, World!", Alerts.Kind.CAUTION, )
assert str(alert) == "> [!CAUTION]\n> Hello, World!"
def test_alerts_inline():
- alert = Alerts(Alerts.Kind.NOTE, Inline("Hello, World!", italics=True))
+ alert = Alerts(Inline("Hello, World!", italics=True), Alerts.Kind.NOTE)
assert str(alert) == "> [!NOTE]\n> _Hello, World!_"
From 48a9e489ab47012f1d0e1e9b229777fa801fd5e0 Mon Sep 17 00:00:00 2001
From: jrg94 <11050412+jrg94@users.noreply.github.com>
Date: Mon, 20 Oct 2025 22:26:21 -0400
Subject: [PATCH 2/5] Fixed mistakes in docs
---
snakemd/document.py | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/snakemd/document.py b/snakemd/document.py
index 1008aac..94ed2c6 100644
--- a/snakemd/document.py
+++ b/snakemd/document.py
@@ -276,7 +276,7 @@ def add_checklist(self, items: Iterable[str]) -> Checklist:
>>> doc = snakemd.new_doc()
>>> doc.add_checklist(["Okabe", "Mayuri", "Kurisu"])
- MDList(items=[...], ordered=False, checked=False)
+ Checklist(items=[...], checked=False)
>>> print(doc)
- [ ] Okabe
- [ ] Mayuri
@@ -446,10 +446,11 @@ def add_alert(self, message: str, kind: Alerts.Kind = Alerts.Kind.NOTE) -> Alert
>>> doc = snakemd.new_doc()
>>> doc.add_alert("Please subscribe")
- Alert(message="Please subscribe", kind=Kind.NOTE)
+ Quote(content=[Raw(text='[!NOTE]'), Raw(text='Please subscribe')])
>>> print(doc)
- >> ![NOTE]\n>> Please subscribe
-
+ > [!NOTE]
+ > Please subscribe
+
:param str message:
a message that you want to stand out in your document
:param Kind kind:
@@ -458,6 +459,7 @@ def add_alert(self, message: str, kind: Alerts.Kind = Alerts.Kind.NOTE) -> Alert
alert = Alerts(message, kind)
self._elements.append(alert)
logger.info("Added alert to document: %r", alert)
+ return alert
def scramble(self) -> None:
"""
From fcd7f6512e7c6d21e9022fa91856373997830048 Mon Sep 17 00:00:00 2001
From: jrg94 <11050412+jrg94@users.noreply.github.com>
Date: Mon, 20 Oct 2025 22:35:25 -0400
Subject: [PATCH 3/5] Rebranded alerts to alert
---
snakemd/templates.py | 4 ++--
tests/templates/test_alerts.py | 26 +++++++++++++-------------
2 files changed, 15 insertions(+), 15 deletions(-)
diff --git a/snakemd/templates.py b/snakemd/templates.py
index 06af2af..dd6afb2 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.
diff --git a/tests/templates/test_alerts.py b/tests/templates/test_alerts.py
index 97581b5..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("Hello, World!", Alerts.Kind.NOTE)
+def test_alert_note():
+ alert = Alert("Hello, World!", Alert.Kind.NOTE)
assert str(alert) == "> [!NOTE]\n> Hello, World!"
-def test_alerts_tip():
- alert = Alerts("Hello, World!", Alerts.Kind.TIP)
+def test_alert_tip():
+ alert = Alert("Hello, World!", Alert.Kind.TIP)
assert str(alert) == "> [!TIP]\n> Hello, World!"
-def test_alerts_important():
- alert = Alerts("Hello, World!", Alerts.Kind.IMPORTANT)
+def test_alert_important():
+ alert = Alert("Hello, World!", Alert.Kind.IMPORTANT)
assert str(alert) == "> [!IMPORTANT]\n> Hello, World!"
-def test_alerts_warning():
- alert = Alerts("Hello, World!", Alerts.Kind.WARNING)
+def test_alert_warning():
+ alert = Alert("Hello, World!", Alert.Kind.WARNING)
assert str(alert) == "> [!WARNING]\n> Hello, World!"
-def test_alerts_caution():
- alert = Alerts("Hello, World!", Alerts.Kind.CAUTION, )
+def test_alert_caution():
+ alert = Alert("Hello, World!", Alert.Kind.CAUTION, )
assert str(alert) == "> [!CAUTION]\n> Hello, World!"
-def test_alerts_inline():
- alert = Alerts(Inline("Hello, World!", italics=True), Alerts.Kind.NOTE)
+def test_alert_inline():
+ alert = Alert(Inline("Hello, World!", italics=True), Alert.Kind.NOTE)
assert str(alert) == "> [!NOTE]\n> _Hello, World!_"
From 03f922a3213462f66c77bc76159a3fa2abf0bae4 Mon Sep 17 00:00:00 2001
From: jrg94 <11050412+jrg94@users.noreply.github.com>
Date: Mon, 20 Oct 2025 22:35:40 -0400
Subject: [PATCH 4/5] Added a convenience method for adding tables from csv
---
snakemd/document.py | 36 +++++++++++++++++++++++++++++++++---
1 file changed, 33 insertions(+), 3 deletions(-)
diff --git a/snakemd/document.py b/snakemd/document.py
index 94ed2c6..ec9b1dc 100644
--- a/snakemd/document.py
+++ b/snakemd/document.py
@@ -24,7 +24,8 @@
Table,
)
from .templates import (
- Alerts,
+ Alert,
+ CSVTable,
Template,
Checklist,
TableOfContents,
@@ -334,6 +335,33 @@ def add_table(
self._elements.append(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:
"""
@@ -438,7 +466,7 @@ 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: Alerts.Kind = Alerts.Kind.NOTE) -> Alerts:
+ def add_alert(self, message: str, kind: Alert.Kind = Alert.Kind.NOTE) -> Alert:
"""
A convenience method which adds an alert to the document:
@@ -455,8 +483,10 @@ def add_alert(self, message: str, kind: Alerts.Kind = Alerts.Kind.NOTE) -> Alert
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 = Alerts(message, kind)
+ alert = Alert(message, kind)
self._elements.append(alert)
logger.info("Added alert to document: %r", alert)
return alert
From 38397948ac6a07db6efcaee64cdbf3ebfe884327 Mon Sep 17 00:00:00 2001
From: jrg94 <11050412+jrg94@users.noreply.github.com>
Date: Mon, 20 Oct 2025 22:45:01 -0400
Subject: [PATCH 5/5] Cleaned up code
---
snakemd/document.py | 8 +++----
snakemd/elements.py | 55 ++++++++++++++++++++++----------------------
snakemd/templates.py | 10 ++++++--
3 files changed, 40 insertions(+), 33 deletions(-)
diff --git a/snakemd/document.py b/snakemd/document.py
index ec9b1dc..41d4a4f 100644
--- a/snakemd/document.py
+++ b/snakemd/document.py
@@ -27,8 +27,8 @@
Alert,
CSVTable,
Template,
- Checklist,
- TableOfContents,
+ Checklist,
+ TableOfContents,
)
logger = logging.getLogger(__name__)
@@ -335,7 +335,7 @@ def add_table(
self._elements.append(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
@@ -465,7 +465,7 @@ def add_table_of_contents(self, levels: range = range(2, 3)) -> TableOfContents:
self._elements.append(toc)
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:
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 dd6afb2..fe755c1 100644
--- a/snakemd/templates.py
+++ b/snakemd/templates.py
@@ -77,6 +77,11 @@ class Alert(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()
@@ -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 "