-
Notifications
You must be signed in to change notification settings - Fork 2
/
htmlcssgrade.py
330 lines (283 loc) · 15.1 KB
/
htmlcssgrade.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
#######################
# HTML/CSS Grade
# Version 1.1.1
# Created by Joe Mazzone
# Documentation: https://github.com/MrMazzone/HTML-CSS-Grade
#######################
from bs4 import BeautifulSoup
import cssutils
import logging
import os
class HTML_Check:
"""
Create an object that allows you to check student HTML code.
Properties
----------
filepath - the path to the file you are checking.
html_obj - the BeautifulSoup object being used.
code - text representation of the css file, which can be printed or parsed.
Methods
-------
check_HTML() - Given a snip of HTML code, returns True if the snip is found in the student's file.
check_element_used() - Given an element, returns True if the student used the element.
check_num_element_used() - Given an element and number, returns True if student's file has at least specified number of that element.
get_num_element_used() - Given an element, returns the number of times the element is used in student's file.
get_element_content() - Given an element, returns the content of that element.
get_all_element_content() - Given an element, returns a list with the content for all instances of that element.
check_element_content() - Given an element and content, returns True if the content is in the element (ignores captialization, whitespace, etc).
check_element_content_exact() - Given an element and content, returns True if the content is in the element character for character.
get_elements_attribute_value() - Given an element and an attribute, returns the value of the element's attribute.
get_all_elements_attribute_value() - Given an element and an attribute, returns a list of all instances of the element and each one's attribute value.
check_elements_attribute() - Given an element, attribute, and value, returns True if element's attribute is equal to the value.
check_element_has_attribute() - Given an element and attribute, returns True if element's attribute was assigned any value.
get_list_of_elements_with_class() - Given a class name, returns a list of all elements with class set to given name.
check_element_has_class() - Given an element and class name, returns True if element was assigned class with given name.
get_element_with_id() - Given an id name, returns the element assigned the id.
check_element_has_id() - Given an element and id name, returns True if that element was assigned the id.
check_use_css_file() - Given a CSS filepath, returns True if HTML code uses that CSS file.
check_use_js_file() - Given a JS filepath, returns True if HTML code uses that JS file.
extract_style_as_CSS_obj() - No parameters. Returns css_obj of all CSS found in <style> tags of HTML file.
"""
def __init__(self, filepath, text=False):
if text:
self.html_obj = BeautifulSoup(filepath, 'html.parser')
else:
self.filepath = filepath
with open(filepath) as fp:
self.html_obj = BeautifulSoup(fp, 'html.parser')
self.code = self.html_obj.prettify()
def check_HTML(self, code_snip):
"""Does student HTML have ___ code snip?"""
return (code_snip.casefold().replace(" ", "").replace("\n", "") in str(self.html_obj.contents[2]).casefold().replace(" ", "").replace("\n", ""))
def check_element_used(self, element):
"""Does student HTML have ___ element?"""
return (len(self.html_obj.find_all(element)) > 0)
def check_num_element_used(self, element, number):
"""Does student HTML have ___ number of ___ element?"""
return (len(self.html_obj.find_all(element)) >= number)
def get_num_element_used(self, element):
"""Gets the number of times ___ element is used."""
return (len(self.html_obj.find_all(element)))
def get_element_content(self, element):
"""Gets ___ element's content."""
for line in self.html_obj.find_all(element):
return str(line.contents)
def get_all_element_content(self, element):
"""Gets all ___ element's content in a list."""
all_content = []
for line in self.html_obj.find_all(element):
all_content += line.contents
return all_content
def check_element_content(self, element, content):
"""Does ___ element contain ___ content?"""
for line in self.html_obj.find_all(element):
if (content.casefold().replace(" ", "").replace("\n", "") in str(line.contents).casefold().replace(" ", "").replace("\n", "")):
return True
return False
def check_element_content_exact(self, element, content):
"""Is ___ element's content ___ exactly?"""
for line in self.html_obj.find_all(element):
if (content in str(line.contents)):
return True
return False
def get_elements_attribute_value(self, element, attribute):
"""Gets ___ element's ___ attribute value."""
for line in self.html_obj.find_all(element):
return line.attrs.get(attribute)
def get_all_elements_attribute_value(self, element, attribute):
"""Gets all ___ element's ___ attribute value in a list."""
all_values = []
for line in self.html_obj.find_all(element):
all_values.append(line.attrs.get(attribute))
return all_values
def check_elements_attribute(self, element, attribute, value):
"""Does ___ element have ___ attribute with ___ value?"""
for line in self.html_obj.find_all(element):
if (value == ''.join(line.attrs.get(attribute))):
return True
return False
def check_element_has_attribute(self, element, attribute):
"""Does ___ element have ___ attribute with a value?"""
for line in self.html_obj.find_all(element):
if (line.attrs.get(attribute) != None):
return True
return False
def get_list_of_elements_with_class(self, class_name):
"""Gets a list of all elements with ___ class name."""
return self.html_obj.find_all(class_=class_name)
def check_element_has_class(self, element, class_name):
""""Is ___ element assigned ___ class name?"""
return (len(self.html_obj.find_all(element, class_=class_name)) > 0)
def get_element_with_id(self, id_name):
"""Gets element with ___ id name."""
return self.html_obj.find(id=id_name).name
def check_element_has_id(self, element, id_name):
"""Does ___ element have ___ id name assigned?"""
return (len(self.html_obj.find_all(element, id=id_name)) > 0)
def check_use_css_file(self, css_filepath):
"""Does student HTML use ___ CSS file?"""
for line in self.html_obj.find_all("link"):
if (str(line.attrs.get("rel")) == "['stylesheet']" and str(line.attrs.get("href")) == css_filepath):
return True
return False
def check_use_js_file(self, js_filepath):
"""Does student HTML use ___ JS file?"""
for line in self.html_obj.find_all("script"):
if (str(line.attrs.get("type")) == "text/javascript" and str(line.attrs.get("src")) == js_filepath):
return True
return False
def extract_style_as_CSS_obj(self):
"""Returns CSS_Check css_obj of all CSS found in <style> tags of HTML."""
style_element_content = ""
for style in self.html_obj.find_all("style"):
style_element_content += style.contents[0]
return CSS_Check(style_element_content, text=True)
class CSS_Check:
"""
Create an object that allows you to check student CSS code.
Properties
----------
filepath - the path to the file you are checking.
css_obj - the cssutils object being used.
code - text representation of the css file, which can be printed or parsed.
Methods
-------
check_declaration() - Given a selector and a declaration, returns True if in CSS.
check_property_used() - Given a selector and a property name, returns True if property was given a value in CSS.
check_selector_rule() - Given a selector, property, and property value, returns True if the property is set to that value.
check_selector_has_ruleset() - Given a selector, returns True if selector has a ruleset.
get_selector_ruleset() - Given a selector, returns the ruleset text.
get_property_value() - Given a selector and property, returns the property's value.
check_num_selector_declarations() - Given a selector and a number, returns True if selector has at least specified number of declarations.
check_num_selector_declarations_equal() - Given a selector and a number, returns True if selector has exact specified number of declarations.
get_num_selector_declarations() - Given a selector, returns the number of declarations in the ruleset.
check_num_selector_rulesets() - Given a number, returns True if number of selector rulesets is greater than or equal to the number.
check_num_selector_rulesets_equal() - Given a number, returns True if number of selector rulesets is equal to the number.
get_num_selector_rulesets() - Returns the number of selector rulesets in CSS file.
check_num_declarations() - Given a number, returns True if number of declarations in CSS file is greater than or equal to the number.
check_num_declarations_equal() - Given a number, returns True if number of declarations in CSS file is equal to the number.
get_num_declarations() - Returns the number of declarations in CSS file.
"""
def __init__(self, filepath, text=False):
logging.basicConfig(filename=os.devnull,
format='%(asctime)s %(message)s',)
newlog = logging.getLogger()
cssutils.log.setLog(newlog)
if text:
self.filepath = "No Filepath was provided, only text."
self.css_obj = cssutils.parseString(filepath)
else:
self.filepath = filepath
self.css_obj = cssutils.parseFile(filepath)
self.code = self.css_obj.cssText
def check_declaration(self, selector, declaration):
"""Does ___ selector have ___ declaration?"""
for rule in self.css_obj:
if rule.selectorText == selector:
return (declaration.replace(" ", "").replace(";", "") in rule.style.cssText.replace(" ", "").replace(";", ""))
return False
def check_property_used(self, selector, property):
"""Does ___ selector have ___ property set?"""
for rule in self.css_obj:
if rule.selectorText == selector:
return (property.replace(" ", "") in rule.style.cssText)
return False
def check_selector_rule(self, selector, property, value):
"""Does ___ selector have rule with ___ property set to ___ value?"""
for rule in self.css_obj:
if rule.selectorText == selector:
return (rule.style[property] == value)
return False
def check_selector_has_ruleset(self, selector):
"""Does ___ selector have a ruleset?"""
for rule in self.css_obj:
if rule.selectorText == selector:
return True
return False
def get_selector_ruleset(self, selector):
"""Gets ___ selector's ruleset"""
for rule in self.css_obj:
if rule.selectorText == selector:
if (len(rule.style.cssText) > 0):
return rule.style.cssText
return selector + " does not have a ruleset."
def get_property_value(self, selector, property):
"""Gets ___ selector's ___ property value"""
for rule in self.css_obj:
if rule.selectorText == selector:
if (len(rule.style[property]) > 0):
return rule.style[property]
return selector + " does not have " + property + " set."
def check_num_selector_declarations(self, selector, number):
"""Does ___ selector have at least ___ number of declarations?"""
for rule in self.css_obj:
if rule.selectorText == selector:
return (rule.style.cssText.count("\n")+1 >= number)
return False
def check_num_selector_declarations_equal(self, selector, number):
"""Does ___ selector have at least ___ number of declarations?"""
for rule in self.css_obj:
if rule.selectorText == selector:
return (rule.style.cssText.count("\n")+1 == number)
return False
def get_num_selector_declarations(self, selector):
"""Gets ___ selector's number of declarations?"""
for rule in self.css_obj:
if rule.selectorText == selector:
return (rule.style.cssText.count("\n")+1)
return 0
def check_num_selector_rulesets(self, number):
"""Does CSS file have at least ___ number of selector rulesets?"""
count = 0
for rule in self.css_obj:
count += 1
return (count >= number)
def check_num_selector_rulesets_equal(self, number):
"""Does CSS file have exactly ___ number of selector rulesets?"""
count = 0
for rule in self.css_obj:
count += 1
return (count == number)
def get_num_selector_rulesets(self):
"""Gets number of selector rulesets in CSS file."""
count = 0
for rule in self.css_obj:
count += 1
return count
def check_num_declarations(self, number):
"""Does CSS file have at least ___ number of declarations?"""
count = 0
for rule in self.css_obj:
count += rule.style.cssText.count("\n")+1
return (count >= number)
def check_num_declarations_equal(self, number):
"""Does CSS file have exactly ___ number of declarations?"""
count = 0
for rule in self.css_obj:
count += rule.style.cssText.count("\n")+1
return (count == number)
def get_num_declarations(self):
"""Gets number of declarations in CSS file"""
count = 0
for rule in self.css_obj:
count += rule.style.cssText.count("\n")+1
return count
"""
MIT License
Copyright (c) 2022 Joe Mazzone
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
"""