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
218159if __name__ == "__main__" :
0 commit comments