python-color-math 0.2.1__tar.gz → 0.2.2__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.1/python_color_math.egg-info → python_color_math-0.2.2}/PKG-INFO +2 -2
- {python_color_math-0.2.1 → python_color_math-0.2.2}/README.md +1 -1
- {python_color_math-0.2.1 → python_color_math-0.2.2}/color_math/__init__.py +1 -1
- {python_color_math-0.2.1 → python_color_math-0.2.2}/color_math/main.py +1 -1
- {python_color_math-0.2.1 → python_color_math-0.2.2}/color_math/mcp_server.py +109 -70
- {python_color_math-0.2.1 → python_color_math-0.2.2}/pyproject.toml +1 -1
- {python_color_math-0.2.1 → python_color_math-0.2.2/python_color_math.egg-info}/PKG-INFO +2 -2
- {python_color_math-0.2.1 → python_color_math-0.2.2}/tests/test_mcp_hardcore.py +24 -0
- {python_color_math-0.2.1 → python_color_math-0.2.2}/.pre-commit-hooks.yaml +0 -0
- {python_color_math-0.2.1 → python_color_math-0.2.2}/LICENSE +0 -0
- {python_color_math-0.2.1 → python_color_math-0.2.2}/MANIFEST.in +0 -0
- {python_color_math-0.2.1 → python_color_math-0.2.2}/color_math/__main__.py +0 -0
- {python_color_math-0.2.1 → python_color_math-0.2.2}/color_math/adapters.py +0 -0
- {python_color_math-0.2.1 → python_color_math-0.2.2}/color_math/completions.py +0 -0
- {python_color_math-0.2.1 → python_color_math-0.2.2}/color_math/config.py +0 -0
- {python_color_math-0.2.1 → python_color_math-0.2.2}/color_math/converters/__init__.py +0 -0
- {python_color_math-0.2.1 → python_color_math-0.2.2}/color_math/converters/align.py +0 -0
- {python_color_math-0.2.1 → python_color_math-0.2.2}/color_math/converters/block.py +0 -0
- {python_color_math-0.2.1 → python_color_math-0.2.2}/color_math/converters/derivative.py +0 -0
- {python_color_math-0.2.1 → python_color_math-0.2.2}/color_math/converters/equation.py +0 -0
- {python_color_math-0.2.1 → python_color_math-0.2.2}/color_math/converters/generic.py +0 -0
- {python_color_math-0.2.1 → python_color_math-0.2.2}/color_math/converters/integral.py +0 -0
- {python_color_math-0.2.1 → python_color_math-0.2.2}/color_math/converters/limit.py +0 -0
- {python_color_math-0.2.1 → python_color_math-0.2.2}/color_math/converters/matrix.py +0 -0
- {python_color_math-0.2.1 → python_color_math-0.2.2}/color_math/converters/semantic.py +0 -0
- {python_color_math-0.2.1 → python_color_math-0.2.2}/color_math/gui.py +0 -0
- {python_color_math-0.2.1 → python_color_math-0.2.2}/color_math/io.py +0 -0
- {python_color_math-0.2.1 → python_color_math-0.2.2}/color_math/mcp.py +0 -0
- {python_color_math-0.2.1 → python_color_math-0.2.2}/color_math/parsers/__init__.py +0 -0
- {python_color_math-0.2.1 → python_color_math-0.2.2}/color_math/parsers/alignment.py +0 -0
- {python_color_math-0.2.1 → python_color_math-0.2.2}/color_math/parsers/braket.py +0 -0
- {python_color_math-0.2.1 → python_color_math-0.2.2}/color_math/parsers/constants.py +0 -0
- {python_color_math-0.2.1 → python_color_math-0.2.2}/color_math/parsers/delimiters.py +0 -0
- {python_color_math-0.2.1 → python_color_math-0.2.2}/color_math/parsers/differentials.py +0 -0
- {python_color_math-0.2.1 → python_color_math-0.2.2}/color_math/parsers/dimensionless.py +0 -0
- {python_color_math-0.2.1 → python_color_math-0.2.2}/color_math/parsers/latex_spans.py +0 -0
- {python_color_math-0.2.1 → python_color_math-0.2.2}/color_math/parsers/markdown_scanner.py +0 -0
- {python_color_math-0.2.1 → python_color_math-0.2.2}/color_math/parsers/math_parser.py +0 -0
- {python_color_math-0.2.1 → python_color_math-0.2.2}/color_math/parsers/scanner.py +0 -0
- {python_color_math-0.2.1 → python_color_math-0.2.2}/color_math/parsers/taxonomy.py +0 -0
- {python_color_math-0.2.1 → python_color_math-0.2.2}/color_math/parsers/units.py +0 -0
- {python_color_math-0.2.1 → python_color_math-0.2.2}/color_math/parsers/variable_hash.py +0 -0
- {python_color_math-0.2.1 → python_color_math-0.2.2}/color_math/py.typed +0 -0
- {python_color_math-0.2.1 → python_color_math-0.2.2}/color_math/self_test.py +0 -0
- {python_color_math-0.2.1 → python_color_math-0.2.2}/color_math/tutorial.py +0 -0
- {python_color_math-0.2.1 → python_color_math-0.2.2}/color_math/undo.py +0 -0
- {python_color_math-0.2.1 → python_color_math-0.2.2}/color_math/utils/__init__.py +0 -0
- {python_color_math-0.2.1 → python_color_math-0.2.2}/color_math/utils/coloring.py +0 -0
- {python_color_math-0.2.1 → python_color_math-0.2.2}/color_math/utils/latex_helpers.py +0 -0
- {python_color_math-0.2.1 → python_color_math-0.2.2}/color_math/utils/spans.py +0 -0
- {python_color_math-0.2.1 → python_color_math-0.2.2}/python_color_math/__init__.py +0 -0
- {python_color_math-0.2.1 → python_color_math-0.2.2}/python_color_math/__main__.py +0 -0
- {python_color_math-0.2.1 → python_color_math-0.2.2}/python_color_math.egg-info/SOURCES.txt +0 -0
- {python_color_math-0.2.1 → python_color_math-0.2.2}/python_color_math.egg-info/dependency_links.txt +0 -0
- {python_color_math-0.2.1 → python_color_math-0.2.2}/python_color_math.egg-info/entry_points.txt +0 -0
- {python_color_math-0.2.1 → python_color_math-0.2.2}/python_color_math.egg-info/requires.txt +0 -0
- {python_color_math-0.2.1 → python_color_math-0.2.2}/python_color_math.egg-info/top_level.txt +0 -0
- {python_color_math-0.2.1 → python_color_math-0.2.2}/setup.cfg +0 -0
- {python_color_math-0.2.1 → python_color_math-0.2.2}/tests/test_adversarial.py +0 -0
- {python_color_math-0.2.1 → python_color_math-0.2.2}/tests/test_cli.py +0 -0
- {python_color_math-0.2.1 → python_color_math-0.2.2}/tests/test_features.py +0 -0
- {python_color_math-0.2.1 → python_color_math-0.2.2}/tests/test_fuzz.py +0 -0
- {python_color_math-0.2.1 → python_color_math-0.2.2}/tests/test_gui.py +0 -0
- {python_color_math-0.2.1 → python_color_math-0.2.2}/tests/test_mcp_server.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-color-math
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.2
|
|
4
4
|
Summary: A fast, local semantic LaTeX colorizer for Markdown, Jupyter, and LaTeX math equations.
|
|
5
5
|
Author: Aditya
|
|
6
6
|
License: MIT License
|
|
@@ -232,7 +232,7 @@ Integrate `color-math` into your git workflow using [pre-commit](https://pre-com
|
|
|
232
232
|
```yaml
|
|
233
233
|
repos:
|
|
234
234
|
- repo: https://github.com/36ty-blip/color-math
|
|
235
|
-
rev: v0.2.
|
|
235
|
+
rev: v0.2.2
|
|
236
236
|
hooks:
|
|
237
237
|
# Formatter: colorizes modified Markdown, LaTeX, and Jupyter files in-place
|
|
238
238
|
- id: color-math
|
|
@@ -175,7 +175,7 @@ Integrate `color-math` into your git workflow using [pre-commit](https://pre-com
|
|
|
175
175
|
```yaml
|
|
176
176
|
repos:
|
|
177
177
|
- repo: https://github.com/36ty-blip/color-math
|
|
178
|
-
rev: v0.2.
|
|
178
|
+
rev: v0.2.2
|
|
179
179
|
hooks:
|
|
180
180
|
# Formatter: colorizes modified Markdown, LaTeX, and Jupyter files in-place
|
|
181
181
|
- id: color-math
|
|
@@ -32,7 +32,7 @@ from .parsers.math_parser import describe_math_blocks
|
|
|
32
32
|
from .self_test import run_self_test
|
|
33
33
|
from .tutorial import run_tutorial
|
|
34
34
|
|
|
35
|
-
VERSION = "0.2.
|
|
35
|
+
VERSION = "0.2.2"
|
|
36
36
|
SUPPORTED_EXTENSIONS = {".md", ".markdown", ".qmd", ".ipynb", ".tex", ".latex"}
|
|
37
37
|
DEFAULT_EXCLUDES = {
|
|
38
38
|
".git",
|
|
@@ -149,22 +149,30 @@ def create_mcp_server() -> MCPServer:
|
|
|
149
149
|
normalize_braces=normalize_braces,
|
|
150
150
|
)
|
|
151
151
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
152
|
+
try:
|
|
153
|
+
clean_expr = expression.strip()
|
|
154
|
+
had_delimiters = clean_expr.startswith("$$") and clean_expr.endswith("$$")
|
|
155
|
+
block_text = clean_expr if had_delimiters else f"$${clean_expr}$$"
|
|
155
156
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
157
|
+
colored = convert_math_block(block_text, pal, opts)
|
|
158
|
+
if not had_delimiters and colored.startswith("$$") and colored.endswith("$$"):
|
|
159
|
+
colored_output = colored[2:-2]
|
|
160
|
+
else:
|
|
161
|
+
colored_output = colored
|
|
161
162
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
163
|
+
return {
|
|
164
|
+
"original": expression,
|
|
165
|
+
"colorized": colored_output,
|
|
166
|
+
"changed": colored_output != expression,
|
|
167
|
+
"theme": theme,
|
|
168
|
+
}
|
|
169
|
+
except Exception as err:
|
|
170
|
+
return {
|
|
171
|
+
"original": expression,
|
|
172
|
+
"error": str(err),
|
|
173
|
+
"changed": False,
|
|
174
|
+
"theme": theme,
|
|
175
|
+
}
|
|
168
176
|
|
|
169
177
|
@server.tool(
|
|
170
178
|
name="colorize_text",
|
|
@@ -199,16 +207,25 @@ def create_mcp_server() -> MCPServer:
|
|
|
199
207
|
normalize_braces=normalize_braces,
|
|
200
208
|
)
|
|
201
209
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
210
|
+
try:
|
|
211
|
+
fmt = format_name if format_name in FORMATS else "markdown"
|
|
212
|
+
result = transform_document(text, fmt, undo=False, palette=pal, options=opts)
|
|
213
|
+
return {
|
|
214
|
+
"format": fmt,
|
|
215
|
+
"theme": theme,
|
|
216
|
+
"original_length": len(text),
|
|
217
|
+
"colorized_length": len(result),
|
|
218
|
+
"changed": result != text,
|
|
219
|
+
"result": result,
|
|
220
|
+
}
|
|
221
|
+
except Exception as err:
|
|
222
|
+
return {
|
|
223
|
+
"format": format_name,
|
|
224
|
+
"theme": theme,
|
|
225
|
+
"error": str(err),
|
|
226
|
+
"changed": False,
|
|
227
|
+
"result": text,
|
|
228
|
+
}
|
|
212
229
|
|
|
213
230
|
@server.tool(
|
|
214
231
|
name="uncolor_text",
|
|
@@ -221,15 +238,23 @@ def create_mcp_server() -> MCPServer:
|
|
|
221
238
|
text: str,
|
|
222
239
|
format_name: str = "markdown",
|
|
223
240
|
) -> dict[str, Any]:
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
241
|
+
try:
|
|
242
|
+
fmt = format_name if format_name in FORMATS else "markdown"
|
|
243
|
+
result = transform_document(text, fmt, undo=True)
|
|
244
|
+
return {
|
|
245
|
+
"format": fmt,
|
|
246
|
+
"original_length": len(text),
|
|
247
|
+
"cleaned_length": len(result),
|
|
248
|
+
"changed": result != text,
|
|
249
|
+
"result": result,
|
|
250
|
+
}
|
|
251
|
+
except Exception as err:
|
|
252
|
+
return {
|
|
253
|
+
"format": format_name,
|
|
254
|
+
"error": str(err),
|
|
255
|
+
"changed": False,
|
|
256
|
+
"result": text,
|
|
257
|
+
}
|
|
233
258
|
|
|
234
259
|
@server.tool(
|
|
235
260
|
name="process_file",
|
|
@@ -271,47 +296,56 @@ def create_mcp_server() -> MCPServer:
|
|
|
271
296
|
normalize_braces=normalize_braces,
|
|
272
297
|
)
|
|
273
298
|
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
299
|
+
try:
|
|
300
|
+
fmt = detect_format(path)
|
|
301
|
+
original_text, raw_bytes = read_utf8(path)
|
|
302
|
+
transformed = transform_document(
|
|
303
|
+
original_text, fmt, undo=undo, palette=pal, options=opts
|
|
304
|
+
)
|
|
279
305
|
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
306
|
+
changed = transformed != original_text
|
|
307
|
+
diff_output = ""
|
|
308
|
+
if changed:
|
|
309
|
+
diff_lines = list(
|
|
310
|
+
difflib.unified_diff(
|
|
311
|
+
original_text.splitlines(keepends=True),
|
|
312
|
+
transformed.splitlines(keepends=True),
|
|
313
|
+
fromfile=str(path),
|
|
314
|
+
tofile=str(path),
|
|
315
|
+
)
|
|
289
316
|
)
|
|
290
|
-
|
|
291
|
-
diff_output = "".join(diff_lines[:100]) # limit diff length
|
|
317
|
+
diff_output = "".join(diff_lines[:100]) # limit diff length
|
|
292
318
|
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
319
|
+
written = False
|
|
320
|
+
if changed and in_place:
|
|
321
|
+
new_bytes = encode_utf8(transformed, raw_bytes)
|
|
322
|
+
written = replace_bytes(path, new_bytes, raw_bytes)
|
|
297
323
|
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
324
|
+
return {
|
|
325
|
+
"file_path": str(path),
|
|
326
|
+
"format": fmt,
|
|
327
|
+
"action": "undo" if undo else "colorize",
|
|
328
|
+
"changed": changed,
|
|
329
|
+
"written_to_disk": written,
|
|
330
|
+
"diff": diff_output if changed else None,
|
|
331
|
+
"message": (
|
|
332
|
+
f"File successfully updated on disk: {path.name}"
|
|
333
|
+
if written
|
|
334
|
+
else (
|
|
335
|
+
f"Dry run complete: changes detected in {path.name}"
|
|
336
|
+
if changed
|
|
337
|
+
else f"No changes needed: {path.name} is already up to date."
|
|
338
|
+
)
|
|
339
|
+
),
|
|
340
|
+
}
|
|
341
|
+
except Exception as err:
|
|
342
|
+
return {
|
|
343
|
+
"file_path": str(path),
|
|
344
|
+
"error": str(err),
|
|
345
|
+
"changed": False,
|
|
346
|
+
"written_to_disk": False,
|
|
347
|
+
"message": f"Error processing {path.name}: {err}",
|
|
348
|
+
}
|
|
315
349
|
|
|
316
350
|
@server.tool(
|
|
317
351
|
name="scan_vault",
|
|
@@ -423,3 +457,8 @@ def run_mcp_server(transport: str = "stdio", **kwargs: Any) -> None:
|
|
|
423
457
|
server.run(transport="streamable-http", **kwargs)
|
|
424
458
|
else:
|
|
425
459
|
raise ValueError(f"Unsupported transport: {transport}. Expected 'stdio', 'sse', or 'streamable-http'.")
|
|
460
|
+
|
|
461
|
+
|
|
462
|
+
if __name__ == "__main__":
|
|
463
|
+
run_mcp_server()
|
|
464
|
+
|
|
@@ -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.2"
|
|
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"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-color-math
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.2
|
|
4
4
|
Summary: A fast, local semantic LaTeX colorizer for Markdown, Jupyter, and LaTeX math equations.
|
|
5
5
|
Author: Aditya
|
|
6
6
|
License: MIT License
|
|
@@ -232,7 +232,7 @@ Integrate `color-math` into your git workflow using [pre-commit](https://pre-com
|
|
|
232
232
|
```yaml
|
|
233
233
|
repos:
|
|
234
234
|
- repo: https://github.com/36ty-blip/color-math
|
|
235
|
-
rev: v0.2.
|
|
235
|
+
rev: v0.2.2
|
|
236
236
|
hooks:
|
|
237
237
|
# Formatter: colorizes modified Markdown, LaTeX, and Jupyter files in-place
|
|
238
238
|
- id: color-math
|
|
@@ -406,6 +406,30 @@ $$"""
|
|
|
406
406
|
self.assertIn("-", colorized)
|
|
407
407
|
self.assertIn(r"\end{cases}", colorized)
|
|
408
408
|
|
|
409
|
+
# -------------------------------------------------------------
|
|
410
|
+
# 13. Adversarial MCP Error Resilience (Malformed Input, Binary Files)
|
|
411
|
+
# -------------------------------------------------------------
|
|
412
|
+
def test_adversarial_error_resilience(self) -> None:
|
|
413
|
+
"""Verify that malformed inputs and binary files return structured error dicts without crashing."""
|
|
414
|
+
# 1. Malformed Jupyter notebook in colorize_text
|
|
415
|
+
bad_ipynb = "{\n \"cells\": [ this is not valid json! \n"
|
|
416
|
+
res_color = self._call("colorize_text", {"text": bad_ipynb, "format_name": "jupyter"})
|
|
417
|
+
self.assertFalse(res_color.get("changed", True))
|
|
418
|
+
self.assertIn("error", res_color)
|
|
419
|
+
|
|
420
|
+
# 2. Malformed Jupyter notebook in uncolor_text
|
|
421
|
+
res_uncolor = self._call("uncolor_text", {"text": bad_ipynb, "format_name": "jupyter"})
|
|
422
|
+
self.assertFalse(res_uncolor.get("changed", True))
|
|
423
|
+
self.assertIn("error", res_uncolor)
|
|
424
|
+
|
|
425
|
+
# 3. Binary file in process_file
|
|
426
|
+
with tempfile.TemporaryDirectory() as tmpdir:
|
|
427
|
+
bin_file = Path(tmpdir) / "corrupt.md"
|
|
428
|
+
bin_file.write_bytes(b"\xff\xfe\x00\x00\xaa\xbb\xcc")
|
|
429
|
+
res_proc = self._call("process_file", {"file_path": str(bin_file)})
|
|
430
|
+
self.assertFalse(res_proc.get("changed", True))
|
|
431
|
+
self.assertIn("error", res_proc)
|
|
432
|
+
|
|
409
433
|
|
|
410
434
|
if __name__ == "__main__":
|
|
411
435
|
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
|
|
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
|
|
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.1 → python_color_math-0.2.2}/python_color_math.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
{python_color_math-0.2.1 → python_color_math-0.2.2}/python_color_math.egg-info/entry_points.txt
RENAMED
|
File without changes
|
|
File without changes
|
{python_color_math-0.2.1 → python_color_math-0.2.2}/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
|