manimpango 0.2.4__tar.gz → 0.2.5__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 (51) hide show
  1. ManimPango-0.2.5/.coveragerc +26 -0
  2. ManimPango-0.2.5/CODE_OF_CONDUCT.md +5 -0
  3. ManimPango-0.2.5/MANIFEST.in +7 -0
  4. {ManimPango-0.2.4 → ManimPango-0.2.5/ManimPango.egg-info}/PKG-INFO +2 -2
  5. {ManimPango-0.2.4 → ManimPango-0.2.5}/ManimPango.egg-info/SOURCES.txt +21 -1
  6. {ManimPango-0.2.4/ManimPango.egg-info → ManimPango-0.2.5}/PKG-INFO +2 -2
  7. {ManimPango-0.2.4 → ManimPango-0.2.5}/README.md +1 -1
  8. ManimPango-0.2.5/docs/RELEASE.rst +52 -0
  9. ManimPango-0.2.5/docs/_static/favicon.ico +0 -0
  10. ManimPango-0.2.5/docs/_templates/autosummary/class.rst +19 -0
  11. ManimPango-0.2.5/docs/_templates/autosummary/module.rst +50 -0
  12. ManimPango-0.2.5/docs/conf.py +85 -0
  13. ManimPango-0.2.5/docs/index.rst +16 -0
  14. ManimPango-0.2.5/docs/make.bat +35 -0
  15. ManimPango-0.2.5/docs/reference.rst +22 -0
  16. {ManimPango-0.2.4 → ManimPango-0.2.5}/manimpango/__init__.py +2 -2
  17. {ManimPango-0.2.4 → ManimPango-0.2.5}/manimpango/_version.py +1 -1
  18. {ManimPango-0.2.4 → ManimPango-0.2.5}/manimpango/cmanimpango.pyx +34 -2
  19. {ManimPango-0.2.4 → ManimPango-0.2.5}/manimpango/enums.pyx +18 -0
  20. {ManimPango-0.2.4 → ManimPango-0.2.5}/manimpango/pango.pxd +35 -0
  21. {ManimPango-0.2.4 → ManimPango-0.2.5}/manimpango/utils.py +0 -2
  22. ManimPango-0.2.5/requirements-dev.txt +5 -0
  23. {ManimPango-0.2.4 → ManimPango-0.2.5}/setup.cfg +5 -0
  24. {ManimPango-0.2.4 → ManimPango-0.2.5}/setup.py +10 -2
  25. {ManimPango-0.2.4 → ManimPango-0.2.5}/tests/__init__.py +10 -0
  26. ManimPango-0.2.5/tests/_manim.py +81 -0
  27. ManimPango-0.2.5/tests/conftest.py +10 -0
  28. ManimPango-0.2.5/tests/fonts/AdobeVFPrototype.ttf +0 -0
  29. ManimPango-0.2.5/tests/fonts/BungeeColor-Regular_colr_Windows.ttf +0 -0
  30. ManimPango-0.2.5/tests/fonts/BungeeOutline-Regular.ttf +0 -0
  31. ManimPango-0.2.5/tests/fonts/LICENSE.txt +6 -0
  32. ManimPango-0.2.5/tests/fonts/NotoNastaliqUrdu-Regular.ttf +0 -0
  33. ManimPango-0.2.5/tests/svg_tester.py +134 -0
  34. {ManimPango-0.2.4 → ManimPango-0.2.5}/tests/test_fonts.py +20 -2
  35. ManimPango-0.2.5/tests/test_markup.py +99 -0
  36. ManimPango-0.2.5/tests/test_utils.py +40 -0
  37. ManimPango-0.2.4/MANIFEST.in +0 -4
  38. ManimPango-0.2.4/tests/test_markup.py +0 -24
  39. {ManimPango-0.2.4 → ManimPango-0.2.5}/LICENSE +0 -0
  40. {ManimPango-0.2.4 → ManimPango-0.2.5}/ManimPango.egg-info/dependency_links.txt +0 -0
  41. {ManimPango-0.2.4 → ManimPango-0.2.5}/ManimPango.egg-info/not-zip-safe +0 -0
  42. {ManimPango-0.2.4 → ManimPango-0.2.5}/ManimPango.egg-info/top_level.txt +0 -0
  43. {ManimPango-0.2.4 → ManimPango-0.2.5}/manimpango/cairo.pxd +0 -0
  44. {ManimPango-0.2.4 → ManimPango-0.2.5}/manimpango/cmanimpango.pxd +0 -0
  45. {ManimPango-0.2.4 → ManimPango-0.2.5}/manimpango/glib.pxd +0 -0
  46. {ManimPango-0.2.4 → ManimPango-0.2.5}/manimpango/register_font.pxd +0 -0
  47. {ManimPango-0.2.4 → ManimPango-0.2.5}/manimpango/register_font.pyx +0 -0
  48. {ManimPango-0.2.4 → ManimPango-0.2.5}/pyproject.toml +0 -0
  49. {ManimPango-0.2.4 → ManimPango-0.2.5}/tests/test_import.py +0 -0
  50. {ManimPango-0.2.4 → ManimPango-0.2.5}/tests/test_list_fonts.py +0 -0
  51. {ManimPango-0.2.4 → ManimPango-0.2.5}/tests/test_version.py +0 -0
@@ -0,0 +1,26 @@
1
+ [run]
2
+ plugins = Cython.Coverage
3
+ omit =
4
+ packing
5
+ data_file = .coverage/data
6
+ source = manimpango
7
+
8
+ [report]
9
+ skip_empty = true
10
+ ignore_errors = true
11
+ exclude_lines =
12
+ pragma: no cover
13
+ def __repr__
14
+ if self.debug:
15
+ raise AssertionError
16
+ raise NotImplementedError
17
+ except Exception as e:
18
+
19
+ [html]
20
+ directory = .coverage/html
21
+
22
+ [xml]
23
+ output = .coverage/coverage.xml
24
+
25
+ [json]
26
+ output = .coverage/coverage.json
@@ -0,0 +1,5 @@
1
+ # Code of Conduct
2
+
3
+
4
+ If you haven't read our code of conduct, please do so at the
5
+ [manim repository](https://github.com/ManimCommunity/manim/blob/master/CODE_OF_CONDUCT.md#code-of-conduct).
@@ -0,0 +1,7 @@
1
+ global-include *.pyx *.pxd
2
+ recursive-include tests *.py *.ttf LICENSE.txt
3
+ recursive-include docs *.rst *.py make* _*/*
4
+ prune docs/_build
5
+ include *.md
6
+ include *.txt
7
+ include .coveragerc
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ManimPango
3
- Version: 0.2.4
3
+ Version: 0.2.5
4
4
  Summary: Bindings for Pango for using with Manim.
5
5
  Home-page: https://manimpango.manim.community/
6
6
  Author: Naveen M K
@@ -16,7 +16,7 @@ Description: # ManimPango
16
16
  <a href="https://pypi.org/project/manimpango/"><img src="https://img.shields.io/pypi/v/manimpango.svg?style=flat&logo=pypi" alt="PyPI Latest Release"></a>
17
17
  <a href="https://pypi.org/project/manimpango/"><img alt="PyPI - Wheel" src="https://img.shields.io/pypi/wheel/manimpango"></a>
18
18
  <a href="https://pypi.org/project/manimpango/"><img alt="PyPI - Downloads" src="https://img.shields.io/pypi/dm/manimpango"></a>
19
- <a href="http://choosealicense.com/licenses/mit/"><img alt="PyPI - License" src="https://img.shields.io/pypi/l/manimpango"></a>
19
+ <a href="https://choosealicense.com/licenses/gpl-3.0/"><img alt="PyPI - License" src="https://img.shields.io/pypi/l/manimpango"></a>
20
20
  <a href="https://pypi.org/project/manimpango/"><img alt="PyPI - Python Version" src="https://img.shields.io/pypi/pyversions/pangocffi.svg?style=flat"></a>
21
21
  <a href='https://manimpango.readthedocs.io/en/latest/?badge=latest'><img src='https://readthedocs.org/projects/manimpango/badge/?version=latest' alt='Documentation Status' /></a>
22
22
  <br>
@@ -1,7 +1,10 @@
1
+ .coveragerc
2
+ CODE_OF_CONDUCT.md
1
3
  LICENSE
2
4
  MANIFEST.in
3
5
  README.md
4
6
  pyproject.toml
7
+ requirements-dev.txt
5
8
  setup.cfg
6
9
  setup.py
7
10
  ManimPango.egg-info/PKG-INFO
@@ -9,6 +12,14 @@ ManimPango.egg-info/SOURCES.txt
9
12
  ManimPango.egg-info/dependency_links.txt
10
13
  ManimPango.egg-info/not-zip-safe
11
14
  ManimPango.egg-info/top_level.txt
15
+ docs/RELEASE.rst
16
+ docs/conf.py
17
+ docs/index.rst
18
+ docs/make.bat
19
+ docs/reference.rst
20
+ docs/_static/favicon.ico
21
+ docs/_templates/autosummary/class.rst
22
+ docs/_templates/autosummary/module.rst
12
23
  manimpango/__init__.py
13
24
  manimpango/_version.py
14
25
  manimpango/cairo.pxd
@@ -21,8 +32,17 @@ manimpango/register_font.pxd
21
32
  manimpango/register_font.pyx
22
33
  manimpango/utils.py
23
34
  tests/__init__.py
35
+ tests/_manim.py
36
+ tests/conftest.py
37
+ tests/svg_tester.py
24
38
  tests/test_fonts.py
25
39
  tests/test_import.py
26
40
  tests/test_list_fonts.py
27
41
  tests/test_markup.py
28
- tests/test_version.py
42
+ tests/test_utils.py
43
+ tests/test_version.py
44
+ tests/fonts/AdobeVFPrototype.ttf
45
+ tests/fonts/BungeeColor-Regular_colr_Windows.ttf
46
+ tests/fonts/BungeeOutline-Regular.ttf
47
+ tests/fonts/LICENSE.txt
48
+ tests/fonts/NotoNastaliqUrdu-Regular.ttf
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ManimPango
3
- Version: 0.2.4
3
+ Version: 0.2.5
4
4
  Summary: Bindings for Pango for using with Manim.
5
5
  Home-page: https://manimpango.manim.community/
6
6
  Author: Naveen M K
@@ -16,7 +16,7 @@ Description: # ManimPango
16
16
  <a href="https://pypi.org/project/manimpango/"><img src="https://img.shields.io/pypi/v/manimpango.svg?style=flat&logo=pypi" alt="PyPI Latest Release"></a>
17
17
  <a href="https://pypi.org/project/manimpango/"><img alt="PyPI - Wheel" src="https://img.shields.io/pypi/wheel/manimpango"></a>
18
18
  <a href="https://pypi.org/project/manimpango/"><img alt="PyPI - Downloads" src="https://img.shields.io/pypi/dm/manimpango"></a>
19
- <a href="http://choosealicense.com/licenses/mit/"><img alt="PyPI - License" src="https://img.shields.io/pypi/l/manimpango"></a>
19
+ <a href="https://choosealicense.com/licenses/gpl-3.0/"><img alt="PyPI - License" src="https://img.shields.io/pypi/l/manimpango"></a>
20
20
  <a href="https://pypi.org/project/manimpango/"><img alt="PyPI - Python Version" src="https://img.shields.io/pypi/pyversions/pangocffi.svg?style=flat"></a>
21
21
  <a href='https://manimpango.readthedocs.io/en/latest/?badge=latest'><img src='https://readthedocs.org/projects/manimpango/badge/?version=latest' alt='Documentation Status' /></a>
22
22
  <br>
@@ -4,7 +4,7 @@
4
4
  <a href="https://pypi.org/project/manimpango/"><img src="https://img.shields.io/pypi/v/manimpango.svg?style=flat&logo=pypi" alt="PyPI Latest Release"></a>
5
5
  <a href="https://pypi.org/project/manimpango/"><img alt="PyPI - Wheel" src="https://img.shields.io/pypi/wheel/manimpango"></a>
6
6
  <a href="https://pypi.org/project/manimpango/"><img alt="PyPI - Downloads" src="https://img.shields.io/pypi/dm/manimpango"></a>
7
- <a href="http://choosealicense.com/licenses/mit/"><img alt="PyPI - License" src="https://img.shields.io/pypi/l/manimpango"></a>
7
+ <a href="https://choosealicense.com/licenses/gpl-3.0/"><img alt="PyPI - License" src="https://img.shields.io/pypi/l/manimpango"></a>
8
8
  <a href="https://pypi.org/project/manimpango/"><img alt="PyPI - Python Version" src="https://img.shields.io/pypi/pyversions/pangocffi.svg?style=flat"></a>
9
9
  <a href='https://manimpango.readthedocs.io/en/latest/?badge=latest'><img src='https://readthedocs.org/projects/manimpango/badge/?version=latest' alt='Documentation Status' /></a>
10
10
  <br>
@@ -0,0 +1,52 @@
1
+ Release Procedure
2
+ =================
3
+
4
+ This is the **maintainer** note on how to Release.
5
+ All versioning is in accordance to
6
+ `Semantic Versioning 2.0.0 <https://semver.org/>`_.
7
+ This means older version would have a backport of bugs fixes.
8
+
9
+ 1. Check whether the test suite passes on the main branch.
10
+
11
+ 2. Revert any changes which seems to be not working, and check
12
+ for the milestone if PR are merged accordingly.
13
+
14
+ 3. Check whether the `Wheels Build`_,
15
+ against the main branch works as expected.
16
+
17
+ 4. Clone the repository locally.
18
+
19
+ 5. Bump the version in `manimpango/_version`_ accordingly.
20
+
21
+ 6. Make a commit with the changes done, as ``Release v<version here>``
22
+
23
+ 7. Create a tag, locally with
24
+
25
+ .. code-block:: sh
26
+
27
+ git tag -s v<version-number>
28
+
29
+ .. note::
30
+
31
+ Here, ``-s`` is used to sign the tag with gpg so that users
32
+ can later verify it, and a tag shouldn't be created with
33
+ signing because Github shows it unverified.
34
+ .. important::
35
+
36
+ The message should include the changelog of the release.
37
+
38
+ 8. Push the tag to remote.
39
+
40
+ 9. Go to `Github`_, and `draft a new release`_ with the same tag pushed.
41
+
42
+ 10. Check whether the CI uploads the wheels and the ``.tar.gz`` file to
43
+ PyPi.
44
+
45
+ 11. Finally, test the ``.tar.gz`` which was uploaded to `PyPi`_, and install
46
+ it in a new virtual environment.
47
+
48
+ .. _Wheels Build: https://github.com/ManimCommunity/ManimPango/actions?query=workflow%3A%22Build+Wheels%22
49
+ .. _manimpango/_version: https://github.com/ManimCommunity/ManimPango/blob/main/manimpango/_version.py
50
+ .. _Github: https://github.com
51
+ .. _draft a new release: https://docs.github.com/en/free-pro-team@latest/github/administering-a-repository/managing-releases-in-a-repository#creating-a-release
52
+ .. _PyPi: https://pypi.org/project/manimpango/
@@ -0,0 +1,19 @@
1
+ {{ fullname | escape | underline}}
2
+
3
+ .. currentmodule:: {{ module }}
4
+
5
+ .. autoclass:: {{ objname }}
6
+ :show-inheritance:
7
+ :members:
8
+
9
+ {% block methods %}
10
+ {%- if methods %}
11
+ .. rubric:: {{ _('Methods') }}
12
+
13
+ .. autosummary::
14
+ :nosignatures:
15
+ {% for item in methods if item != '__init__' and item not in inherited_members %}
16
+ ~{{ name }}.{{ item }}
17
+ {%- endfor %}
18
+ {%- endif %}
19
+ {%- endblock %}
@@ -0,0 +1,50 @@
1
+ {{ fullname | escape | underline }}
2
+
3
+ .. currentmodule:: {{ fullname }}
4
+
5
+ .. automodule:: {{ fullname }}
6
+
7
+ {% block attributes %}
8
+ {% if attributes %}
9
+ .. rubric:: Module Attributes
10
+
11
+ .. autosummary::
12
+ {% for item in attributes %}
13
+ {{ item }}
14
+ {%- endfor %}
15
+ {% endif %}
16
+ {% endblock %}
17
+
18
+ {% block classes %}
19
+ {% if classes %}
20
+ .. rubric:: Classes
21
+
22
+ .. autosummary::
23
+ :toctree: .
24
+ :nosignatures:
25
+ {% for class in classes %}
26
+ {{ class }}
27
+ {% endfor %}
28
+ {% endif %}
29
+ {% endblock %}
30
+
31
+ {% block functions %}
32
+ {% if functions %}
33
+ .. rubric:: {{ _('Functions') }}
34
+
35
+ {% for item in functions %}
36
+ .. autofunction:: {{ item }}
37
+ {%- endfor %}
38
+ {% endif %}
39
+ {% endblock %}
40
+
41
+ {% block exceptions %}
42
+ {% if exceptions %}
43
+ .. rubric:: {{ _('Exceptions') }}
44
+
45
+ .. autosummary::
46
+ {% for item in exceptions %}
47
+ {{ item }}
48
+ {%- endfor %}
49
+ {% endif %}
50
+ {% endblock %}
@@ -0,0 +1,85 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Configuration file for the Sphinx documentation builder.
3
+ #
4
+ # This file only contains a selection of the most common options. For a full
5
+ # list see the documentation:
6
+ # https://www.sphinx-doc.org/en/master/usage/configuration.html
7
+
8
+ # -- Path setup --------------------------------------------------------------
9
+
10
+ # If extensions (or modules to document with autodoc) are in another directory,
11
+ # add these directories to sys.path here. If the directory is relative to the
12
+ # documentation root, use os.path.abspath to make it absolute, like shown here.
13
+ #
14
+ # import os
15
+ # import sys
16
+ # sys.path.insert(0, os.path.abspath(".."))
17
+
18
+
19
+ from pathlib import Path
20
+
21
+ # -- Project information -----------------------------------------------------
22
+ from pkg_resources import get_distribution
23
+
24
+ project = "ManimPango"
25
+ copyright = "2021, The Manim Community Dev Team"
26
+ author = "The Manim Community Dev Team"
27
+
28
+ release = get_distribution("ManimPango").version
29
+ version = ".".join(release.split(".")[:2])
30
+
31
+
32
+ # -- General configuration ---------------------------------------------------
33
+
34
+ # Add any Sphinx extension module names here, as strings. They can be
35
+ # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
36
+ # ones.
37
+ extensions = [
38
+ "sphinx.ext.autodoc",
39
+ "sphinx.ext.napoleon",
40
+ "sphinx.ext.autosummary",
41
+ "sphinx.ext.doctest",
42
+ "sphinx.ext.extlinks",
43
+ "sphinx.ext.intersphinx",
44
+ "sphinxext.opengraph",
45
+ ]
46
+
47
+ # Add any paths that contain templates here, relative to this directory.
48
+ templates_path = ["_templates"]
49
+
50
+ # List of patterns, relative to source directory, that match files and
51
+ # directories to ignore when looking for source files.
52
+ # This pattern also affects html_static_path and html_extra_path.
53
+ exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]
54
+
55
+
56
+ # -- Options for HTML output -------------------------------------------------
57
+
58
+ # The theme to use for HTML and HTML Help pages. See the documentation for
59
+ # a list of builtin themes.
60
+ #
61
+ html_theme = "furo"
62
+
63
+ # Add any paths that contain custom static files (such as style sheets) here,
64
+ # relative to this directory. They are copied after the builtin static files,
65
+ # so a file named "default.css" will overwrite the builtin "default.css".
66
+ html_static_path = ["_static"]
67
+ html_favicon = str(Path("_static/favicon.ico"))
68
+ autosummary_generate = True
69
+
70
+ # generate documentation from type hints
71
+ autodoc_typehints = "description"
72
+ autoclass_content = "both"
73
+
74
+ # controls whether functions documented by the autofunction directive
75
+ # appear with their full module names
76
+ add_module_names = False
77
+
78
+ intersphinx_mapping = {
79
+ "manim": ("https://docs.manim.community/en/v0.2.0", None),
80
+ "python": ("https://docs.python.org/3", None),
81
+ }
82
+
83
+ ogp_image = "https://www.manim.community/logo.png"
84
+ ogp_site_name = "Manim Pango | Documentation"
85
+ ogp_site_url = "https://manimpango.manim.community/"
@@ -0,0 +1,16 @@
1
+ ManimPango's documentation!
2
+ ===========================
3
+
4
+ .. toctree::
5
+ :maxdepth: 2
6
+ :caption: Contents:
7
+
8
+ reference
9
+ RELEASE
10
+
11
+ Indices and tables
12
+ ==================
13
+
14
+ * :ref:`genindex`
15
+ * :ref:`modindex`
16
+ * :ref:`search`
@@ -0,0 +1,35 @@
1
+ @ECHO OFF
2
+
3
+ pushd %~dp0
4
+
5
+ REM Command file for Sphinx documentation
6
+
7
+ if "%SPHINXBUILD%" == "" (
8
+ set SPHINXBUILD=sphinx-build
9
+ )
10
+ set SOURCEDIR=.
11
+ set BUILDDIR=_build
12
+
13
+ if "%1" == "" goto help
14
+
15
+ %SPHINXBUILD% >NUL 2>NUL
16
+ if errorlevel 9009 (
17
+ echo.
18
+ echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
19
+ echo.installed, then set the SPHINXBUILD environment variable to point
20
+ echo.to the full path of the 'sphinx-build' executable. Alternatively you
21
+ echo.may add the Sphinx directory to PATH.
22
+ echo.
23
+ echo.If you don't have Sphinx installed, grab it from
24
+ echo.http://sphinx-doc.org/
25
+ exit /b 1
26
+ )
27
+
28
+ %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
29
+ goto end
30
+
31
+ :help
32
+ %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
33
+
34
+ :end
35
+ popd
@@ -0,0 +1,22 @@
1
+ Manimpango Reference
2
+ ====================
3
+
4
+ .. autosummary::
5
+ :toctree: reference
6
+
7
+ manimpango.TextSetting
8
+ manimpango.PangoUtils
9
+ manimpango.text2svg
10
+ manimpango.MarkupUtils
11
+ manimpango.register_font
12
+ manimpango.unregister_font
13
+ manimpango.list_fonts
14
+
15
+ Enums
16
+ =====
17
+ .. autosummary::
18
+ :toctree: reference
19
+
20
+ manimpango.Style
21
+ manimpango.Weight
22
+ manimpango.Variant
@@ -3,7 +3,7 @@ import os
3
3
 
4
4
  from ._version import __version__ # noqa: F403,F401
5
5
 
6
- if os.name == "nt":
6
+ if os.name == "nt": # pragma: no cover
7
7
  os.environ["PATH"] = (
8
8
  f"{os.path.abspath(os.path.dirname(__file__))}"
9
9
  f"{os.pathsep}"
@@ -13,5 +13,5 @@ try:
13
13
  from .cmanimpango import * # noqa: F403,F401
14
14
  from .enums import * # noqa: F403,F401
15
15
  from .register_font import * # noqa: F403,F401
16
- except ImportError:
16
+ except ImportError: # pragma: no cover
17
17
  raise ImportError("Couldn't load the necessary Shared Libraries.")
@@ -1,2 +1,2 @@
1
1
  # -*- coding: utf-8 -*-
2
- __version__ = "0.2.4"
2
+ __version__ = "0.2.5"
@@ -1,5 +1,7 @@
1
1
  from xml.sax.saxutils import escape
2
2
  from .utils import *
3
+ from .enums import Alignment
4
+ import warnings
3
5
 
4
6
  class TextSetting:
5
7
  """Formatting for slices of a :class:`manim.mobject.svg.text_mobject.Text` object."""
@@ -138,13 +140,18 @@ class MarkupUtils:
138
140
  slant: str,
139
141
  weight: str,
140
142
  size: int,
141
- line_spacing: int,
143
+ _: int, # for some there was a keyword here.
142
144
  disable_liga: bool,
143
145
  file_name: str,
144
146
  START_X: int,
145
147
  START_Y: int,
146
148
  width: int,
147
149
  height: int,
150
+ *, # keyword only arguments below
151
+ justify: bool = None,
152
+ indent: float = None,
153
+ line_spacing: float = None,
154
+ alignment: Alignment = None
148
155
  ) -> int:
149
156
  """Render an SVG file from a :class:`manim.mobject.svg.text_mobject.MarkupText` object."""
150
157
  cdef cairo_surface_t* surface
@@ -152,8 +159,9 @@ class MarkupUtils:
152
159
  cdef PangoFontDescription* font_desc
153
160
  cdef PangoLayout* layout
154
161
  cdef cairo_status_t status
155
- cdef double width_layout = width
162
+ cdef double width_layout = width - 50
156
163
  cdef double font_size = size
164
+ cdef int temp_int # a temporary C integer for conversion
157
165
 
158
166
  file_name_bytes = file_name.encode("utf-8")
159
167
 
@@ -182,8 +190,32 @@ class MarkupUtils:
182
190
  cairo_destroy(context)
183
191
  cairo_surface_destroy(surface)
184
192
  raise MemoryError("Pango.Layout can't be created from Cairo Context.")
193
+
185
194
  pango_layout_set_width(layout, pango_units_from_double(width_layout))
186
195
 
196
+ if justify:
197
+ pango_layout_set_justify(layout, justify)
198
+
199
+ if indent:
200
+ temp_int = pango_units_from_double(indent)
201
+ pango_layout_set_indent(layout, temp_int)
202
+
203
+ if line_spacing:
204
+ # Typical values are: 0, 1, 1.5, 2.
205
+ ret = set_line_width(layout, line_spacing)
206
+ if not ret:
207
+ # warn that line spacing don't work
208
+ # because of old Pango version they
209
+ # have
210
+ warnings.warn(
211
+ "Pango Version<1.44 found."
212
+ "Impossible to set line_spacing."
213
+ "Expect Ugly Output."
214
+ )
215
+
216
+ if alignment:
217
+ pango_layout_set_alignment(layout, alignment.value)
218
+
187
219
  font_desc = pango_font_description_new()
188
220
  if font_desc==NULL:
189
221
  cairo_destroy(context)
@@ -90,3 +90,21 @@ class Variant(Enum):
90
90
  """
91
91
  NORMAL = PANGO_VARIANT_NORMAL
92
92
  SMALL_CAPS = PANGO_VARIANT_SMALL_CAPS
93
+
94
+ class Alignment(Enum):
95
+ """
96
+ An enumeration specifying alignment.
97
+
98
+ Attributes
99
+ ----------
100
+
101
+ NORMAL :
102
+ A normal font.
103
+
104
+ SMALL_CAPS :
105
+ A font with the lower case characters replaced by smaller variants
106
+ of the capital characters.
107
+ """
108
+ LEFT = PANGO_ALIGN_LEFT
109
+ CENTER = PANGO_ALIGN_CENTER
110
+ RIGHT = PANGO_ALIGN_RIGHT
@@ -37,6 +37,10 @@ cdef extern from "pango/pangocairo.h":
37
37
  PANGO_WRAP_WORD
38
38
  PANGO_WRAP_CHAR
39
39
  PANGO_WRAP_WORD_CHAR
40
+ ctypedef enum PangoAlignment:
41
+ PANGO_ALIGN_LEFT
42
+ PANGO_ALIGN_CENTER
43
+ PANGO_ALIGN_RIGHT
40
44
  PangoLayout* pango_cairo_create_layout(cairo_t* cr)
41
45
  void pango_cairo_show_layout(
42
46
  cairo_t* cr,
@@ -121,3 +125,34 @@ cdef extern from "pango/pangocairo.h":
121
125
  const char* pango_font_family_get_name(
122
126
  PangoFontFamily *family
123
127
  )
128
+ void pango_layout_set_justify(
129
+ PangoLayout *layout,
130
+ gboolean justify
131
+ )
132
+ void pango_layout_set_indent(
133
+ PangoLayout *layout,
134
+ int indent
135
+ )
136
+ void pango_layout_set_alignment(
137
+ PangoLayout *layout,
138
+ PangoAlignment alignment
139
+ )
140
+
141
+ cdef extern from *:
142
+ """
143
+ #if PANGO_VERSION_CHECK(1,44,0)
144
+ int set_line_width(PangoLayout *layout,float spacing)
145
+ {
146
+ pango_layout_set_line_spacing(layout, spacing);
147
+ return 1;
148
+ }
149
+ #else
150
+ int set_line_width(PangoLayout *layout,float spacing){return 0;}
151
+ #endif
152
+ """
153
+ # The above docs string is C which is used to
154
+ # check for the Pango Version there at run time.
155
+ # pango_layout_set_line_spacing is only avaiable only for
156
+ # pango>=1.44.0 but we support pango>=1.30.0 that why this
157
+ # conditionals.
158
+ bint set_line_width(PangoLayout *layout,float spacing)
@@ -30,8 +30,6 @@ class PangoUtils:
30
30
  return Weight.ULTRALIGHT
31
31
  elif string == "LIGHT":
32
32
  return Weight.LIGHT
33
- elif string == "SEMILIGHT":
34
- return Weight.SEMILIGHT
35
33
  elif string == "BOOK":
36
34
  return Weight.BOOK
37
35
  elif string == "MEDIUM":
@@ -0,0 +1,5 @@
1
+ pytest-cov
2
+ pytest
3
+ Cython
4
+ coverage
5
+ manim>0.2.0
@@ -6,6 +6,11 @@ license_files =
6
6
  [flake8]
7
7
  max-line-length = 88
8
8
 
9
+ [tool:pytest]
10
+ testpaths =
11
+ tests
12
+ addopts = --cov --no-cov-on-fail --basetemp=.pytest_temp
13
+
9
14
  [egg_info]
10
15
  tag_build =
11
16
  tag_date = 0
@@ -19,6 +19,11 @@ try:
19
19
  except ImportError:
20
20
  USE_CYTHON = False
21
21
 
22
+ coverage = False
23
+ if sys.argv[-1] == "--coverage":
24
+ coverage = True
25
+ sys.argv.pop()
26
+
22
27
 
23
28
  def get_version():
24
29
  version_file = "manimpango/_version.py"
@@ -166,7 +171,6 @@ class PKG_CONFIG:
166
171
  known_cflags, unknown_cflags = self.parse_cflags(raw_cflags.decode("utf8"))
167
172
  if unknown_cflags:
168
173
  known_cflags["extra_compile_args"] = unknown_cflags.split()
169
- # return update_dict(known_cflags, known_libs)
170
174
  return known_cflags
171
175
  return dict()
172
176
 
@@ -197,6 +201,9 @@ if sys.platform == "win32":
197
201
  returns["define_macros"] += [("UNICODE", 1)]
198
202
  else:
199
203
  returns["define_macros"] = [("UNICODE", 1)]
204
+ if coverage:
205
+ returns["define_macros"] += [("CYTHON_TRACE", 1)]
206
+ returns["define_macros"] += [("CYTHON_TRACE_NOGIL", 1)]
200
207
 
201
208
  ext_modules = [
202
209
  Extension(
@@ -221,6 +228,7 @@ if USE_CYTHON:
221
228
  language_level=3,
222
229
  include_path=["manimpango"],
223
230
  gdb_debug=DEBUG,
231
+ compiler_directives={"linetrace": coverage},
224
232
  )
225
233
  with open("README.md") as fh:
226
234
  long_description = fh.read()
@@ -259,6 +267,6 @@ setup(
259
267
  },
260
268
  ext_modules=ext_modules,
261
269
  package_data={
262
- "manimpango": ["*.pxd"],
270
+ "manimpango": ["*.pxd", "*.pyx"],
263
271
  },
264
272
  )
@@ -29,3 +29,13 @@ def delete_media_dir():
29
29
 
30
30
  set_dll_search_path()
31
31
  delete_media_dir()
32
+ CASES_DIR = Path(Path(__file__).parent, "cases").absolute()
33
+ FONT_DIR = Path(__file__).parent / "fonts"
34
+
35
+ import manimpango # noqa: E402
36
+
37
+ font = str((FONT_DIR / "BungeeOutline-Regular.ttf").absolute())
38
+ orig = manimpango.list_fonts()
39
+ assert manimpango.register_font(font)
40
+ final = manimpango.list_fonts()
41
+ main_font = list(set(final) - set(orig))[0]
@@ -0,0 +1,81 @@
1
+ # -*- coding: utf-8 -*-
2
+ """This file contains helpers for the tests copied and modified
3
+ from Manim.
4
+ """
5
+
6
+ import os
7
+ from pathlib import Path
8
+
9
+ from manimpango import Alignment, MarkupUtils
10
+
11
+
12
+ class MarkupText:
13
+ def __init__(
14
+ self,
15
+ text: str,
16
+ *,
17
+ size: int = 1,
18
+ line_spacing: int = None,
19
+ font: str = None,
20
+ slant: str = "NORMAL",
21
+ weight: str = "NORMAL",
22
+ tab_width: int = 4,
23
+ disable_ligatures: bool = False,
24
+ justify: bool = None,
25
+ indent: float = None,
26
+ alignment: Alignment = None,
27
+ # for the tests
28
+ filename: str = "test.svg",
29
+ **kwargs,
30
+ ):
31
+ self.text = text
32
+ self.size = size
33
+ self.line_spacing = line_spacing
34
+ self.font = font
35
+ self.slant = slant
36
+ self.weight = weight
37
+ self.tab_width = tab_width
38
+ self.filename = filename
39
+ self.original_text = text
40
+ self.disable_ligatures = disable_ligatures
41
+
42
+ self.justify = justify
43
+ self.indent = indent
44
+ self.alignment = alignment
45
+ if not MarkupUtils.validate(self.text):
46
+ raise ValueError(
47
+ f"Pango cannot parse your markup in {self.text}. "
48
+ "Please check for typos, unmatched tags or unescaped "
49
+ "special chars like < and &."
50
+ )
51
+ self.text2svg()
52
+
53
+ def text2svg(self):
54
+ """Convert the text to SVG using Pango."""
55
+ size = self.size * 10
56
+ dir_name = Path(self.filename).parent
57
+ disable_liga = self.disable_ligatures
58
+ if not os.path.exists(dir_name):
59
+ os.makedirs(dir_name)
60
+ file_name = self.filename
61
+ return MarkupUtils.text2svg(
62
+ f"{self.text}",
63
+ self.font,
64
+ self.slant,
65
+ self.weight,
66
+ size,
67
+ True, # stray positional argument
68
+ disable_liga,
69
+ file_name,
70
+ 20,
71
+ 20,
72
+ 600, # width
73
+ 400, # height
74
+ justify=self.justify,
75
+ indent=self.indent,
76
+ line_spacing=self.line_spacing,
77
+ alignment=self.alignment,
78
+ )
79
+
80
+ def __repr__(self):
81
+ return f"MarkupText({repr(self.original_text)})"
@@ -0,0 +1,10 @@
1
+ # -*- coding: utf-8 -*-
2
+ import manimpango
3
+
4
+
5
+ def pytest_report_header(config):
6
+ return (
7
+ f"ManimPango version {manimpango.__version__}\n"
8
+ f"Pango version {manimpango.pango_version()}\n"
9
+ f"Cairo version {manimpango.cairo_version()}"
10
+ )
@@ -0,0 +1,6 @@
1
+ NotoNastaliqUrdu-Regular.ttf from https://github.com/googlei18n/noto-fonts
2
+ BungeeColor-Regular_colr_Windows.ttf, from https://github.com/djrrb/bungee
3
+ AdobeVFPrototype.ttf, from https://github.com/adobe-fonts/adobe-variable-font-prototype
4
+ BungeeOutline-Regular.ttf, from https://fonts.google.com/specimen/Bungee+Outline
5
+
6
+ All of the above fonts are published under the SIL Open Font License (OFL) v1.1 (http://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=OFL), which allows you to copy, modify, and redistribute them if you need to.
@@ -0,0 +1,134 @@
1
+ # -*- coding: utf-8 -*-
2
+ from pathlib import Path
3
+ from typing import Dict
4
+ from xml.parsers.expat import ParserCreate
5
+
6
+
7
+ class SVGUtils:
8
+ SVG_DEFAULT_ATTRIBUTES: Dict[str, str] = {
9
+ "fill": "black",
10
+ "fill-opacity": "1",
11
+ "stroke": "none",
12
+ "stroke-opacity": "1",
13
+ }
14
+
15
+ def __init__(self) -> None:
16
+ pass
17
+
18
+ def parse_color_string(self, color_spec: str) -> str:
19
+ # copied from Manim's SVG parser.
20
+ if color_spec[0:3] == "rgb":
21
+ # these are only in integer form,
22
+ # but the Colour module wants them in floats.
23
+ splits = color_spec[4:-1].split(",")
24
+ if splits[0][-1] == "%":
25
+ # if the last character of the first number is a percentage,
26
+ # then interpret the number as a percentage
27
+ parsed_rgbs = [float(i[:-1]) / 100.0 for i in splits]
28
+ else:
29
+ parsed_rgbs = [int(i) / 255.0 for i in splits]
30
+
31
+ # hex_color = rgb_to_hex(parsed_rgbs)
32
+
33
+ else:
34
+ # not necessary for web2hex case and hex
35
+ raise NotImplementedError
36
+
37
+ return parsed_rgbs
38
+
39
+ def str2styledict(self, style_specs: str) -> Dict[str, str]:
40
+ # helper for parse style
41
+ # copied from manim's svg parser.
42
+ style = {}
43
+
44
+ # the style attribute should be handled separately in order to
45
+ # break it up nicely. furthermore, style takes priority over other
46
+ # attributes in the same element.
47
+ if style_specs:
48
+ for style_spec in style_specs.split(";"):
49
+ try:
50
+ key, value = style_spec.split(":")
51
+ except ValueError as e:
52
+ if not style_spec:
53
+ # there was just a stray semicolon
54
+ # at the end, producing an
55
+ # emptystring
56
+ pass
57
+ else:
58
+ raise e
59
+ else:
60
+ style[key] = value
61
+
62
+ return style
63
+
64
+ def parse_style(self, stylestr: str) -> Dict:
65
+ # Originally written by @MrMallIronmaker
66
+ # Copied from Manim.
67
+ # https://github.com/ManimCommunity/manim/
68
+ # blob/aa873e0f8e5c4f35c864568213b04b88af5b4769/manim/mobject/svg/style_utils.py#L143
69
+ SVG_DEFAULT_ATTRIBUTES = self.SVG_DEFAULT_ATTRIBUTES
70
+ manim_style = {}
71
+ svg_style = self.str2styledict(stylestr)
72
+ for key in SVG_DEFAULT_ATTRIBUTES:
73
+ if key not in svg_style:
74
+ svg_style[key] = SVG_DEFAULT_ATTRIBUTES[key]
75
+
76
+ if "fill-opacity" in svg_style:
77
+ manim_style["fill_opacity"] = float(svg_style["fill-opacity"])
78
+
79
+ if "stroke-opacity" in svg_style:
80
+ manim_style["stroke_opacity"] = float(svg_style["stroke-opacity"])
81
+
82
+ # nones need to be handled specially
83
+ if "fill" in svg_style:
84
+ if svg_style["fill"] == "none":
85
+ manim_style["fill_opacity"] = 0
86
+ else:
87
+ manim_style["fill_color"] = self.parse_color_string(svg_style["fill"])
88
+
89
+ if "stroke" in svg_style:
90
+ if svg_style["stroke"] == "none":
91
+ # In order to not break animations.creation.Write,
92
+ # we interpret no stroke as stroke-width of zero and
93
+ # color the same as the fill color, if it exists.
94
+ manim_style["stroke_width"] = 0
95
+ if "fill_color" in manim_style:
96
+ manim_style["stroke_color"] = manim_style["fill_color"]
97
+ else:
98
+ manim_style["stroke_color"] = self.parse_color_string(
99
+ svg_style["stroke"]
100
+ )
101
+
102
+ return manim_style
103
+
104
+
105
+ class SVGStyleTester(SVGUtils):
106
+ def __init__(self, gotSVG: Path, expectedSVG: Path) -> None:
107
+ self.expected_file = expectedSVG
108
+ self.got_file = gotSVG
109
+ self.prepare()
110
+
111
+ def get_handler(self, final_setter):
112
+ def func(name, attrs):
113
+ styles = []
114
+ if name == "g":
115
+ if "style" in attrs:
116
+ styles.append(self.parse_style(attrs["style"]))
117
+ if styles:
118
+ # need to think of better way than this.
119
+ exec(f"self.{final_setter} += [styles]")
120
+
121
+ return func
122
+
123
+ def prepare(self):
124
+ self.got_svg_style = []
125
+ self.expected_svg_style = []
126
+ got_parser = ParserCreate()
127
+ got_parser.StartElementHandler = self.get_handler("got_svg_style")
128
+ with open(self.got_file, "rb") as f:
129
+ got_parser.ParseFile(f)
130
+
131
+ expected_parser = ParserCreate()
132
+ expected_parser.StartElementHandler = self.get_handler("expected_svg_style")
133
+ with open(self.expected_file, "rb") as f:
134
+ expected_parser.ParseFile(f)
@@ -8,7 +8,9 @@ import pytest
8
8
 
9
9
  import manimpango
10
10
 
11
- FONT_DIR = Path(__file__).parent / "fonts"
11
+ from . import FONT_DIR, main_font
12
+ from ._manim import MarkupText
13
+
12
14
  font_lists = {
13
15
  (FONT_DIR / "AdobeVFPrototype.ttf").absolute(): "Adobe Variable Font Prototype",
14
16
  (
@@ -76,4 +78,20 @@ def test_fail_just_unregister():
76
78
  )
77
79
  @pytest.mark.skipif(sys.platform.startswith("darwin"), reason="unsupported api for mac")
78
80
  def test_unregister_linux():
79
- manimpango.unregister_font("random")
81
+ assert manimpango.unregister_font("random")
82
+
83
+
84
+ @pytest.mark.skipif(
85
+ sys.platform.startswith("linux"), reason="unsupported api for linux"
86
+ )
87
+ def test_adding_dummy_font(tmpdir):
88
+ dummy = tmpdir / "font.ttf"
89
+ with open(dummy, "wb") as f:
90
+ f.write(b"dummy")
91
+ assert not manimpango.register_font(str(dummy)), "Registered a dummy font?"
92
+
93
+
94
+ def test_fonts_render(tmpdir):
95
+ filename = str(Path(tmpdir) / "hello.svg")
96
+ MarkupText("Hello World", font=main_font, filename=filename)
97
+ assert Path(filename).exists()
@@ -0,0 +1,99 @@
1
+ # -*- coding: utf-8 -*-
2
+ from pathlib import Path
3
+
4
+ import manimpango
5
+
6
+ from . import CASES_DIR
7
+ from ._manim import MarkupText
8
+ from .svg_tester import SVGStyleTester
9
+
10
+ ipsum_text = (
11
+ "<b>Lorem ipsum dolor</b> sit amet, <i>consectetur</i> adipiscing elit,"
12
+ "sed do eiusmod tempor incididunt ut labore et dolore"
13
+ "magna aliqua. Ut enim <b>ad</b> minim veniam, quis nostrud"
14
+ "exercitation ullamco laboris nisi ut aliquip"
15
+ "ex ea commodo consequat. Duis aute irure dolor"
16
+ "in reprehenderit in voluptate velit esse cillum"
17
+ "dolore eu fugiat nulla pariatur. Excepteur sint"
18
+ "occaecat cupidatat non proident, sunt in culpa qui"
19
+ "officia deserunt mollit anim id est laborum."
20
+ )
21
+
22
+
23
+ def test_good_markup():
24
+
25
+ assert manimpango.MarkupUtils.validate(
26
+ "foo",
27
+ ), '"foo" should not fail validation'
28
+ assert manimpango.MarkupUtils.validate(
29
+ "<b>bar</b>"
30
+ ), '"<b>bar</b>" should not fail validation'
31
+ assert manimpango.MarkupUtils.validate(
32
+ "வணக்கம்",
33
+ ), '"வணக்கம்" should not fail'
34
+
35
+
36
+ def test_bad_markup():
37
+
38
+ assert not manimpango.MarkupUtils.validate(
39
+ "<b>foo"
40
+ ), '"<b>foo" should fail validation (unbalanced tags)'
41
+ assert not manimpango.MarkupUtils.validate(
42
+ "<xyz>foo</xyz>"
43
+ ), '"<xyz>foo</xyz>" should fail validation (invalid tag)'
44
+
45
+
46
+ def test_markup_text(tmpdir):
47
+ loc = Path(tmpdir, "test.svg")
48
+ assert not loc.exists()
49
+ MarkupText(
50
+ '<span underline="error"><b><i>Hello Manim</i></b></span>', filename=str(loc)
51
+ )
52
+ assert loc.exists()
53
+
54
+
55
+ def test_markup_justify(tmpdir):
56
+ # don't know how to verify this correctly
57
+ # it varies upon diffent system so, we are
58
+ # just check whether it runs
59
+ loc = Path(tmpdir, "test.svg")
60
+ assert not loc.exists()
61
+ MarkupText(ipsum_text, justify=True, filename=str(loc))
62
+ assert loc.exists()
63
+
64
+
65
+ def test_markup_indent(tmpdir):
66
+ # don't know how to verify this correctly
67
+ # it varies upon diffent system so, we are
68
+ # just check whether it runs
69
+ loc = Path(tmpdir, "test.svg")
70
+ assert not loc.exists()
71
+ MarkupText(ipsum_text, indent=10, filename=str(loc))
72
+ assert loc.exists()
73
+
74
+
75
+ def test_markup_alignment(tmpdir):
76
+ # don't know how to verify this correctly
77
+ # it varies upon diffent system so, we are
78
+ # just check whether it runs
79
+ loc = Path(tmpdir, "test.svg")
80
+ assert not loc.exists()
81
+ MarkupText(
82
+ ipsum_text,
83
+ alignment=manimpango.Alignment.CENTER,
84
+ filename=str(loc),
85
+ )
86
+ assert loc.exists()
87
+
88
+
89
+ def test_markup_style(tmpdir):
90
+ test_case = CASES_DIR / "hello_blue_world_green.svg"
91
+ expected = tmpdir / "expected.svg"
92
+ text = "<span foreground='BLUE'>Hello</span>\n<span foreground='GREEN'>World</span>"
93
+ MarkupText(
94
+ text,
95
+ filename=str(expected),
96
+ )
97
+ s = SVGStyleTester(gotSVG=expected, expectedSVG=test_case)
98
+ assert len(s.got_svg_style) == len(s.expected_svg_style)
99
+ assert s.got_svg_style == s.expected_svg_style
@@ -0,0 +1,40 @@
1
+ # -*- coding: utf-8 -*-
2
+ import pytest
3
+
4
+ from manimpango.enums import Style, Weight
5
+ from manimpango.utils import PangoUtils
6
+
7
+
8
+ def test_str2style():
9
+ p = PangoUtils()
10
+
11
+ assert p.str2style("NORMAL") == Style.NORMAL
12
+ assert p.str2style("ITALIC") == Style.ITALIC
13
+ assert p.str2style("OBLIQUE") == Style.OBLIQUE
14
+
15
+ with pytest.raises(AttributeError) as exc_info:
16
+ p.str2style("DNE")
17
+ exception_raised = exc_info.value
18
+ assert "There is no Style Called DNE" == str(exception_raised)
19
+
20
+
21
+ def test_str2weight():
22
+ p = PangoUtils()
23
+
24
+ assert p.str2weight("NORMAL") == Weight.NORMAL
25
+ assert p.str2weight("BOLD") == Weight.BOLD
26
+ assert p.str2weight("THIN") == Weight.THIN
27
+ assert p.str2weight("THIN") == Weight.THIN
28
+ assert p.str2weight("ULTRALIGHT") == Weight.ULTRALIGHT
29
+ assert p.str2weight("LIGHT") == Weight.LIGHT
30
+ assert p.str2weight("BOOK") == Weight.BOOK
31
+ assert p.str2weight("MEDIUM") == Weight.MEDIUM
32
+ assert p.str2weight("SEMIBOLD") == Weight.SEMIBOLD
33
+ assert p.str2weight("ULTRABOLD") == Weight.ULTRABOLD
34
+ assert p.str2weight("HEAVY") == Weight.HEAVY
35
+ assert p.str2weight("ULTRAHEAVY") == Weight.ULTRAHEAVY
36
+
37
+ with pytest.raises(AttributeError) as exc_info:
38
+ p.str2weight("DNE")
39
+ exception_raised = exc_info.value
40
+ assert "There is no Font Weight Called DNE" == str(exception_raised)
@@ -1,4 +0,0 @@
1
- global-include *.pyx
2
- recursive-include tests *.py
3
- prune docs/_build
4
- recursive-include docs
@@ -1,24 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
- def test_good_markup():
3
- import manimpango # noqa: F401
4
-
5
- assert manimpango.MarkupUtils.validate(
6
- "foo",
7
- ), '"foo" should not fail validation'
8
- assert manimpango.MarkupUtils.validate(
9
- "<b>bar</b>"
10
- ), '"<b>bar</b>" should not fail validation'
11
- assert manimpango.MarkupUtils.validate(
12
- "வணக்கம்",
13
- ), '"வணக்கம்" should not fail'
14
-
15
-
16
- def test_bad_markup():
17
- import manimpango # noqa: F401
18
-
19
- assert not manimpango.MarkupUtils.validate(
20
- "<b>foo"
21
- ), '"<b>foo" should fail validation (unbalanced tags)'
22
- assert not manimpango.MarkupUtils.validate(
23
- "<xyz>foo</xyz>"
24
- ), '"<xyz>foo</xyz>" should fail validation (invalid tag)'
File without changes
File without changes