webcode-tk 1.2.20__tar.gz → 1.2.22__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {webcode_tk-1.2.20 → webcode_tk-1.2.22}/PKG-INFO +2 -1
- {webcode_tk-1.2.20 → webcode_tk-1.2.22}/pyproject.toml +1 -1
- {webcode_tk-1.2.20 → webcode_tk-1.2.22}/webcode_tk/__init__.py +1 -1
- {webcode_tk-1.2.20 → webcode_tk-1.2.22}/webcode_tk/color_tools.py +1 -9
- {webcode_tk-1.2.20 → webcode_tk-1.2.22}/webcode_tk/contrast_tools.py +1 -7
- {webcode_tk-1.2.20 → webcode_tk-1.2.22}/webcode_tk/css_tools.py +5 -8
- {webcode_tk-1.2.20 → webcode_tk-1.2.22}/webcode_tk/font_tools.py +16 -21
- webcode_tk-1.2.22/webcode_tk/requirements.yml +24 -0
- {webcode_tk-1.2.20 → webcode_tk-1.2.22}/webcode_tk/validator_tools.py +15 -8
- {webcode_tk-1.2.20 → webcode_tk-1.2.22}/LICENSE.rst +0 -0
- {webcode_tk-1.2.20 → webcode_tk-1.2.22}/README.rst +0 -0
- {webcode_tk-1.2.20 → webcode_tk-1.2.22}/webcode_tk/_style_inheritance.py +0 -0
- {webcode_tk-1.2.20 → webcode_tk-1.2.22}/webcode_tk/animation_tools.py +0 -0
- {webcode_tk-1.2.20 → webcode_tk-1.2.22}/webcode_tk/cascade_tools.py +0 -0
- {webcode_tk-1.2.20 → webcode_tk-1.2.22}/webcode_tk/color_keywords.py +0 -0
- {webcode_tk-1.2.20 → webcode_tk-1.2.22}/webcode_tk/html_tools.py +0 -0
- {webcode_tk-1.2.20 → webcode_tk-1.2.22}/webcode_tk/sample_report.json +0 -0
- {webcode_tk-1.2.20 → webcode_tk-1.2.22}/webcode_tk/utils.py +0 -0
- {webcode_tk-1.2.20 → webcode_tk-1.2.22}/webcode_tk/ux_tools.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: webcode-tk
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.22
|
|
4
4
|
Summary: A set of tools for inspecting HTML and CSS code
|
|
5
5
|
License: MIT
|
|
6
6
|
License-File: LICENSE.rst
|
|
@@ -16,6 +16,7 @@ Classifier: Programming Language :: Python :: 3.11
|
|
|
16
16
|
Classifier: Programming Language :: Python :: 3.12
|
|
17
17
|
Classifier: Programming Language :: Python :: 3.13
|
|
18
18
|
Classifier: Programming Language :: Python :: 3.14
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.15
|
|
19
20
|
Requires-Dist: bs4 (>=0.0.1,<0.0.2)
|
|
20
21
|
Requires-Dist: file-clerk (>=1.0.9,<2.0.0)
|
|
21
22
|
Requires-Dist: lxml (>=6.0.0,<7.0.0)
|
|
@@ -607,8 +607,7 @@ def contrast_ratio(hex1: str, hex2: str) -> float:
|
|
|
607
607
|
try:
|
|
608
608
|
rgb1 = hex_to_rgb(hex1)
|
|
609
609
|
rgb2 = hex_to_rgb(hex2)
|
|
610
|
-
except ValueError
|
|
611
|
-
print(f"Oops {str(e)}")
|
|
610
|
+
except ValueError:
|
|
612
611
|
return 0
|
|
613
612
|
l1 = luminance(rgb1)
|
|
614
613
|
l2 = luminance(rgb2)
|
|
@@ -1095,12 +1094,5 @@ def color_to_hsl(color_code: str) -> str:
|
|
|
1095
1094
|
|
|
1096
1095
|
|
|
1097
1096
|
if __name__ == "__main__":
|
|
1098
|
-
# print()
|
|
1099
|
-
# hex = rgb_to_hex("rgb(190, 228, 210)")
|
|
1100
|
-
# print(hex)
|
|
1101
|
-
# hex2 = rgb_to_hex("rgb(215, 248, 247)")
|
|
1102
|
-
# print(hex2)
|
|
1103
|
-
# hex = rgb_to_hex("rgb(250, 178, 172)")
|
|
1104
|
-
# print(hex)
|
|
1105
1097
|
hex = rgb_to_hex("rgb(237, 161, 193)")
|
|
1106
1098
|
print(hex)
|
|
@@ -592,8 +592,6 @@ def apply_browser_defaults(
|
|
|
592
592
|
},
|
|
593
593
|
}
|
|
594
594
|
|
|
595
|
-
if element.name in ["html", "body"]:
|
|
596
|
-
print(f" ✓ Added <{element.name}> to element_styles")
|
|
597
595
|
# Apply element-specific defaults
|
|
598
596
|
# Apply link colors
|
|
599
597
|
if element.name == "a":
|
|
@@ -758,7 +756,6 @@ def find_matching_elements(soup: BeautifulSoup, selector: str) -> list:
|
|
|
758
756
|
if not is_selector_supported_by_bs4(selector):
|
|
759
757
|
warning = f"Warning: Selector '{selector}' contains features not "
|
|
760
758
|
warning += "supported by BS4"
|
|
761
|
-
print(warning)
|
|
762
759
|
return []
|
|
763
760
|
|
|
764
761
|
# Try BeautifulSoup's select method
|
|
@@ -1097,9 +1094,8 @@ def convert_font_size_to_pixels(
|
|
|
1097
1094
|
|
|
1098
1095
|
return f"{computed_px:.1f}px"
|
|
1099
1096
|
|
|
1100
|
-
except Exception
|
|
1097
|
+
except Exception:
|
|
1101
1098
|
# Fallback for parsing errors
|
|
1102
|
-
print(f"DEBUG: Exception caught: '{e}'")
|
|
1103
1099
|
return f"{font_size_value}px" # Assume it's already in pixels
|
|
1104
1100
|
|
|
1105
1101
|
|
|
@@ -1386,5 +1382,3 @@ if __name__ == "__main__":
|
|
|
1386
1382
|
contrast_results = generate_contrast_report(project_path, "AAA")
|
|
1387
1383
|
project_path = "tests/test_files/contrast_tool_test/"
|
|
1388
1384
|
global_colors = css_tools.get_project_global_colors(project_path)
|
|
1389
|
-
print()
|
|
1390
|
-
print()
|
|
@@ -326,15 +326,16 @@ class Stylesheet:
|
|
|
326
326
|
|
|
327
327
|
# Check for a gradient bg color
|
|
328
328
|
is_bg_gradient = color_tools.is_gradient(value)
|
|
329
|
-
|
|
330
|
-
print()
|
|
329
|
+
|
|
331
330
|
# skip if has vendor prefix
|
|
332
331
|
if has_vendor_prefix(value):
|
|
333
332
|
continue
|
|
333
|
+
|
|
334
334
|
# skip if not valid color value
|
|
335
335
|
is_valid_color = color_tools.is_color_value(value)
|
|
336
336
|
if not is_valid_color and not is_bg_gradient:
|
|
337
337
|
continue
|
|
338
|
+
|
|
338
339
|
# make sure the value is a color (not other)
|
|
339
340
|
rule = {selector: {property: value}}
|
|
340
341
|
color_rulesets.append(rule)
|
|
@@ -1259,8 +1260,7 @@ def get_comment_positions(code: str) -> Union[list, None]:
|
|
|
1259
1260
|
positions.append(code.index("/*"))
|
|
1260
1261
|
positions.append(code.index("*/"))
|
|
1261
1262
|
return positions
|
|
1262
|
-
except Exception
|
|
1263
|
-
print(ex)
|
|
1263
|
+
except Exception:
|
|
1264
1264
|
return
|
|
1265
1265
|
|
|
1266
1266
|
|
|
@@ -1362,8 +1362,6 @@ def get_font_families(sheet: Stylesheet) -> list:
|
|
|
1362
1362
|
# always take the last family as it would be an override in CSS
|
|
1363
1363
|
family = families[-1]
|
|
1364
1364
|
font_families.append({"selector": selector, "family": family})
|
|
1365
|
-
else:
|
|
1366
|
-
print()
|
|
1367
1365
|
return font_families
|
|
1368
1366
|
|
|
1369
1367
|
|
|
@@ -1885,8 +1883,7 @@ def get_unique_font_rules(project_folder: str) -> list:
|
|
|
1885
1883
|
unique_font_selectors.append(selector)
|
|
1886
1884
|
if value not in unique_font_values:
|
|
1887
1885
|
unique_font_values.append(value)
|
|
1888
|
-
|
|
1889
|
-
print()
|
|
1886
|
+
|
|
1890
1887
|
# apply the file, unique rules, unique selectors, and unique values
|
|
1891
1888
|
filename = file.get("file")
|
|
1892
1889
|
file_data = {"file": filename, "rules": unique_rules}
|
|
@@ -24,13 +24,12 @@ font-file or some other hidden calculation from the browser.
|
|
|
24
24
|
|
|
25
25
|
import re
|
|
26
26
|
from typing import Any
|
|
27
|
-
|
|
27
|
+
|
|
28
28
|
from file_clerk import clerk
|
|
29
29
|
|
|
30
30
|
from webcode_tk import css_tools
|
|
31
31
|
from webcode_tk import html_tools as html
|
|
32
32
|
|
|
33
|
-
|
|
34
33
|
absolute_keyword_regex = (
|
|
35
34
|
r"\b(?:xx-small|x-small|small(?!-caps)|medium|large|x-large|"
|
|
36
35
|
)
|
|
@@ -137,7 +136,7 @@ def get_font_unit(value: str) -> str:
|
|
|
137
136
|
"""returns unit being use when setting font-size"""
|
|
138
137
|
unit = ""
|
|
139
138
|
# Check for relative keywords
|
|
140
|
-
if value in KEYWORD_SIZE_MAP
|
|
139
|
+
if value in KEYWORD_SIZE_MAP:
|
|
141
140
|
unit = "absolute_keyword"
|
|
142
141
|
elif relative_keyword.search(value):
|
|
143
142
|
unit = "relative_keyword"
|
|
@@ -169,7 +168,7 @@ def split_value_unit(value: str) -> tuple:
|
|
|
169
168
|
value_unit: a tuple of the value and the unit.
|
|
170
169
|
"""
|
|
171
170
|
value_unit = ["", ""]
|
|
172
|
-
if value in KEYWORD_SIZE_MAP
|
|
171
|
+
if value in KEYWORD_SIZE_MAP:
|
|
173
172
|
value_unit = (value, "absolute_keyword")
|
|
174
173
|
elif relative_keyword.search(value):
|
|
175
174
|
value_unit = (value, "relative_keyword")
|
|
@@ -236,17 +235,15 @@ def is_large_text(size: float, is_bold: bool) -> bool:
|
|
|
236
235
|
is_large: whether the text is considered large or not.
|
|
237
236
|
"""
|
|
238
237
|
is_large = False
|
|
239
|
-
if size >= 24:
|
|
240
|
-
is_large = True
|
|
241
|
-
elif is_bold and size >= 18.66:
|
|
238
|
+
if size >= 24 or is_bold and size >= 18.66:
|
|
242
239
|
is_large = True
|
|
243
240
|
return is_large
|
|
244
241
|
|
|
245
242
|
|
|
246
243
|
def compute_font_size(
|
|
247
|
-
value:
|
|
244
|
+
value: str | float,
|
|
248
245
|
unit: str,
|
|
249
|
-
parent_size:
|
|
246
|
+
parent_size: float = 16.0,
|
|
250
247
|
element_name: str = "",
|
|
251
248
|
) -> float:
|
|
252
249
|
"""Computes font size based on value, unit, and possibly parent size.
|
|
@@ -288,7 +285,7 @@ def compute_font_size(
|
|
|
288
285
|
percentage = value * 0.01
|
|
289
286
|
computed_size = parent_size * percentage
|
|
290
287
|
elif unit == "em":
|
|
291
|
-
if element_name.lower() in HEADING_SIZES
|
|
288
|
+
if element_name.lower() in HEADING_SIZES:
|
|
292
289
|
# factor = HEADING_SIZES.get(element_name).split("e")[0]
|
|
293
290
|
computed_size = parent_size * value # * factor
|
|
294
291
|
else:
|
|
@@ -296,7 +293,7 @@ def compute_font_size(
|
|
|
296
293
|
elif unit in ("unset", "inherit"):
|
|
297
294
|
computed_size = parent_size
|
|
298
295
|
elif unit in "revert":
|
|
299
|
-
if element_name.lower() in HEADING_SIZES
|
|
296
|
+
if element_name.lower() in HEADING_SIZES:
|
|
300
297
|
ems = HEADING_SIZES.get(element_name)
|
|
301
298
|
multiplier = ems.split("e")[0]
|
|
302
299
|
computed_size = parent_size * float(multiplier)
|
|
@@ -340,13 +337,12 @@ def is_valid_shorthand(value: str) -> bool:
|
|
|
340
337
|
if ignore:
|
|
341
338
|
continue
|
|
342
339
|
font_size_values = get_numeric_fontsize_values(val)
|
|
343
|
-
if
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
elif val in UNIT_TO_PT_CONVERSIONS.keys():
|
|
340
|
+
if (
|
|
341
|
+
font_size_values
|
|
342
|
+
or val in KEYWORD_SIZE_MAP
|
|
343
|
+
or val in ("larger", "smaller")
|
|
344
|
+
or val in UNIT_TO_PT_CONVERSIONS
|
|
345
|
+
):
|
|
350
346
|
targets_size = True
|
|
351
347
|
|
|
352
348
|
# check for font family.
|
|
@@ -419,9 +415,8 @@ def get_google_font_report(project_dir: str, min=1, max=2) -> str:
|
|
|
419
415
|
families = extract_families(font_data)
|
|
420
416
|
if families:
|
|
421
417
|
for family in google_fonts_linked:
|
|
422
|
-
if family in families:
|
|
423
|
-
|
|
424
|
-
fonts_used.append(family)
|
|
418
|
+
if family in families and family not in fonts_used:
|
|
419
|
+
fonts_used.append(family)
|
|
425
420
|
|
|
426
421
|
num_used = len(fonts_used)
|
|
427
422
|
if num_used >= min and num_used <= max:
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
name: Update requirements.txt
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
workflow_dispatch:
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
requirements:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
steps:
|
|
12
|
+
- uses: actions/checkout@v2
|
|
13
|
+
- uses: actions/setup-python@v2
|
|
14
|
+
- name: Install Poetry
|
|
15
|
+
uses: snok/install-poetry@v1
|
|
16
|
+
- name: Generate requirements.txt
|
|
17
|
+
run: poetry export --with dev -f requirements.txt -o requirements.txt
|
|
18
|
+
- name: Commit and push requirements.txt
|
|
19
|
+
run: |
|
|
20
|
+
git config user.name "github-actions"
|
|
21
|
+
git config user.email "github-actions@github.com"
|
|
22
|
+
git add requirements.txt
|
|
23
|
+
git commit -m "chore: update requirements.txt" || true
|
|
24
|
+
git push
|
|
@@ -103,7 +103,7 @@ def get_markup_validity(file_path: str) -> list:
|
|
|
103
103
|
try:
|
|
104
104
|
errors = r.json()
|
|
105
105
|
errors = errors.get("messages")
|
|
106
|
-
except
|
|
106
|
+
except ValueError:
|
|
107
107
|
# We need to use the web browser
|
|
108
108
|
errors = get_validation_by_browser(file_path)
|
|
109
109
|
|
|
@@ -252,7 +252,7 @@ def get_validation_by_browser(file_path: str) -> list:
|
|
|
252
252
|
browser["fragment"] = html_code
|
|
253
253
|
browser.submit_selected()
|
|
254
254
|
results = browser.get_current_page().select("div#results")
|
|
255
|
-
except
|
|
255
|
+
except requests.ConnectionError:
|
|
256
256
|
# Convert the file "no_css_connection.html" into a soup tag object
|
|
257
257
|
no_connection_code = (
|
|
258
258
|
"<h1>Sorry, but we could not make a connection</h1>"
|
|
@@ -288,11 +288,18 @@ def validate_css(css_code: str) -> bs4.ResultSet:
|
|
|
288
288
|
browser["text"] = css_code
|
|
289
289
|
browser.submit_selected()
|
|
290
290
|
results = browser.get_current_page().select("#results_container")
|
|
291
|
-
except
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
291
|
+
except requests.ConnectionError:
|
|
292
|
+
no_connection_code = """
|
|
293
|
+
<div id="results_container">
|
|
294
|
+
<table>
|
|
295
|
+
<tr class="error">
|
|
296
|
+
<td>NA</td>
|
|
297
|
+
<td>NA</td>
|
|
298
|
+
<td>Sorry, but we could not make a connection</td>
|
|
299
|
+
</tr>
|
|
300
|
+
</table>
|
|
301
|
+
</div>
|
|
302
|
+
"""
|
|
296
303
|
soup = BeautifulSoup(no_connection_code, "lxml")
|
|
297
304
|
# Convert string to result set
|
|
298
305
|
results = soup.select("#results_container")
|
|
@@ -357,6 +364,6 @@ def get_project_validation(project_dir: str, type="html") -> list:
|
|
|
357
364
|
if __name__ == "__main__":
|
|
358
365
|
path = "tests/test_files/sample_with_errors.html"
|
|
359
366
|
report = get_markup_validity(path)
|
|
360
|
-
print("report is a {
|
|
367
|
+
print(f"report is a {type(report)}.")
|
|
361
368
|
for item in report:
|
|
362
369
|
print(item)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|