3
3
from typing import Optional
4
4
5
5
import feedparser
6
+ import requests
6
7
from bs4 import BeautifulSoup
7
- from snakemd import Document , InlineText , Table
8
-
8
+ from snakemd import Document , Inline , Table
9
9
10
10
logger = logging .getLogger (__name__ )
11
11
@@ -22,7 +22,7 @@ def main() -> None:
22
22
raise ValueError (f'Invalid log level: { loglevel } ' )
23
23
logging .basicConfig (level = numeric_level )
24
24
how_to = HowTo ()
25
- how_to .page .output_page ( " " )
25
+ how_to .page .dump ( "README " )
26
26
27
27
28
28
def _get_log_level () -> str :
@@ -70,7 +70,7 @@ def get_series_posts() -> list:
70
70
return feed
71
71
72
72
73
- def get_youtube_video (entry ) -> InlineText :
73
+ def get_youtube_video (entry ) -> Inline :
74
74
"""
75
75
Generates an InlineText item corresponding to the YouTube
76
76
video link if it exists. Otherwise, it returns an empty
@@ -81,41 +81,84 @@ def get_youtube_video(entry) -> InlineText:
81
81
"""
82
82
content = entry .content [0 ].value
83
83
soup = BeautifulSoup (content , "html.parser" )
84
- target = soup .find ("h2" , text = "Video Summary" )
84
+ target = soup .find ("h2" , string = "Video Summary" )
85
85
if target :
86
86
url = target .find_next_sibling ().find_all ("a" )[- 1 ]["href" ]
87
- return InlineText ("Video" , url = url )
88
- return InlineText ("" )
87
+ return Inline ("Video" , link = url )
88
+ return Inline ("" )
89
89
90
90
91
91
def get_slug (title : str , sep : str ) -> str :
92
+ """
93
+ Converts a title to a slug.
94
+
95
+ :param title: title of item
96
+ :param sep: the separator to use in place of whitespace
97
+ :return: a slug from a title
98
+ """
92
99
return title .split (":" )[0 ][:- 10 ].lower ().replace (" " , sep )
93
100
94
101
95
- def get_challenge (title : str ) -> InlineText :
102
+ def verify_url (url : str ) -> bool :
103
+ """
104
+ Checks that a URL exists.
105
+
106
+ :param url: the URL to verify
107
+ :return: True if the URL exists; False otherwise
108
+ """
109
+ try :
110
+ r = requests .get (url )
111
+ if r .status_code == 404 :
112
+ logger .debug (f"URL does not exist: { url } " )
113
+ return False
114
+ except :
115
+ logger .warning (f"Issue loading URL: { url } " )
116
+ return False
117
+ return True
118
+
119
+
120
+ def get_challenge (title : str ) -> Inline :
121
+ """
122
+ Retrieves the link to the challenge code samples.
123
+
124
+ :param title: the title of the article
125
+ :return: the link to the challenge folder, if it exists
126
+ """
96
127
slug = get_slug (title , "-" )
97
128
base = "https://github.com/TheRenegadeCoder/how-to-python-code/tree/main/challenges/"
98
- challenge = InlineText ("Challenge" , url = f"{ base } { slug } " )
99
- if not challenge . verify_url ():
100
- return InlineText ("" )
129
+ challenge = Inline ("Challenge" , link = f"{ base } { slug } " )
130
+ if not verify_url (challenge . _link ):
131
+ return Inline ("" )
101
132
return challenge
102
133
103
134
104
- def get_notebook (title : str ) -> InlineText :
135
+ def get_notebook (title : str ) -> Inline :
136
+ """
137
+ Retrieves the link to the Jupyter Notebook for the article.
138
+
139
+ :param title: the title of the article
140
+ :return: the link to the notebook, if it exists
141
+ """
105
142
slug = get_slug (title , "_" )
106
143
base = "https://github.com/TheRenegadeCoder/how-to-python-code/tree/main/notebooks/"
107
- notebook = InlineText ("Notebook" , f"{ base } { slug } .ipynb" )
108
- if not notebook . verify_url ():
109
- return InlineText ("" )
144
+ notebook = Inline ("Notebook" , link = f"{ base } { slug } .ipynb" )
145
+ if not verify_url (notebook . _link ):
146
+ return Inline ("" )
110
147
return notebook
111
148
112
149
113
- def get_test (title : str ) -> InlineText :
150
+ def get_test (title : str ) -> Inline :
151
+ """
152
+ Retrieves the test file for the article.
153
+
154
+ :param title: the title of the article
155
+ :return: the link to the test, if it exists
156
+ """
114
157
slug = get_slug (title , "_" )
115
158
base = "https://github.com/TheRenegadeCoder/how-to-python-code/tree/main/testing/"
116
- test = InlineText ("Test" , f"{ base } { slug } .py" )
117
- if not test . verify_url ():
118
- return InlineText ("" )
159
+ test = Inline ("Test" , link = f"{ base } { slug } .py" )
160
+ if not verify_url (test . _link ):
161
+ return Inline ("" )
119
162
return test
120
163
121
164
@@ -130,10 +173,10 @@ def _load_data(self):
130
173
self .feed = get_series_posts ()
131
174
132
175
def _build_readme (self ):
133
- self .page = Document ("README" )
176
+ self .page = Document ()
134
177
135
178
# Introduction
136
- self .page .add_header ("How to Python - Source Code" )
179
+ self .page .add_heading ("How to Python - Source Code" )
137
180
self .page .add_paragraph (_get_intro_text ()) \
138
181
.insert_link ("How to Python" , "https://therenegadecoder.com/series/how-to-python/" ) \
139
182
.insert_link (
@@ -153,25 +196,25 @@ def _build_readme(self):
153
196
"Testing"
154
197
]
155
198
table = Table (
156
- [InlineText (header ) for header in headers ],
199
+ [Inline (header ) for header in headers ],
157
200
self .build_table ()
158
201
)
159
- self .page .add_element (table )
202
+ self .page .add_block (table )
160
203
161
- def build_table (self ) -> list [list [InlineText ]]:
204
+ def build_table (self ) -> list [list [Inline ]]:
162
205
index = 1
163
206
body = []
164
207
for entry in self .feed :
165
208
if "Code Snippets" not in entry .title :
166
- article = InlineText ("Article" , url = entry .link )
209
+ article = Inline ("Article" , link = entry .link )
167
210
youtube = get_youtube_video (entry )
168
211
challenge = get_challenge (entry .title )
169
212
notebook = get_notebook (entry .title )
170
213
test = get_test (entry .title )
171
214
body .append ([
172
- InlineText (str (index )),
173
- InlineText (entry .title ),
174
- InlineText (entry .published ),
215
+ Inline (str (index )),
216
+ Inline (entry .title ),
217
+ Inline (entry .published ),
175
218
article ,
176
219
youtube ,
177
220
challenge ,
0 commit comments