python-color-math 0.2.21__tar.gz → 0.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.
- {python_color_math-0.2.21/python_color_math.egg-info → python_color_math-0.2.22}/PKG-INFO +1 -1
- {python_color_math-0.2.21 → python_color_math-0.2.22}/color_math/__init__.py +1 -1
- {python_color_math-0.2.21 → python_color_math-0.2.22}/color_math/config.py +71 -15
- {python_color_math-0.2.21 → python_color_math-0.2.22}/pyproject.toml +1 -1
- {python_color_math-0.2.21 → python_color_math-0.2.22/python_color_math.egg-info}/PKG-INFO +1 -1
- {python_color_math-0.2.21 → python_color_math-0.2.22}/python_color_math.egg-info/SOURCES.txt +1 -0
- python_color_math-0.2.22/tests/test_harmonic_tuples.py +84 -0
- {python_color_math-0.2.21 → python_color_math-0.2.22}/tests/test_mcp_hardcore.py +1 -0
- {python_color_math-0.2.21 → python_color_math-0.2.22}/tests/test_mcp_server.py +1 -0
- {python_color_math-0.2.21 → python_color_math-0.2.22}/.pre-commit-hooks.yaml +0 -0
- {python_color_math-0.2.21 → python_color_math-0.2.22}/LICENSE +0 -0
- {python_color_math-0.2.21 → python_color_math-0.2.22}/MANIFEST.in +0 -0
- {python_color_math-0.2.21 → python_color_math-0.2.22}/README.md +0 -0
- {python_color_math-0.2.21 → python_color_math-0.2.22}/color_math/__main__.py +0 -0
- {python_color_math-0.2.21 → python_color_math-0.2.22}/color_math/adapters.py +0 -0
- {python_color_math-0.2.21 → python_color_math-0.2.22}/color_math/colormath.default.json +0 -0
- {python_color_math-0.2.21 → python_color_math-0.2.22}/color_math/completions.py +0 -0
- {python_color_math-0.2.21 → python_color_math-0.2.22}/color_math/converters/__init__.py +0 -0
- {python_color_math-0.2.21 → python_color_math-0.2.22}/color_math/converters/align.py +0 -0
- {python_color_math-0.2.21 → python_color_math-0.2.22}/color_math/converters/block.py +0 -0
- {python_color_math-0.2.21 → python_color_math-0.2.22}/color_math/converters/derivative.py +0 -0
- {python_color_math-0.2.21 → python_color_math-0.2.22}/color_math/converters/equation.py +0 -0
- {python_color_math-0.2.21 → python_color_math-0.2.22}/color_math/converters/generic.py +0 -0
- {python_color_math-0.2.21 → python_color_math-0.2.22}/color_math/converters/integral.py +0 -0
- {python_color_math-0.2.21 → python_color_math-0.2.22}/color_math/converters/limit.py +0 -0
- {python_color_math-0.2.21 → python_color_math-0.2.22}/color_math/converters/matrix.py +0 -0
- {python_color_math-0.2.21 → python_color_math-0.2.22}/color_math/converters/semantic.py +0 -0
- {python_color_math-0.2.21 → python_color_math-0.2.22}/color_math/converters/unicode_converter.py +0 -0
- {python_color_math-0.2.21 → python_color_math-0.2.22}/color_math/custom_definitions.py +0 -0
- {python_color_math-0.2.21 → python_color_math-0.2.22}/color_math/gui.py +0 -0
- {python_color_math-0.2.21 → python_color_math-0.2.22}/color_math/io.py +0 -0
- {python_color_math-0.2.21 → python_color_math-0.2.22}/color_math/ipython.py +0 -0
- {python_color_math-0.2.21 → python_color_math-0.2.22}/color_math/jupyter.py +0 -0
- {python_color_math-0.2.21 → python_color_math-0.2.22}/color_math/main.py +0 -0
- {python_color_math-0.2.21 → python_color_math-0.2.22}/color_math/mcp.py +0 -0
- {python_color_math-0.2.21 → python_color_math-0.2.22}/color_math/mcp_server.py +0 -0
- {python_color_math-0.2.21 → python_color_math-0.2.22}/color_math/parsers/__init__.py +0 -0
- {python_color_math-0.2.21 → python_color_math-0.2.22}/color_math/parsers/alignment.py +0 -0
- {python_color_math-0.2.21 → python_color_math-0.2.22}/color_math/parsers/braket.py +0 -0
- {python_color_math-0.2.21 → python_color_math-0.2.22}/color_math/parsers/constants.py +0 -0
- {python_color_math-0.2.21 → python_color_math-0.2.22}/color_math/parsers/delimiters.py +0 -0
- {python_color_math-0.2.21 → python_color_math-0.2.22}/color_math/parsers/differentials.py +0 -0
- {python_color_math-0.2.21 → python_color_math-0.2.22}/color_math/parsers/dimensionless.py +0 -0
- {python_color_math-0.2.21 → python_color_math-0.2.22}/color_math/parsers/frontmatter.py +0 -0
- {python_color_math-0.2.21 → python_color_math-0.2.22}/color_math/parsers/latex_spans.py +0 -0
- {python_color_math-0.2.21 → python_color_math-0.2.22}/color_math/parsers/markdown_scanner.py +0 -0
- {python_color_math-0.2.21 → python_color_math-0.2.22}/color_math/parsers/math_parser.py +0 -0
- {python_color_math-0.2.21 → python_color_math-0.2.22}/color_math/parsers/physics.py +0 -0
- {python_color_math-0.2.21 → python_color_math-0.2.22}/color_math/parsers/scanner.py +0 -0
- {python_color_math-0.2.21 → python_color_math-0.2.22}/color_math/parsers/taxonomy.py +0 -0
- {python_color_math-0.2.21 → python_color_math-0.2.22}/color_math/parsers/units.py +0 -0
- {python_color_math-0.2.21 → python_color_math-0.2.22}/color_math/parsers/variable_hash.py +0 -0
- {python_color_math-0.2.21 → python_color_math-0.2.22}/color_math/py.typed +0 -0
- {python_color_math-0.2.21 → python_color_math-0.2.22}/color_math/self_test.py +0 -0
- {python_color_math-0.2.21 → python_color_math-0.2.22}/color_math/tutorial.py +0 -0
- {python_color_math-0.2.21 → python_color_math-0.2.22}/color_math/undo.py +0 -0
- {python_color_math-0.2.21 → python_color_math-0.2.22}/color_math/unicode.py +0 -0
- {python_color_math-0.2.21 → python_color_math-0.2.22}/color_math/utils/__init__.py +0 -0
- {python_color_math-0.2.21 → python_color_math-0.2.22}/color_math/utils/coloring.py +0 -0
- {python_color_math-0.2.21 → python_color_math-0.2.22}/color_math/utils/latex_helpers.py +0 -0
- {python_color_math-0.2.21 → python_color_math-0.2.22}/color_math/utils/spans.py +0 -0
- {python_color_math-0.2.21 → python_color_math-0.2.22}/python_color_math/__init__.py +0 -0
- {python_color_math-0.2.21 → python_color_math-0.2.22}/python_color_math/__main__.py +0 -0
- {python_color_math-0.2.21 → python_color_math-0.2.22}/python_color_math.egg-info/dependency_links.txt +0 -0
- {python_color_math-0.2.21 → python_color_math-0.2.22}/python_color_math.egg-info/entry_points.txt +0 -0
- {python_color_math-0.2.21 → python_color_math-0.2.22}/python_color_math.egg-info/requires.txt +0 -0
- {python_color_math-0.2.21 → python_color_math-0.2.22}/python_color_math.egg-info/top_level.txt +0 -0
- {python_color_math-0.2.21 → python_color_math-0.2.22}/setup.cfg +0 -0
- {python_color_math-0.2.21 → python_color_math-0.2.22}/tests/test_adversarial.py +0 -0
- {python_color_math-0.2.21 → python_color_math-0.2.22}/tests/test_cli.py +0 -0
- {python_color_math-0.2.21 → python_color_math-0.2.22}/tests/test_config_tolerance.py +0 -0
- {python_color_math-0.2.21 → python_color_math-0.2.22}/tests/test_custom_definitions.py +0 -0
- {python_color_math-0.2.21 → python_color_math-0.2.22}/tests/test_extreme_adversarial.py +0 -0
- {python_color_math-0.2.21 → python_color_math-0.2.22}/tests/test_features.py +0 -0
- {python_color_math-0.2.21 → python_color_math-0.2.22}/tests/test_frontmatter.py +0 -0
- {python_color_math-0.2.21 → python_color_math-0.2.22}/tests/test_fuzz.py +0 -0
- {python_color_math-0.2.21 → python_color_math-0.2.22}/tests/test_gui.py +0 -0
- {python_color_math-0.2.21 → python_color_math-0.2.22}/tests/test_ipython.py +0 -0
- {python_color_math-0.2.21 → python_color_math-0.2.22}/tests/test_physics.py +0 -0
- {python_color_math-0.2.21 → python_color_math-0.2.22}/tests/test_unicode.py +0 -0
- {python_color_math-0.2.21 → python_color_math-0.2.22}/tests/test_unicode_converter.py +0 -0
|
@@ -610,26 +610,82 @@ RAINBOW_DELIMITER_COLORS: list[str] = [
|
|
|
610
610
|
|
|
611
611
|
|
|
612
612
|
VARIABLE_HASH_PALETTE: list[str] = [
|
|
613
|
-
"#7aa2f7", # Tokyo Blue
|
|
614
|
-
"#7dcfff", # Tokyo Cyan
|
|
615
|
-
"#bb9af7", # Tokyo Purple
|
|
616
|
-
"#f7768e", # Tokyo Pink
|
|
617
|
-
"#e0af68", # Tokyo Orange/Gold
|
|
618
|
-
"#9ece6a", # Tokyo Green
|
|
619
|
-
"#2ac3de", # Light Cyan
|
|
620
|
-
"#ff9e64", # Peach
|
|
613
|
+
"#7aa2f7", # 0: Tokyo Blue
|
|
614
|
+
"#7dcfff", # 1: Tokyo Cyan
|
|
615
|
+
"#bb9af7", # 2: Tokyo Purple
|
|
616
|
+
"#f7768e", # 3: Tokyo Pink
|
|
617
|
+
"#e0af68", # 4: Tokyo Orange/Gold
|
|
618
|
+
"#9ece6a", # 5: Tokyo Green
|
|
619
|
+
"#2ac3de", # 6: Light Cyan/Teal
|
|
620
|
+
"#ff9e64", # 7: Peach
|
|
621
621
|
]
|
|
622
622
|
|
|
623
|
+
CANONICAL_VARIABLE_SLOTS: dict[str, int] = {
|
|
624
|
+
# 1. Spatial 3D Cartesian coordinates: guaranteed maximum pairwise separation
|
|
625
|
+
"x": 0, # Tokyo Blue
|
|
626
|
+
"y": 4, # Tokyo Gold
|
|
627
|
+
"z": 5, # Tokyo Green
|
|
628
|
+
|
|
629
|
+
# 2. Coefficients: high-contrast against (x, y, z) and within the group
|
|
630
|
+
"a": 2, # Tokyo Purple
|
|
631
|
+
"b": 3, # Tokyo Pink
|
|
632
|
+
"c": 6, # Light Cyan/Teal
|
|
633
|
+
"d": 7, # Peach
|
|
634
|
+
|
|
635
|
+
# 3. Parameters / Velocity / Substitutions
|
|
636
|
+
"u": 1, # Tokyo Cyan
|
|
637
|
+
"v": 2, # Tokyo Purple
|
|
638
|
+
"w": 4, # Tokyo Gold
|
|
639
|
+
|
|
640
|
+
# 4. Discrete summation & matrix indices
|
|
641
|
+
"i": 4, # Tokyo Gold
|
|
642
|
+
"j": 0, # Tokyo Blue
|
|
643
|
+
"k": 3, # Tokyo Pink
|
|
644
|
+
"l": 5, # Tokyo Green
|
|
645
|
+
"m": 2, # Tokyo Purple
|
|
646
|
+
"n": 6, # Light Cyan/Teal
|
|
647
|
+
|
|
648
|
+
# 5. Calculus & Analysis duals
|
|
649
|
+
"s": 3, # Tokyo Pink
|
|
650
|
+
"t": 1, # Tokyo Cyan
|
|
651
|
+
"p": 0, # Tokyo Blue
|
|
652
|
+
"q": 7, # Peach
|
|
653
|
+
|
|
654
|
+
# 6. Thermodynamics & State
|
|
655
|
+
"P": 3, # Tokyo Pink
|
|
656
|
+
"V": 0, # Tokyo Blue
|
|
657
|
+
"T": 4, # Tokyo Gold
|
|
658
|
+
|
|
659
|
+
# 7. Greek letters & canonical duals
|
|
660
|
+
"\\theta": 4, "θ": 4, "𝜗": 4, "ϑ": 4,
|
|
661
|
+
"\\phi": 2, "\\varphi": 2, "ϕ": 2, "φ": 2, "𝜙": 2, "𝜑": 2,
|
|
662
|
+
"\\psi": 2, "ψ": 2, "𝜓": 2,
|
|
663
|
+
"\\epsilon": 2, "\\varepsilon": 2, "ε": 2, "𝜀": 2,
|
|
664
|
+
"\\delta": 5, "δ": 5, "𝛿": 5,
|
|
665
|
+
"\\alpha": 2, "α": 2, "𝛼": 2,
|
|
666
|
+
"\\beta": 3, "β": 3, "𝛽": 3,
|
|
667
|
+
"\\gamma": 5, "γ": 5, "𝛾": 5,
|
|
668
|
+
"\\omega": 7, "ω": 7, "𝜔": 7,
|
|
669
|
+
"\\lambda": 6, "λ": 6, "𝜆": 6,
|
|
670
|
+
}
|
|
623
671
|
|
|
624
|
-
|
|
625
|
-
|
|
672
|
+
|
|
673
|
+
def hash_string_to_slot(s: str, num_slots: int = 8) -> int:
|
|
674
|
+
"""Dispersive hash mapping identifiers to palette slots with golden ratio dispersion."""
|
|
675
|
+
if s in CANONICAL_VARIABLE_SLOTS:
|
|
676
|
+
return CANONICAL_VARIABLE_SLOTS[s] % num_slots
|
|
677
|
+
|
|
678
|
+
# Knuth 32-bit multiplicative hash with golden ratio constant 2654435761 (0x9E3779B9)
|
|
626
679
|
h = 0
|
|
627
680
|
for char in s:
|
|
628
|
-
h = (h
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
681
|
+
h = ((h << 5) - h + ord(char)) & 0xFFFFFFFF
|
|
682
|
+
return ((h * 2654435761) & 0xFFFFFFFF) % num_slots
|
|
683
|
+
|
|
684
|
+
|
|
685
|
+
def hash_string_to_color(s: str, palette: list[str] = VARIABLE_HASH_PALETTE) -> str:
|
|
686
|
+
"""Deterministic string hashing for variable data-flow coloring with harmonic disambiguation."""
|
|
687
|
+
slot = hash_string_to_slot(s, len(palette))
|
|
688
|
+
return palette[slot]
|
|
633
689
|
|
|
634
690
|
|
|
635
691
|
@dataclass
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "python-color-math"
|
|
7
|
-
version = "0.2.
|
|
7
|
+
version = "0.2.22"
|
|
8
8
|
description = "A fast, local semantic LaTeX colorizer for Markdown, Jupyter, and LaTeX math equations."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.10"
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"""Unit tests for Harmonic Tuple Disambiguation & Perceptual Contrast."""
|
|
2
|
+
|
|
3
|
+
import unittest
|
|
4
|
+
from color_math.config import (
|
|
5
|
+
VARIABLE_HASH_PALETTE,
|
|
6
|
+
CANONICAL_VARIABLE_SLOTS,
|
|
7
|
+
hash_string_to_color,
|
|
8
|
+
hash_string_to_slot,
|
|
9
|
+
)
|
|
10
|
+
from color_math.converters.block import convert_text
|
|
11
|
+
from color_math.config import ColorMathOptions
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class TestHarmonicTupleDisambiguation(unittest.TestCase):
|
|
15
|
+
def test_spatial_coordinates_distinct(self):
|
|
16
|
+
"""Verify (x, y, z) are assigned mutually distinct, contrasting colors."""
|
|
17
|
+
col_x = hash_string_to_color("x")
|
|
18
|
+
col_y = hash_string_to_color("y")
|
|
19
|
+
col_z = hash_string_to_color("z")
|
|
20
|
+
self.assertNotEqual(col_x, col_y)
|
|
21
|
+
self.assertNotEqual(col_y, col_z)
|
|
22
|
+
self.assertNotEqual(col_x, col_z)
|
|
23
|
+
|
|
24
|
+
def test_coefficients_distinct(self):
|
|
25
|
+
"""Verify (a, b, c, d) are mutually distinct."""
|
|
26
|
+
col_a = hash_string_to_color("a")
|
|
27
|
+
col_b = hash_string_to_color("b")
|
|
28
|
+
col_c = hash_string_to_color("c")
|
|
29
|
+
col_d = hash_string_to_color("d")
|
|
30
|
+
colors = {col_a, col_b, col_c, col_d}
|
|
31
|
+
self.assertEqual(len(colors), 4)
|
|
32
|
+
|
|
33
|
+
def test_parameters_distinct(self):
|
|
34
|
+
"""Verify (u, v, w) are mutually distinct."""
|
|
35
|
+
col_u = hash_string_to_color("u")
|
|
36
|
+
col_v = hash_string_to_color("v")
|
|
37
|
+
col_w = hash_string_to_color("w")
|
|
38
|
+
colors = {col_u, col_v, col_w}
|
|
39
|
+
self.assertEqual(len(colors), 3)
|
|
40
|
+
|
|
41
|
+
def test_indices_distinct(self):
|
|
42
|
+
"""Verify (i, j, k, l) are mutually distinct."""
|
|
43
|
+
col_i = hash_string_to_color("i")
|
|
44
|
+
col_j = hash_string_to_color("j")
|
|
45
|
+
col_k = hash_string_to_color("k")
|
|
46
|
+
col_l = hash_string_to_color("l")
|
|
47
|
+
colors = {col_i, col_j, col_k, col_l}
|
|
48
|
+
self.assertEqual(len(colors), 4)
|
|
49
|
+
|
|
50
|
+
def test_linear_combination_cross_contrast(self):
|
|
51
|
+
"""Verify in ax + by + cz, all six variables receive distinct colors."""
|
|
52
|
+
vars_to_test = ["a", "x", "b", "y", "c", "z"]
|
|
53
|
+
colors = [hash_string_to_color(v) for v in vars_to_test]
|
|
54
|
+
# In term 1: a != x
|
|
55
|
+
self.assertNotEqual(colors[0], colors[1])
|
|
56
|
+
# In term 2: b != y
|
|
57
|
+
self.assertNotEqual(colors[2], colors[3])
|
|
58
|
+
# In term 3: c != z
|
|
59
|
+
self.assertNotEqual(colors[4], colors[5])
|
|
60
|
+
# All 6 must be unique!
|
|
61
|
+
self.assertEqual(len(set(colors)), 6)
|
|
62
|
+
|
|
63
|
+
def test_rendered_linear_combination_equation(self):
|
|
64
|
+
"""Verify full math expression rendering of ax + by + cz = d."""
|
|
65
|
+
eq = "$$ax + by + cz = d$$"
|
|
66
|
+
opts = ColorMathOptions.all_enabled()
|
|
67
|
+
res = convert_text(eq, options=opts)
|
|
68
|
+
self.assertIn(r"\textcolor{#bb9af7}{a}", res)
|
|
69
|
+
self.assertIn(r"\textcolor{#7aa2f7}{x}", res)
|
|
70
|
+
self.assertIn(r"\textcolor{#f7768e}{b}", res)
|
|
71
|
+
self.assertIn(r"\textcolor{#e0af68}{y}", res)
|
|
72
|
+
self.assertIn(r"\textcolor{#2ac3de}{c}", res)
|
|
73
|
+
self.assertIn(r"\textcolor{#9ece6a}{z}", res)
|
|
74
|
+
|
|
75
|
+
def test_dispersive_hash_unknown_variables(self):
|
|
76
|
+
"""Verify arbitrary variables receive deterministic slots."""
|
|
77
|
+
s1 = hash_string_to_slot("var1")
|
|
78
|
+
s2 = hash_string_to_slot("var1")
|
|
79
|
+
self.assertEqual(s1, s2)
|
|
80
|
+
self.assertTrue(0 <= s1 < 8)
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
if __name__ == "__main__":
|
|
84
|
+
unittest.main()
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_color_math-0.2.21 → python_color_math-0.2.22}/color_math/converters/unicode_converter.py
RENAMED
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_color_math-0.2.21 → python_color_math-0.2.22}/color_math/parsers/markdown_scanner.py
RENAMED
|
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
|
|
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
|
{python_color_math-0.2.21 → python_color_math-0.2.22}/python_color_math.egg-info/entry_points.txt
RENAMED
|
File without changes
|
{python_color_math-0.2.21 → python_color_math-0.2.22}/python_color_math.egg-info/requires.txt
RENAMED
|
File without changes
|
{python_color_math-0.2.21 → python_color_math-0.2.22}/python_color_math.egg-info/top_level.txt
RENAMED
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|