webcode-tk 0.7.11__tar.gz → 1.0.0__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: webcode-tk
3
- Version: 0.7.11
3
+ Version: 1.0.0
4
4
  Summary:
5
5
  Home-page: https://github.com/HundredVisionsGuy/webcode-tk
6
6
  License: MIT
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "webcode-tk"
3
- version = "0.7.11"
3
+ version = "1.0.0"
4
4
  description = ""
5
5
  authors = ["hundredvisionsguy <cwinikka@gmail.com>"]
6
6
  keywords = ["html", "validation", "css", ]
@@ -18,4 +18,4 @@ Modules exported by this package:
18
18
  - `validator_tools`: sends HTML or CSS code to the W3C Validator to check
19
19
  for errors.
20
20
  """
21
- __version__ = "0.7.11"
21
+ __version__ = "1.0.0"
@@ -5,12 +5,13 @@ inheritance and the cascade.
5
5
  The goal is to use the DOM, inheritance, and the cascade, to determine
6
6
  all styles applied to every element on the page.
7
7
 
8
- With that, it scans each stylesheet and applies eacSh style one at a time
8
+ With that, it scans each stylesheet and applies each style one at a time
9
9
  to all elements and their children (if applicable) of a page.
10
10
  """
11
11
  import ctypes
12
12
  import re
13
13
  from collections import abc
14
+ from typing import Union
14
15
 
15
16
  from file_clerk import clerk
16
17
 
@@ -73,12 +74,14 @@ class Element(object):
73
74
  self.attributes = attributes
74
75
  self.background_color = {
75
76
  "value": "#ffffff",
77
+ "has_alpha": False,
78
+ "computed_value": "",
76
79
  "sheet": "user-agent",
77
80
  "selector": "",
78
81
  "specificity": "000",
79
82
  "applied_by": "context",
80
83
  "is_gradient": False,
81
- "gradiparentent_colors": [],
84
+ "gradient_colors": [],
82
85
  }
83
86
  self.color = {
84
87
  "value": "#000000",
@@ -129,12 +132,14 @@ class Element(object):
129
132
  "normal_aaa": True,
130
133
  "normal_aa": True,
131
134
  "large_aaa": True,
135
+ "large_aa": True,
132
136
  }
133
137
  self.visited_contrast_data = {
134
138
  "ratio": 0.0,
135
139
  "normal_aaa": False,
136
140
  "normal_aa": False,
137
141
  "large_aaa": False,
142
+ "large_aa": False,
138
143
  }
139
144
  self.__set_link_color()
140
145
  self.get_contrast_data("default")
@@ -166,6 +171,7 @@ class Element(object):
166
171
  # get relevant specificity
167
172
  new_specificity = new_styles.get("specificity")
168
173
  col_specificity = self.color.get("specificity")
174
+
169
175
  # Check for overrides
170
176
  color_has_override = new_specificity >= col_specificity
171
177
 
@@ -263,7 +269,12 @@ class Element(object):
263
269
  col, bg, self.ancestors
264
270
  )
265
271
  # Set bg to composite color with lowest contrast ratio
266
- bg = results[0][-1]
272
+ bg = results[0][-2]
273
+ has_alpha = results[0][-1]
274
+ if has_alpha:
275
+ self.background_color["has_alpha"] = True
276
+ self.background_color["computed_value"] = bg
277
+
267
278
  hexc = color.get_hex(col)
268
279
  hexbg = color.get_hex(bg)
269
280
  self.__build_contrast_report(hexc, hexbg)
@@ -327,6 +338,9 @@ class Element(object):
327
338
  self.visited_contrast_data["large_aaa"] = bool(
328
339
  link_contrast.get("Large AAA") == "Pass"
329
340
  )
341
+ self.visited_contrast_data["large_aa"] = bool(
342
+ link_contrast.get("Large AA") == "Pass"
343
+ )
330
344
 
331
345
  def change_styles(
332
346
  self,
@@ -554,6 +568,7 @@ class Element(object):
554
568
  directly_targeted = self.directly_targets(selector)
555
569
  previously_set = self.background_color.get("applied_by") == "directly"
556
570
  bg_gradient = color.is_gradient(val)
571
+
557
572
  # If directly, check specificity
558
573
  if directly_targeted:
559
574
  if previously_set:
@@ -562,13 +577,49 @@ class Element(object):
562
577
  colors = []
563
578
  if bg_gradient:
564
579
  self.background_color["is_gradient"] = True
580
+ c = self.color.get("value")
581
+ details = color.get_color_contrast_with_gradients(
582
+ c, val, self.ancestors
583
+ )
565
584
  colors = color.get_gradient_colors(val)
585
+
586
+ # Set gradient colors with highest and lowest contrast
587
+ self.background_color["best_contrast"] = {}
588
+ self.background_color["worst_contrast"] = {}
589
+
590
+ def process_gradient_data(details, bg_dict):
591
+ contrast_ratio = details[0]
592
+ size = self.font_size
593
+ is_bold = self.is_bold
594
+ results = color.get_contrast_results_from_ratio(
595
+ contrast_ratio, size, is_bold
596
+ )
597
+ has_alpha = details[-1]
598
+ if has_alpha:
599
+ bg_dict["has_alpha"] = has_alpha
600
+ self.background_color["has_alpha"] = True
601
+ self.background_color["computed_value"] = details[3]
602
+ bg_dict["computed_value"] = details[-2]
603
+ else:
604
+ bg_dict["value"] = details[2]
605
+ bg_dict["contrast_ratio"] = details[0]
606
+ bg_dict["results"] = results
607
+
608
+ best = details[-1]
609
+ worst = details[0]
610
+ process_gradient_data(
611
+ best, self.background_color["best_contrast"]
612
+ )
613
+ process_gradient_data(
614
+ worst, self.background_color["worst_contrast"]
615
+ )
566
616
  self.background_color["gradient_colors"] = colors
567
617
  # set color, specificity, and directly applied
568
618
  self.background_color["value"] = val
569
619
  self.background_color["sheet"] = filename
570
620
  self.background_color["specificity"] = new_specificity
571
621
  self.background_color["applied_by"] = "directly"
622
+ self.background_color["selector"] = selector
572
623
  else:
573
624
  if not previously_set:
574
625
  self.background_color["value"] = val
@@ -1441,6 +1492,89 @@ def update_contrast_results(
1441
1492
  return results
1442
1493
 
1443
1494
 
1495
+ def get_color_contrast_details(tree: CSSAppliedTree, rating="AAA") -> list:
1496
+ """returns a list of all all failures or a pass based on rating
1497
+
1498
+ We'll create a recursive inner nested function to traverse the DOM. We will
1499
+ target only the styles that are applied directly so as to not overwhelm the
1500
+ user and allow fixing the error more easily.
1501
+
1502
+ Args:
1503
+ tree: the cascade tree for a single file.
1504
+ rating: the rating of contrast we check for (AAA or AA). The default
1505
+ is AAA.
1506
+ Returns:
1507
+ results"""
1508
+ results = []
1509
+ filename = tree.filename
1510
+ # Loop recursively through the tree
1511
+ elements = tree.children
1512
+
1513
+ def check_element(
1514
+ el: Element, rating: str, filename: str
1515
+ ) -> Union[list, None]:
1516
+ children = el.children
1517
+ msg = ""
1518
+ applied_directly = (
1519
+ el.background_color.get("applied_by") == "directly"
1520
+ or el.color.get("applied_by") == "directly"
1521
+ )
1522
+ if applied_directly or el.name == "body":
1523
+ is_gradient = el.background_color.get("is_gradient")
1524
+ if is_gradient:
1525
+ # get worst case
1526
+ worst_case = el.background_color.get("worst_contrast")
1527
+ worst_results = worst_case.get("results")
1528
+ fails = "fail" in worst_results[:5]
1529
+ if fails:
1530
+ selector = el.background_color.get("selector")
1531
+ if el.is_large:
1532
+ size = "Large"
1533
+ else:
1534
+ size = "Normal"
1535
+ msg = f"{el.name} tag (selector: {selector}) fails color "
1536
+ msg += f"contrast at {size} {rating}."
1537
+ results.append(msg)
1538
+ return
1539
+ contrast_data = el.contrast_data
1540
+ if el.is_large:
1541
+ if rating == "AAA":
1542
+ passes = contrast_data.get("large_aaa")
1543
+ else:
1544
+ passes = contrast_data.get("large_aa")
1545
+ else:
1546
+ if rating == "AAA":
1547
+ passes = contrast_data.get("normal_aaa")
1548
+ else:
1549
+ passes = contrast_data.get("normal_aa")
1550
+ # only add results if failure
1551
+ if not passes:
1552
+ if el.is_large:
1553
+ size = "Large"
1554
+ else:
1555
+ size = "Normal"
1556
+ selector = el.background_color.get("selector")
1557
+ if not selector:
1558
+ selector = el.color.get("selector")
1559
+ msg = f"{el.name} tag (selector: {selector}) fails color "
1560
+ msg += f"contrast at {size} {rating}."
1561
+ results.append(msg)
1562
+ if not children:
1563
+ return
1564
+ else:
1565
+ for kid in children:
1566
+ check_element(kid, rating, filename)
1567
+
1568
+ for element in elements:
1569
+ check_element(element, rating, filename)
1570
+ if not results:
1571
+ # It's a success! Let's let them know
1572
+ msg = f"success: {filename} passes color contrast for {rating} Normal"
1573
+ msg += " and Large."
1574
+ results.append(msg)
1575
+ return results
1576
+
1577
+
1444
1578
  if __name__ == "__main__":
1445
1579
  project_path = "tests/test_files/attribute_selector_file"
1446
1580
  project_path = "tests/test_files/large_project/"
@@ -1453,6 +1587,7 @@ if __name__ == "__main__":
1453
1587
  sheet,
1454
1588
  ],
1455
1589
  )
1590
+ results = get_color_contrast_details(gradient_tree, "AAA")
1456
1591
  styles_by_html_files = css.get_styles_by_html_files(project_path)
1457
1592
  for file in styles_by_html_files:
1458
1593
  filepath = file.get("file")
@@ -1461,4 +1596,3 @@ if __name__ == "__main__":
1461
1596
  results = {}
1462
1597
  root = css_tree.children[0]
1463
1598
  results = get_color_contrast_results(root, results)
1464
- print(results)
@@ -78,6 +78,44 @@ def passes_color_contrast(level: str, hex1: str, hex2: str) -> bool:
78
78
  return passes
79
79
 
80
80
 
81
+ def get_contrast_results_from_ratio(
82
+ ratio: float, size: float, is_bold: bool
83
+ ) -> str:
84
+ """takes contrast, compares to map and returns results as a string
85
+
86
+ Args:
87
+ ratio: the contrast ratio.
88
+ size: calculated font size.
89
+
90
+ Returns:
91
+ str: whether it passes or not with details.
92
+ """
93
+ # is the text large or not?
94
+ is_large = size >= 24 or is_bold and size >= 16.66
95
+ if is_large:
96
+ aaa_goal = contrast_ratio_map.get("Large AAA")
97
+ passes = ratio >= aaa_goal
98
+ if passes:
99
+ return "pass: Large AAA contrast rating"
100
+ aa_goal = contrast_ratio_map.get("Large AA")
101
+ conditionally_passes = ratio >= aa_goal
102
+ if conditionally_passes:
103
+ return "conditional pass: Large AA contrast rating"
104
+ else:
105
+ return "fail: fails all contrast ratings"
106
+ else:
107
+ aaa_goal = contrast_ratio_map.get("Normal AAA")
108
+ passes = ratio >= aaa_goal
109
+ if passes:
110
+ return "pass: Normal AAA contrast rating"
111
+ aa_goal = contrast_ratio_map.get("Normal AA")
112
+ conditionally_passes = ratio >= aa_goal
113
+ if conditionally_passes:
114
+ return "conditional pass: Normal AA contrast rating"
115
+ else:
116
+ return "fail: fails normal sized text contrast"
117
+
118
+
81
119
  def get_color_contrast_report(hex1: str, hex2: str) -> dict:
82
120
  """creates a report on how the two hex colors rate on the color
83
121
  contrast chart
@@ -794,10 +832,18 @@ def get_color_contrast_with_gradients(
794
832
  # append to results list
795
833
  if composite_color:
796
834
  results.append(
797
- (contrast, foreground, background, composite_color)
835
+ (
836
+ contrast,
837
+ foreground,
838
+ background,
839
+ composite_color,
840
+ bg_has_alpha,
841
+ )
798
842
  )
799
843
  else:
800
- results.append((contrast, foreground, background, background))
844
+ results.append(
845
+ (contrast, foreground, background, background, False)
846
+ )
801
847
  results.sort()
802
848
  return results
803
849
 
File without changes
File without changes