python-color-math 0.2.16__tar.gz → 0.2.18__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.
Files changed (80) hide show
  1. {python_color_math-0.2.16/python_color_math.egg-info → python_color_math-0.2.18}/PKG-INFO +1 -1
  2. {python_color_math-0.2.16 → python_color_math-0.2.18}/color_math/__init__.py +4 -2
  3. {python_color_math-0.2.16 → python_color_math-0.2.18}/color_math/config.py +56 -1
  4. {python_color_math-0.2.16 → python_color_math-0.2.18}/color_math/ipython.py +24 -2
  5. {python_color_math-0.2.16 → python_color_math-0.2.18}/color_math/main.py +10 -0
  6. {python_color_math-0.2.16 → python_color_math-0.2.18}/pyproject.toml +1 -1
  7. {python_color_math-0.2.16 → python_color_math-0.2.18/python_color_math.egg-info}/PKG-INFO +1 -1
  8. {python_color_math-0.2.16 → python_color_math-0.2.18}/tests/test_ipython.py +4 -2
  9. {python_color_math-0.2.16 → python_color_math-0.2.18}/tests/test_mcp_hardcore.py +3 -0
  10. {python_color_math-0.2.16 → python_color_math-0.2.18}/tests/test_mcp_server.py +3 -0
  11. {python_color_math-0.2.16 → python_color_math-0.2.18}/.pre-commit-hooks.yaml +0 -0
  12. {python_color_math-0.2.16 → python_color_math-0.2.18}/LICENSE +0 -0
  13. {python_color_math-0.2.16 → python_color_math-0.2.18}/MANIFEST.in +0 -0
  14. {python_color_math-0.2.16 → python_color_math-0.2.18}/README.md +0 -0
  15. {python_color_math-0.2.16 → python_color_math-0.2.18}/color_math/__main__.py +0 -0
  16. {python_color_math-0.2.16 → python_color_math-0.2.18}/color_math/adapters.py +0 -0
  17. {python_color_math-0.2.16 → python_color_math-0.2.18}/color_math/colormath.default.json +0 -0
  18. {python_color_math-0.2.16 → python_color_math-0.2.18}/color_math/completions.py +0 -0
  19. {python_color_math-0.2.16 → python_color_math-0.2.18}/color_math/converters/__init__.py +0 -0
  20. {python_color_math-0.2.16 → python_color_math-0.2.18}/color_math/converters/align.py +0 -0
  21. {python_color_math-0.2.16 → python_color_math-0.2.18}/color_math/converters/block.py +0 -0
  22. {python_color_math-0.2.16 → python_color_math-0.2.18}/color_math/converters/derivative.py +0 -0
  23. {python_color_math-0.2.16 → python_color_math-0.2.18}/color_math/converters/equation.py +0 -0
  24. {python_color_math-0.2.16 → python_color_math-0.2.18}/color_math/converters/generic.py +0 -0
  25. {python_color_math-0.2.16 → python_color_math-0.2.18}/color_math/converters/integral.py +0 -0
  26. {python_color_math-0.2.16 → python_color_math-0.2.18}/color_math/converters/limit.py +0 -0
  27. {python_color_math-0.2.16 → python_color_math-0.2.18}/color_math/converters/matrix.py +0 -0
  28. {python_color_math-0.2.16 → python_color_math-0.2.18}/color_math/converters/semantic.py +0 -0
  29. {python_color_math-0.2.16 → python_color_math-0.2.18}/color_math/converters/unicode_converter.py +0 -0
  30. {python_color_math-0.2.16 → python_color_math-0.2.18}/color_math/custom_definitions.py +0 -0
  31. {python_color_math-0.2.16 → python_color_math-0.2.18}/color_math/gui.py +0 -0
  32. {python_color_math-0.2.16 → python_color_math-0.2.18}/color_math/io.py +0 -0
  33. {python_color_math-0.2.16 → python_color_math-0.2.18}/color_math/jupyter.py +0 -0
  34. {python_color_math-0.2.16 → python_color_math-0.2.18}/color_math/mcp.py +0 -0
  35. {python_color_math-0.2.16 → python_color_math-0.2.18}/color_math/mcp_server.py +0 -0
  36. {python_color_math-0.2.16 → python_color_math-0.2.18}/color_math/parsers/__init__.py +0 -0
  37. {python_color_math-0.2.16 → python_color_math-0.2.18}/color_math/parsers/alignment.py +0 -0
  38. {python_color_math-0.2.16 → python_color_math-0.2.18}/color_math/parsers/braket.py +0 -0
  39. {python_color_math-0.2.16 → python_color_math-0.2.18}/color_math/parsers/constants.py +0 -0
  40. {python_color_math-0.2.16 → python_color_math-0.2.18}/color_math/parsers/delimiters.py +0 -0
  41. {python_color_math-0.2.16 → python_color_math-0.2.18}/color_math/parsers/differentials.py +0 -0
  42. {python_color_math-0.2.16 → python_color_math-0.2.18}/color_math/parsers/dimensionless.py +0 -0
  43. {python_color_math-0.2.16 → python_color_math-0.2.18}/color_math/parsers/frontmatter.py +0 -0
  44. {python_color_math-0.2.16 → python_color_math-0.2.18}/color_math/parsers/latex_spans.py +0 -0
  45. {python_color_math-0.2.16 → python_color_math-0.2.18}/color_math/parsers/markdown_scanner.py +0 -0
  46. {python_color_math-0.2.16 → python_color_math-0.2.18}/color_math/parsers/math_parser.py +0 -0
  47. {python_color_math-0.2.16 → python_color_math-0.2.18}/color_math/parsers/physics.py +0 -0
  48. {python_color_math-0.2.16 → python_color_math-0.2.18}/color_math/parsers/scanner.py +0 -0
  49. {python_color_math-0.2.16 → python_color_math-0.2.18}/color_math/parsers/taxonomy.py +0 -0
  50. {python_color_math-0.2.16 → python_color_math-0.2.18}/color_math/parsers/units.py +0 -0
  51. {python_color_math-0.2.16 → python_color_math-0.2.18}/color_math/parsers/variable_hash.py +0 -0
  52. {python_color_math-0.2.16 → python_color_math-0.2.18}/color_math/py.typed +0 -0
  53. {python_color_math-0.2.16 → python_color_math-0.2.18}/color_math/self_test.py +0 -0
  54. {python_color_math-0.2.16 → python_color_math-0.2.18}/color_math/tutorial.py +0 -0
  55. {python_color_math-0.2.16 → python_color_math-0.2.18}/color_math/undo.py +0 -0
  56. {python_color_math-0.2.16 → python_color_math-0.2.18}/color_math/unicode.py +0 -0
  57. {python_color_math-0.2.16 → python_color_math-0.2.18}/color_math/utils/__init__.py +0 -0
  58. {python_color_math-0.2.16 → python_color_math-0.2.18}/color_math/utils/coloring.py +0 -0
  59. {python_color_math-0.2.16 → python_color_math-0.2.18}/color_math/utils/latex_helpers.py +0 -0
  60. {python_color_math-0.2.16 → python_color_math-0.2.18}/color_math/utils/spans.py +0 -0
  61. {python_color_math-0.2.16 → python_color_math-0.2.18}/python_color_math/__init__.py +0 -0
  62. {python_color_math-0.2.16 → python_color_math-0.2.18}/python_color_math/__main__.py +0 -0
  63. {python_color_math-0.2.16 → python_color_math-0.2.18}/python_color_math.egg-info/SOURCES.txt +0 -0
  64. {python_color_math-0.2.16 → python_color_math-0.2.18}/python_color_math.egg-info/dependency_links.txt +0 -0
  65. {python_color_math-0.2.16 → python_color_math-0.2.18}/python_color_math.egg-info/entry_points.txt +0 -0
  66. {python_color_math-0.2.16 → python_color_math-0.2.18}/python_color_math.egg-info/requires.txt +0 -0
  67. {python_color_math-0.2.16 → python_color_math-0.2.18}/python_color_math.egg-info/top_level.txt +0 -0
  68. {python_color_math-0.2.16 → python_color_math-0.2.18}/setup.cfg +0 -0
  69. {python_color_math-0.2.16 → python_color_math-0.2.18}/tests/test_adversarial.py +0 -0
  70. {python_color_math-0.2.16 → python_color_math-0.2.18}/tests/test_cli.py +0 -0
  71. {python_color_math-0.2.16 → python_color_math-0.2.18}/tests/test_config_tolerance.py +0 -0
  72. {python_color_math-0.2.16 → python_color_math-0.2.18}/tests/test_custom_definitions.py +0 -0
  73. {python_color_math-0.2.16 → python_color_math-0.2.18}/tests/test_extreme_adversarial.py +0 -0
  74. {python_color_math-0.2.16 → python_color_math-0.2.18}/tests/test_features.py +0 -0
  75. {python_color_math-0.2.16 → python_color_math-0.2.18}/tests/test_frontmatter.py +0 -0
  76. {python_color_math-0.2.16 → python_color_math-0.2.18}/tests/test_fuzz.py +0 -0
  77. {python_color_math-0.2.16 → python_color_math-0.2.18}/tests/test_gui.py +0 -0
  78. {python_color_math-0.2.16 → python_color_math-0.2.18}/tests/test_physics.py +0 -0
  79. {python_color_math-0.2.16 → python_color_math-0.2.18}/tests/test_unicode.py +0 -0
  80. {python_color_math-0.2.16 → python_color_math-0.2.18}/tests/test_unicode_converter.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-color-math
3
- Version: 0.2.16
3
+ Version: 0.2.18
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
@@ -1,13 +1,13 @@
1
1
  """Public helpers for converting Obsidian LaTeX color markup."""
2
2
 
3
3
  from .adapters import detect_format, transform_document
4
- from .config import ColorMathOptions
4
+ from .config import ColorMathOptions, ensure_global_config_exists, open_config_folder
5
5
  from .converters.block import convert_text
6
6
  from .undo import uncolor_text
7
7
 
8
8
  from .ipython import ColorMath, colormath, load_ipython_extension, unload_ipython_extension
9
9
 
10
- __version__ = "0.2.16"
10
+ __version__ = "0.2.18"
11
11
 
12
12
  __all__ = [
13
13
  "__version__",
@@ -16,7 +16,9 @@ __all__ = [
16
16
  "colormath",
17
17
  "convert_text",
18
18
  "detect_format",
19
+ "ensure_global_config_exists",
19
20
  "load_ipython_extension",
21
+ "open_config_folder",
20
22
  "transform_document",
21
23
  "uncolor_text",
22
24
  "unload_ipython_extension",
@@ -730,6 +730,61 @@ def get_global_config_path() -> Path | None:
730
730
  return None
731
731
 
732
732
 
733
+ def ensure_global_config_exists() -> Path | None:
734
+ """Ensure that the global configuration file and folder exist on disk.
735
+
736
+ Creates the directory and saves the documented default configuration if it
737
+ does not already exist. Returns the Path to the global config.
738
+ """
739
+ path = get_global_config_path()
740
+ if path is None:
741
+ return None
742
+ if not path.exists():
743
+ try:
744
+ path.parent.mkdir(parents=True, exist_ok=True)
745
+ save_default_config(path)
746
+ except OSError:
747
+ pass
748
+ return path
749
+
750
+
751
+ def open_config_folder(path: Path | None = None) -> bool:
752
+ """Open the configuration folder in the operating system's file manager."""
753
+ target = path
754
+ if target is None:
755
+ local_candidate = Path(".colormath.json")
756
+ if local_candidate.exists():
757
+ target = local_candidate
758
+ else:
759
+ target = ensure_global_config_exists() or get_global_config_path()
760
+
761
+ if target is None:
762
+ return False
763
+
764
+ folder = target.parent if target.suffix else target
765
+ try:
766
+ folder.mkdir(parents=True, exist_ok=True)
767
+ if not target.exists() and target.suffix == ".json":
768
+ save_default_config(target)
769
+ except OSError:
770
+ pass
771
+
772
+ try:
773
+ if sys.platform == "win32":
774
+ os.startfile(folder)
775
+ return True
776
+ elif sys.platform == "darwin":
777
+ import subprocess
778
+ subprocess.run(["open", str(folder)], check=False)
779
+ return True
780
+ else:
781
+ import subprocess
782
+ subprocess.run(["xdg-open", str(folder)], check=False)
783
+ return True
784
+ except Exception:
785
+ return False
786
+
787
+
733
788
  DEFAULT_UNICODE_CONFIG: dict[str, object] = {
734
789
  "greek_style": "plane1",
735
790
  "convert_definite_integrals": False,
@@ -781,7 +836,7 @@ def load_config(
781
836
  if local_candidate.exists():
782
837
  target = local_candidate
783
838
  else:
784
- global_candidate = get_global_config_path()
839
+ global_candidate = ensure_global_config_exists()
785
840
  if global_candidate and global_candidate.exists():
786
841
  target = global_candidate
787
842
 
@@ -16,6 +16,8 @@ from .config import (
16
16
  THEMES,
17
17
  load_config,
18
18
  get_global_config_path,
19
+ ensure_global_config_exists,
20
+ open_config_folder,
19
21
  save_default_config,
20
22
  )
21
23
  from .converters.block import convert_math_block, convert_text
@@ -191,14 +193,22 @@ if HAS_IPYTHON:
191
193
  save_default_config(target)
192
194
  print(f"Color Math: Created config template at '{target.resolve()}'.")
193
195
  self._palette, self._options, _ = load_config(target)
196
+ raw = line.strip().lower()
197
+ if raw in ("open", "--open", "explore", "folder"):
198
+ opened = open_config_folder()
199
+ if opened:
200
+ print("Color Math: Opened configuration folder in file manager.")
201
+ else:
202
+ print("Color Math: Could not open configuration folder automatically.")
194
203
  return
195
- if "--reload" in raw:
204
+
205
+ if "--reload" in raw or raw == "reload":
196
206
  self._palette, self._options, _ = load_config()
197
207
  print("Color Math: Configuration reloaded.")
198
208
  return
199
209
 
200
210
  local_path = Path(".colormath.json")
201
- global_path = get_global_config_path()
211
+ global_path = ensure_global_config_exists() or get_global_config_path()
202
212
  print("Color Math Configuration:")
203
213
  print(f" Local config: {local_path.resolve()} ({'exists' if local_path.exists() else 'not found'})")
204
214
  if global_path:
@@ -207,6 +217,7 @@ if HAS_IPYTHON:
207
217
  print(f" Taxonomy: {'ENABLED' if self._options.enable_taxonomy else 'DISABLED'}")
208
218
  print(f" Delimiters: {'ENABLED' if self._options.rainbow_delimiters else 'DISABLED'}")
209
219
  print(f" Auto-display: {'ENABLED' if self._auto_hook_active else 'DISABLED'}")
220
+ print("\nTip: Run '%color_math_config open' to open the configuration folder in your file manager.")
210
221
 
211
222
  @line_magic("color_math_auto")
212
223
  def color_math_auto(self, line: str) -> None:
@@ -257,6 +268,17 @@ if HAS_IPYTHON:
257
268
  if self._orig_math_repr is not None:
258
269
  Math._repr_latex_ = self._orig_math_repr # type: ignore[assignment]
259
270
  self._auto_hook_active = False
271
+ else:
272
+ class ColorMath: # type: ignore[no-redef]
273
+ """Fallback when IPython is not installed."""
274
+
275
+ def __init__(self, *args: Any, **kwargs: Any) -> None:
276
+ raise ImportError(
277
+ "IPython is required to use ColorMath. Install it with 'pip install ipython' or 'pip install python-color-math[jupyter]'."
278
+ )
279
+
280
+ class ColorMathMagics: # type: ignore[no-redef]
281
+ pass
260
282
 
261
283
 
262
284
  def load_ipython_extension(ipython: Any) -> None:
@@ -227,6 +227,11 @@ def build_parser() -> argparse.ArgumentParser:
227
227
  const=".colormath.json",
228
228
  help="Generate a .colormath.json config template (optional target path).",
229
229
  )
230
+ style_group.add_argument(
231
+ "--open-config",
232
+ action="store_true",
233
+ help="Open configuration folder in system file manager.",
234
+ )
230
235
  style_group.add_argument(
231
236
  "--config",
232
237
  type=Path,
@@ -590,6 +595,11 @@ def _main_impl(argv: list[str] | None = None) -> int:
590
595
  sys.stdout.write(f"Created configuration file: {cfg_path}\n")
591
596
  return 0
592
597
 
598
+ if args.open_config:
599
+ from .config import open_config_folder
600
+ open_config_folder(args.config)
601
+ return 0
602
+
593
603
  # 3. Load base configuration & theme
594
604
  palette, config_options, unicode_config = load_config(args.config)
595
605
  if args.theme:
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "python-color-math"
7
- version = "0.2.16"
7
+ version = "0.2.18"
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.16
3
+ Version: 0.2.18
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
@@ -1,6 +1,8 @@
1
- """Tests for IPython and Jupyter integrations."""
2
-
3
1
  import unittest
2
+ import pytest
3
+
4
+ pytest.importorskip("IPython")
5
+
4
6
  from IPython.core.interactiveshell import InteractiveShell
5
7
  from IPython.display import Math
6
8
 
@@ -8,6 +8,9 @@ import tempfile
8
8
  import time
9
9
  import unittest
10
10
  from pathlib import Path
11
+ import pytest
12
+
13
+ pytest.importorskip("mcp")
11
14
 
12
15
  from color_math.mcp_server import create_mcp_server
13
16
 
@@ -5,6 +5,9 @@ from __future__ import annotations
5
5
  import tempfile
6
6
  import unittest
7
7
  from pathlib import Path
8
+ import pytest
9
+
10
+ pytest.importorskip("mcp")
8
11
 
9
12
  from color_math.mcp_server import create_mcp_server
10
13