Skip to content

Commit a4f2085

Browse files
Dídac Colldidix21
authored andcommitted
Refactor Header
- Now instead of using Header.choose_header() method must be used str(Header()). - Add new enums for defining Header styles and Header levels.
1 parent 2d31ac5 commit a4f2085

File tree

3 files changed

+167
-234
lines changed

3 files changed

+167
-234
lines changed

mdutils/mdutils.py

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
import mdutils.tools.Table
2222
import mdutils.tools.TableOfContents
2323
from mdutils.fileutils.fileutils import MarkDownFile
24-
from mdutils.tools.Header import Header
24+
from mdutils.tools.Header import Header, HeaderStyle
2525
from mdutils.tools.Image import Image
2626
from mdutils.tools.Link import Inline, Reference
2727
from mdutils.tools.TextUtils import TextUtils
@@ -57,9 +57,8 @@ def __init__(self, file_name: str, title: str = "", author: str = ""):
5757
"""
5858
self.file_name = file_name
5959
self.author = author
60-
self.header = Header()
6160
self.textUtils = TextUtils
62-
self.title = self.header.choose_header(level=1, title=title, style="setext")
61+
self.title = str(Header(level=1, title=title, style=HeaderStyle.SETEXT))
6362
self.table_of_contents = ""
6463
self.file_data_text = ""
6564
self._table_titles = []
@@ -136,9 +135,9 @@ def new_header(
136135
if add_table_of_contents == "y":
137136
self.__add_new_item_table_of_content(level, title)
138137
self.___update_file_data(
139-
self.header.choose_header(level, title, style, header_id)
138+
str(Header(level, title, HeaderStyle[style.upper()], header_id))
140139
)
141-
return self.header.choose_header(level, title, style, header_id)
140+
return str(Header(level, title, HeaderStyle[style.upper()], header_id))
142141

143142
def __add_new_item_table_of_content(self, level: int, item: Union[List[str], str]):
144143
"""Automatically add new atx headers to the table of contents.
@@ -182,9 +181,9 @@ def new_table_of_contents(
182181

183182
if marker:
184183
self.table_of_contents = ""
185-
marker_table_of_contents = self.header.choose_header(
186-
level=1, title=table_title, style="setext"
187-
)
184+
marker_table_of_contents = str(Header(
185+
level=1, title=table_title, style=HeaderStyle.SETEXT
186+
))
188187
marker_table_of_contents += mdutils.tools.TableOfContents.TableOfContents().create_table_of_contents(
189188
self._table_titles, depth
190189
)
@@ -193,9 +192,9 @@ def new_table_of_contents(
193192
)
194193
else:
195194
marker_table_of_contents = ""
196-
self.table_of_contents += self.header.choose_header(
197-
level=1, title=table_title, style="setext"
198-
)
195+
self.table_of_contents += str(Header(
196+
level=1, title=table_title, style=HeaderStyle.SETEXT
197+
))
199198
self.table_of_contents += mdutils.tools.TableOfContents.TableOfContents().create_table_of_contents(
200199
self._table_titles, depth
201200
)

mdutils/tools/Header.py

Lines changed: 97 additions & 156 deletions
Original file line numberDiff line numberDiff line change
@@ -1,161 +1,115 @@
1-
# Python
2-
#
3-
# This module implements a text class that allows to modify and create text on Markdown files.
4-
#
5-
# This file is part of mdutils. https://github.com/didix21/mdutils
6-
#
7-
# MIT License: (C) 2020 Dídac Coll
1+
from enum import Enum, auto
2+
import warnings
83

94

10-
class Header:
11-
"""Contain the main methods to define Headers on a Markdown file.
5+
class AtxHeaderLevel(Enum):
6+
TITLE = auto() # H1 - Main title (largest and most important)
7+
HEADING = auto() # H2 - Section headings
8+
SUBHEADING = auto() # H3 - Subsection headings
9+
SUBSUBHEADING = auto() # H4 - Smaller subsection headings
10+
MINORHEADING = auto() # H5 - Even smaller headings
11+
LEASTHEADING = auto() # H6 - The smallest heading level
1212

13-
**Features available:**
1413

15-
* Create Markdown Titles: *atx* and *setext* formats are available.
16-
* Create Header Hanchors.
17-
* Auto generate a table of contents.
18-
* Create Tables.
19-
* **Bold**, *italics*, ``inline_code`` text converters.
20-
* Align text to center.
21-
* Add color to text.
22-
"""
14+
class SetextHeaderLevel(Enum):
15+
TITLE = auto()
16+
HEADING = auto()
2317

24-
# ********************************************************************
25-
# * Atx-Style *
26-
# ********************************************************************
27-
@staticmethod
28-
def atx_level_1(title: str, header_id: str = "") -> str:
29-
"""Return a atx level 1 header.
3018

31-
:param str title: text title.
32-
:param header_id: ID of the header for extended Markdown syntax
33-
:return: a header title of form: ``'\\n#' + title + '\\n'``
34-
:rtype: str
35-
"""
36-
if len(header_id):
37-
header_id = " {#" + header_id + "}"
38-
39-
return "\n# " + title + header_id + "\n"
19+
class HeaderStyle(Enum):
20+
ATX = auto()
21+
SETEXT = auto()
4022

41-
@staticmethod
42-
def atx_level_2(title: str, header_id: str = "") -> str:
43-
"""Return a atx level 2 header.
4423

45-
:param str title: text title.
46-
:param header_id: ID of the header for extended Markdown syntax
47-
:return: a header title of form: ``'\\n##' + title + '\\n'``
48-
:rtype: str
49-
"""
50-
if len(header_id):
51-
header_id = " {#" + header_id + "}"
52-
53-
return "\n## " + title + header_id + "\n"
54-
55-
@staticmethod
56-
def atx_level_3(title: str, header_id: str = "") -> str:
57-
"""Return a atx level 3 header.
24+
class Header:
25+
"""Contain the main methods to define Headers on a Markdown file.
5826
59-
:param str title: text title.
60-
:param header_id: ID of the header for extended Markdown syntax
61-
:return: a header title of form: ``'\\n###' + title + '\\n'``
62-
:rtype: str
63-
"""
64-
if len(header_id):
65-
header_id = " {#" + header_id + "}"
27+
Features available:
28+
- Create Markdown Titles: *atx* and *setext* formats are available.
29+
- Create Header Anchors.
6630
67-
return "\n### " + title + header_id + "\n"
31+
:Example:
32+
>>> str(Header(level=1, title='New Header', style=HeaderStyle.ATX))
33+
"""
6834

69-
@staticmethod
70-
def atx_level_4(title: str, header_id: str = "") -> str:
71-
"""Return a atx level 4 header.
35+
def __init__(self, level: int, title: str, style: HeaderStyle, header_id: str = None) -> None:
36+
"""Choose and return the header based on the given level, style, and title.
7237
73-
:param str title: text title.
74-
:param header_id: ID of the header for extended Markdown syntax
75-
:return: a header title of form: ``'\\n####' + title + '\\n'``
76-
:rtype: str
38+
:param level: HeaderLevel enum member, e.g., TITLE, HEADING, SUBHEADING, etc.
39+
:param title: Text title.
40+
:param style: HeaderStyle enum member, e.g., ATX, SETEXT.
41+
:param header_id: ID of the header for extended Markdown syntax (optional)
42+
:return: a header string based on the given level, style, and title
7743
"""
78-
if len(header_id):
79-
header_id = " {#" + header_id + "}"
44+
self.level = level
45+
self.title = title
46+
self.style = style
47+
self.header_id = header_id
8048

81-
return "\n#### " + title + header_id + "\n"
49+
def __str__(self) -> str:
50+
return self._new(self.level, self.title, self.style, self.header_id)
8251

8352
@staticmethod
84-
def atx_level_5(title: str, header_id: str = "") -> str:
85-
"""Return a atx level 5 header.
53+
def atx(level: AtxHeaderLevel, title: str, header_id: str = None) -> str:
54+
"""Return an atx-style header.
8655
87-
:param str title: text title.
88-
:param header_id: ID of the header for extended Markdown syntax
89-
:return: a header title of form: ``'\\n#####' + title + '\\n'``
90-
:rtype: str
56+
:param title: Text title.
57+
:param level: HeaderLevel enum member, e.g., TITLE, HEADING, SUBHEADING, etc.
58+
:param header_id: ID of the header for extended Markdown syntax (optional)
59+
:return: an atx-style header string
9160
"""
92-
if len(header_id):
93-
header_id = " {#" + header_id + "}"
94-
95-
return "\n##### " + title + header_id + "\n"
61+
header_id = Header._get_header_id(header_id)
62+
return "\n" + "#" * level.value + " " + title + header_id + "\n"
9663

9764
@staticmethod
98-
def atx_level_6(title: str, header_id: str = "") -> str:
99-
"""Return a atx level 6 header.
65+
def setext(level: SetextHeaderLevel, title: str) -> str:
66+
"""Return a setext-style header.
10067
101-
:param str title: text title.
102-
:param header_id: ID of the header for extended Markdown syntax
103-
:return: a header title of form: ``'\\n######' + title + '\\n'``
104-
:rtype: str
68+
:param title: Text title.
69+
:param level: HeaderLevel enum member, e.g., TITLE, HEADING.
70+
:return: a setext-style header string
10571
"""
106-
if len(header_id):
107-
header_id = " {#" + header_id + "}"
72+
if level == SetextHeaderLevel.TITLE:
73+
separator = "="
74+
else:
75+
separator = "-"
10876

109-
return "\n###### " + title + header_id + "\n"
77+
return "\n" + title + "\n" + separator * len(title) + "\n"
11078

111-
# ********************************************************************
112-
# * Setext-Style *
113-
# ********************************************************************
11479
@staticmethod
115-
def setext_level_1(title: str) -> str:
116-
"""Return a setext level 1 header.
80+
def header_anchor(text: str, link: str = None) -> str:
81+
"""Create an internal link to a defined header level in the markdown file.
11782
118-
:param str title: text title.
119-
:return: a header titlte of form: ``'\\n' + title +'\\n==========\\n'``.
120-
:rtype: str
121-
"""
83+
:param text: Displayed text for the link.
84+
:param link: Internal link (optional). If not provided, it is generated based on the text.
85+
:return: a header anchor string
12286
123-
return "\n" + title + "\n" + "".join(["=" for _ in title]) + "\n"
87+
Examples:
12488
125-
@staticmethod
126-
def setext_level_2(title: str) -> str:
127-
"""Return a setext level 1 header.
89+
1. Using the default generated link based on the text:
90+
91+
>>> header_link = Header.header_anchor("Section 1")
92+
>>> print(header_link)
93+
[Section 1](#section-1)
12894
129-
:param str title: text title.
130-
:return: a header titlte of form: ``'\\n' + title +'\\n------------\\n'``.
131-
:rtype: str
132-
"""
133-
134-
return "\n" + title + "\n" + "".join(["-" for _ in title]) + "\n"
135-
136-
@staticmethod
137-
def header_anchor(text: str, link: str = "") -> str:
138-
"""Creates an internal link of a defined Header level 1 or level 2 in the markdown file.
95+
2. Providing a custom link:
13996
140-
Giving a text string an text link you can create an internal link of already existing header. If the ``link``
141-
string does not contain '#', it will creates an automatic link of the type ``#title-1``.
97+
>>> header_link = Header.header_anchor("Section 1", "custom-link")
98+
>>> print(header_link)
99+
[Section 1](#custom-link)
142100
143-
:param text: it is the text that will be displayed.
144-
:param link: it is the internal link.
145-
:return: ``'[text](#link)'``
146-
:type text: str
147-
:type link: str
148-
:rtype: string
101+
3. Providing a link with an existing '#' symbol:
149102
150-
**Example:** [Title 1](#title-1)
103+
>>> header_link = Header.header_anchor("Section 1", "#existing-link")
104+
>>> print(header_link)
105+
[Section 1](#existing-link)
151106
"""
152-
if link:
153-
if link[0] != "#":
154-
link = link.lower().replace(" ", "-")
155-
else:
156-
link = "#" + link
157-
else:
107+
if not link:
158108
link = "#" + text.lower().replace(" ", "-")
109+
elif link[0] != "#":
110+
link = link.lower().replace(" ", "-")
111+
else:
112+
link = "#" + link
159113

160114
return "[" + text + "](" + link + ")"
161115

@@ -180,39 +134,26 @@ def choose_header(
180134
:param header_id: ID of the header for extended Markdown syntax
181135
:return:
182136
"""
183-
if style.lower() == "atx":
184-
if level == 1:
185-
return Header.atx_level_1(title, header_id)
186-
elif level == 2:
187-
return Header.atx_level_2(title, header_id)
188-
elif level == 3:
189-
return Header.atx_level_3(title, header_id)
190-
elif level == 4:
191-
return Header.atx_level_4(title, header_id)
192-
elif level == 5:
193-
return Header.atx_level_5(title, header_id)
194-
elif level == 6:
195-
return Header.atx_level_6(title, header_id)
196-
else:
197-
raise ValueError(
198-
"For 'atx' style, level's expected value: 1, 2, 3, 4, 5 or 6, but level = "
199-
+ str(level)
200-
)
201-
elif style.lower() == "setext":
202-
if level == 1:
203-
return Header.setext_level_1(title)
204-
elif level == 2:
205-
return Header.setext_level_2(title)
206-
else:
207-
raise ValueError(
208-
"For 'setext' style, level's expected value: 1, 2, 3, 4, 5 or 6, but level = "
209-
+ str(level)
210-
)
137+
warnings.warn(
138+
"This method is deprecated. Use the Header class instead, `str(Header())`, this method will be removed on 3.0.0 version",
139+
DeprecationWarning,
140+
stacklevel=2,
141+
)
142+
return str(Header(level, title, HeaderStyle[style.upper()], header_id))
143+
144+
def _new(self, level: int, title: str, style: HeaderStyle = HeaderStyle.ATX, header_id: str = None) -> str:
145+
if style == HeaderStyle.ATX:
146+
return Header.atx(AtxHeaderLevel(level), title, header_id)
147+
elif style == HeaderStyle.SETEXT:
148+
return Header.setext(SetextHeaderLevel(level), title)
211149
else:
212-
raise ValueError(
213-
"style's expected value: 'atx' or 'setext', but style = "
214-
+ style.lower()
215-
)
150+
raise ValueError("style's expected value: 'HeaderStyle.ATX' or 'HeaderStyle.SETEXT'")
151+
152+
@staticmethod
153+
def _get_header_id(header_id: str = None) -> str:
154+
if header_id:
155+
return " {#" + header_id + "}"
156+
return ""
216157

217158

218159
if __name__ == "__main__":

0 commit comments

Comments
 (0)