manimpango 0.3.0__tar.gz → 0.4.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.
Files changed (52) hide show
  1. {ManimPango-0.3.0 → ManimPango-0.4.0}/MANIFEST.in +1 -0
  2. {ManimPango-0.3.0 → ManimPango-0.4.0}/ManimPango.egg-info/PKG-INFO +7 -7
  3. {ManimPango-0.3.0 → ManimPango-0.4.0}/ManimPango.egg-info/SOURCES.txt +1 -0
  4. {ManimPango-0.3.0 → ManimPango-0.4.0}/PKG-INFO +7 -7
  5. {ManimPango-0.3.0 → ManimPango-0.4.0}/docs/RELEASE.rst +6 -0
  6. {ManimPango-0.3.0 → ManimPango-0.4.0}/manimpango/_version.py +1 -1
  7. {ManimPango-0.3.0 → ManimPango-0.4.0}/manimpango/cmanimpango.pyx +17 -10
  8. ManimPango-0.4.0/pyproject.toml +11 -0
  9. ManimPango-0.4.0/requirements-dev.txt +4 -0
  10. {ManimPango-0.3.0 → ManimPango-0.4.0}/setup.cfg +1 -1
  11. {ManimPango-0.3.0 → ManimPango-0.4.0}/setup.py +8 -7
  12. ManimPango-0.4.0/tests/_manim.py +278 -0
  13. ManimPango-0.4.0/tests/test_colors.py +26 -0
  14. {ManimPango-0.3.0 → ManimPango-0.4.0}/tests/test_fonts.py +67 -37
  15. {ManimPango-0.3.0 → ManimPango-0.4.0}/tests/test_list_fonts.py +1 -1
  16. ManimPango-0.3.0/pyproject.toml +0 -2
  17. ManimPango-0.3.0/requirements-dev.txt +0 -5
  18. ManimPango-0.3.0/tests/_manim.py +0 -106
  19. {ManimPango-0.3.0 → ManimPango-0.4.0}/.coveragerc +0 -0
  20. {ManimPango-0.3.0 → ManimPango-0.4.0}/CODE_OF_CONDUCT.md +0 -0
  21. {ManimPango-0.3.0 → ManimPango-0.4.0}/LICENSE +0 -0
  22. {ManimPango-0.3.0 → ManimPango-0.4.0}/ManimPango.egg-info/dependency_links.txt +0 -0
  23. {ManimPango-0.3.0 → ManimPango-0.4.0}/ManimPango.egg-info/not-zip-safe +0 -0
  24. {ManimPango-0.3.0 → ManimPango-0.4.0}/ManimPango.egg-info/top_level.txt +0 -0
  25. {ManimPango-0.3.0 → ManimPango-0.4.0}/README.md +0 -0
  26. {ManimPango-0.3.0 → ManimPango-0.4.0}/docs/_static/favicon.ico +0 -0
  27. {ManimPango-0.3.0 → ManimPango-0.4.0}/docs/_templates/autosummary/class.rst +0 -0
  28. {ManimPango-0.3.0 → ManimPango-0.4.0}/docs/_templates/autosummary/module.rst +0 -0
  29. {ManimPango-0.3.0 → ManimPango-0.4.0}/docs/conf.py +0 -0
  30. {ManimPango-0.3.0 → ManimPango-0.4.0}/docs/index.rst +0 -0
  31. {ManimPango-0.3.0 → ManimPango-0.4.0}/docs/make.bat +0 -0
  32. {ManimPango-0.3.0 → ManimPango-0.4.0}/docs/reference.rst +0 -0
  33. {ManimPango-0.3.0 → ManimPango-0.4.0}/manimpango/__init__.py +0 -0
  34. {ManimPango-0.3.0 → ManimPango-0.4.0}/manimpango/cairo.pxd +0 -0
  35. {ManimPango-0.3.0 → ManimPango-0.4.0}/manimpango/cmanimpango.pxd +0 -0
  36. {ManimPango-0.3.0 → ManimPango-0.4.0}/manimpango/enums.pyx +0 -0
  37. {ManimPango-0.3.0 → ManimPango-0.4.0}/manimpango/glib.pxd +0 -0
  38. {ManimPango-0.3.0 → ManimPango-0.4.0}/manimpango/pango.pxd +0 -0
  39. {ManimPango-0.3.0 → ManimPango-0.4.0}/manimpango/register_font.pxd +0 -0
  40. {ManimPango-0.3.0 → ManimPango-0.4.0}/manimpango/register_font.pyx +0 -0
  41. {ManimPango-0.3.0 → ManimPango-0.4.0}/manimpango/utils.py +0 -0
  42. {ManimPango-0.3.0 → ManimPango-0.4.0}/tests/__init__.py +0 -0
  43. {ManimPango-0.3.0 → ManimPango-0.4.0}/tests/conftest.py +0 -0
  44. {ManimPango-0.3.0 → ManimPango-0.4.0}/tests/fonts/AdobeVFPrototype.ttf +0 -0
  45. {ManimPango-0.3.0 → ManimPango-0.4.0}/tests/fonts/BungeeColor-Regular_colr_Windows.ttf +0 -0
  46. {ManimPango-0.3.0 → ManimPango-0.4.0}/tests/fonts/BungeeOutline-Regular.ttf +0 -0
  47. {ManimPango-0.3.0 → ManimPango-0.4.0}/tests/fonts/LICENSE.txt +0 -0
  48. {ManimPango-0.3.0 → ManimPango-0.4.0}/tests/fonts/MaShanZheng-Regular.ttf +0 -0
  49. {ManimPango-0.3.0 → ManimPango-0.4.0}/tests/svg_tester.py +0 -0
  50. {ManimPango-0.3.0 → ManimPango-0.4.0}/tests/test_markup.py +0 -0
  51. {ManimPango-0.3.0 → ManimPango-0.4.0}/tests/test_utils.py +0 -0
  52. {ManimPango-0.3.0 → ManimPango-0.4.0}/tests/test_version.py +0 -0
@@ -5,3 +5,4 @@ prune docs/_build
5
5
  include *.md
6
6
  include *.txt
7
7
  include .coveragerc
8
+ include LICENSE*
@@ -1,12 +1,12 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ManimPango
3
- Version: 0.3.0
3
+ Version: 0.4.0
4
4
  Summary: Bindings for Pango for using with Manim.
5
5
  Home-page: https://manimpango.manim.community/
6
6
  Author: Naveen M K
7
- Author-email: naveen@syrusdark.website
7
+ Author-email: naveen@manim.community
8
8
  Maintainer: The Manim Community Developers
9
- License: UNKNOWN
9
+ License: GPL-3.0-or-later
10
10
  Project-URL: Documentation, https://manimpango.manim.community/
11
11
  Project-URL: Source, https://github.com/ManimCommunity/manimpango
12
12
  Project-URL: Release notes, https://github.com/ManimCommunity/ManimPango/releases/
@@ -193,14 +193,14 @@ Platform: Linux
193
193
  Platform: macOS
194
194
  Platform: Windows
195
195
  Classifier: Programming Language :: Python :: 3
196
- Classifier: Programming Language :: Python :: 3.6
197
196
  Classifier: Programming Language :: Python :: 3.7
198
197
  Classifier: Programming Language :: Python :: 3.8
199
198
  Classifier: Programming Language :: Python :: 3.9
200
- Classifier: Development Status :: 3 - Alpha
199
+ Classifier: Programming Language :: Python :: 3.10
200
+ Classifier: Development Status :: 4 - Beta
201
201
  Classifier: Programming Language :: Python :: 3 :: Only
202
- Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
202
+ Classifier: License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
203
203
  Classifier: Operating System :: OS Independent
204
204
  Classifier: Programming Language :: Cython
205
- Requires-Python: >=3.6
205
+ Requires-Python: >=3.7
206
206
  Description-Content-Type: text/markdown
@@ -35,6 +35,7 @@ tests/__init__.py
35
35
  tests/_manim.py
36
36
  tests/conftest.py
37
37
  tests/svg_tester.py
38
+ tests/test_colors.py
38
39
  tests/test_fonts.py
39
40
  tests/test_list_fonts.py
40
41
  tests/test_markup.py
@@ -1,12 +1,12 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ManimPango
3
- Version: 0.3.0
3
+ Version: 0.4.0
4
4
  Summary: Bindings for Pango for using with Manim.
5
5
  Home-page: https://manimpango.manim.community/
6
6
  Author: Naveen M K
7
- Author-email: naveen@syrusdark.website
7
+ Author-email: naveen@manim.community
8
8
  Maintainer: The Manim Community Developers
9
- License: UNKNOWN
9
+ License: GPL-3.0-or-later
10
10
  Project-URL: Documentation, https://manimpango.manim.community/
11
11
  Project-URL: Source, https://github.com/ManimCommunity/manimpango
12
12
  Project-URL: Release notes, https://github.com/ManimCommunity/ManimPango/releases/
@@ -193,14 +193,14 @@ Platform: Linux
193
193
  Platform: macOS
194
194
  Platform: Windows
195
195
  Classifier: Programming Language :: Python :: 3
196
- Classifier: Programming Language :: Python :: 3.6
197
196
  Classifier: Programming Language :: Python :: 3.7
198
197
  Classifier: Programming Language :: Python :: 3.8
199
198
  Classifier: Programming Language :: Python :: 3.9
200
- Classifier: Development Status :: 3 - Alpha
199
+ Classifier: Programming Language :: Python :: 3.10
200
+ Classifier: Development Status :: 4 - Beta
201
201
  Classifier: Programming Language :: Python :: 3 :: Only
202
- Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
202
+ Classifier: License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
203
203
  Classifier: Operating System :: OS Independent
204
204
  Classifier: Programming Language :: Cython
205
- Requires-Python: >=3.6
205
+ Requires-Python: >=3.7
206
206
  Description-Content-Type: text/markdown
@@ -31,13 +31,18 @@ This means older version would have a backport of bugs fixes.
31
31
  Here, ``-s`` is used to sign the tag with gpg so that users
32
32
  can later verify it, and a tag shouldn't be created with
33
33
  signing because Github shows it unverified.
34
+
34
35
  .. important::
35
36
 
36
37
  The message should include the changelog of the release.
38
+ There is a github actions which will creates a draft `release`_
39
+ with the changelog. You can edit them and copy it to the tag you
40
+ create.
37
41
 
38
42
  8. Push the tag to remote.
39
43
 
40
44
  9. Go to `Github`_, and `draft a new release`_ with the same tag pushed.
45
+ You can copy the same changelog you copied when you created the tag.
41
46
 
42
47
  10. Check whether the CI uploads the wheels and the ``.tar.gz`` file to
43
48
  PyPi.
@@ -50,3 +55,4 @@ This means older version would have a backport of bugs fixes.
50
55
  .. _Github: https://github.com
51
56
  .. _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
57
  .. _PyPi: https://pypi.org/project/manimpango/
58
+ .. _release: https://github.com/ManimCommunity/ManimPango/releases
@@ -1,2 +1,2 @@
1
1
  # -*- coding: utf-8 -*-
2
- __version__ = "0.3.0"
2
+ __version__ = "0.4.0"
@@ -13,14 +13,17 @@ class TextSetting:
13
13
  font:str,
14
14
  slant,
15
15
  weight,
16
- line_num=-1
16
+ line_num=-1,
17
+ color: str=None,
17
18
  ):
18
19
  self.start = start
19
20
  self.end = end
20
- self.font = font.encode('utf-8')
21
+ self.font = font
21
22
  self.slant = slant
22
23
  self.weight = weight
23
24
  self.line_num = line_num
25
+ self.color = color
26
+
24
27
 
25
28
  def text2svg(
26
29
  settings:list,
@@ -79,11 +82,11 @@ def text2svg(
79
82
  pango_layout_set_width(layout, pango_units_from_double(pango_width))
80
83
 
81
84
  for setting in settings:
82
- family = setting.font
85
+ family = setting.font.encode('utf-8')
83
86
  style = PangoUtils.str2style(setting.slant)
84
87
  weight = PangoUtils.str2weight(setting.weight)
88
+ color = setting.color
85
89
  text_str = orig_text[setting.start : setting.end].replace("\n", " ")
86
- text = text_str.encode('utf-8')
87
90
  font_desc = pango_font_description_new()
88
91
  if font_desc==NULL:
89
92
  cairo_destroy(cr)
@@ -103,13 +106,17 @@ def text2svg(
103
106
  cairo_move_to(cr,START_X + offset_x,START_Y + line_spacing * setting.line_num)
104
107
 
105
108
  pango_cairo_update_layout(cr,layout)
109
+ markup = escape(text_str)
110
+ if color:
111
+ markup = (f"<span color='{color}'>{markup}</span>")
112
+ if MarkupUtils.validate(markup):
113
+ cairo_destroy(cr)
114
+ cairo_surface_destroy(surface)
115
+ g_object_unref(layout)
116
+ raise ValueError(f"Pango cannot recognize your color '{color}' for text '{text_str}'.")
106
117
  if disable_liga:
107
- text_bytes = escape(text.decode('utf-8'))
108
- markup = f"<span font_features='liga=0,dlig=0,clig=0,hlig=0'>{text_bytes}</span>"
109
- markup_bytes = markup.encode('utf-8')
110
- pango_layout_set_markup(layout, markup_bytes, -1)
111
- else:
112
- pango_layout_set_text(layout,text,-1)
118
+ markup = f"<span font_features='liga=0,dlig=0,clig=0,hlig=0'>{markup}</span>"
119
+ pango_layout_set_markup(layout, markup.encode('utf-8'), -1)
113
120
  pango_cairo_show_layout(cr, layout)
114
121
  pango_layout_get_size(layout,&temp_width,NULL)
115
122
  offset_x += pango_units_to_double(temp_width)
@@ -0,0 +1,11 @@
1
+ [build-system]
2
+ requires = ["setuptools", "wheel", "Cython>=0.27"]
3
+
4
+ [tool.isort]
5
+ # from https://black.readthedocs.io/en/stable/compatible_configs.html
6
+ multi_line_output = 3
7
+ include_trailing_comma = true
8
+ force_grid_wrap = 0
9
+ use_parentheses = true
10
+ ensure_newline_before_comments = true
11
+ line_length = 88
@@ -0,0 +1,4 @@
1
+ pytest-cov==2.12.0
2
+ pytest==6.2.4
3
+ Cython==0.29.24
4
+ coverage==5.5
@@ -1,7 +1,7 @@
1
1
  [metadata]
2
2
  license_files =
3
3
  LICENSE
4
- LICENSE.win32
4
+ LICENSE.*
5
5
 
6
6
  [flake8]
7
7
  max-line-length = 88
@@ -90,8 +90,8 @@ class PKG_CONFIG:
90
90
  return True
91
91
  except Exception:
92
92
  warnings.warn(
93
- f"{self.pkg_config} doesn't exists or doesn't seem to work"
94
- "We assume that you give the compiler flags using"
93
+ f"{self.pkg_config} doesn't exists or doesn't seem to work\n"
94
+ "We assume that you give the compiler flags using\n"
95
95
  "corresponding environment variables.",
96
96
  RuntimeWarning,
97
97
  )
@@ -243,7 +243,7 @@ setup(
243
243
  name=NAME,
244
244
  version=MANIMPANGO_VERSION,
245
245
  author="Naveen M K",
246
- author_email="naveen@syrusdark.website",
246
+ author_email="naveen@manim.community",
247
247
  maintainer="The Manim Community Developers",
248
248
  url="https://manimpango.manim.community/",
249
249
  description="Bindings for Pango for using with Manim.",
@@ -251,18 +251,19 @@ setup(
251
251
  zip_safe=False,
252
252
  long_description_content_type="text/markdown",
253
253
  packages=["manimpango"],
254
- python_requires=">=3.6",
254
+ python_requires=">=3.7",
255
255
  platforms=["Linux", "macOS", "Windows"],
256
256
  keywords=["cython", "pango", "cairo", "manim"],
257
+ license="GPL-3.0-or-later",
257
258
  classifiers=[
258
259
  "Programming Language :: Python :: 3",
259
- "Programming Language :: Python :: 3.6",
260
260
  "Programming Language :: Python :: 3.7",
261
261
  "Programming Language :: Python :: 3.8",
262
262
  "Programming Language :: Python :: 3.9",
263
- "Development Status :: 3 - Alpha",
263
+ "Programming Language :: Python :: 3.10",
264
+ "Development Status :: 4 - Beta",
264
265
  "Programming Language :: Python :: 3 :: Only",
265
- "License :: OSI Approved :: GNU General Public License v3 (GPLv3)",
266
+ "License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)",
266
267
  "Operating System :: OS Independent",
267
268
  "Programming Language :: Cython",
268
269
  ],
@@ -0,0 +1,278 @@
1
+ # -*- coding: utf-8 -*-
2
+ """This file contains helpers for the tests copied and modified
3
+ from Manim.
4
+ """
5
+ import copy
6
+ import os
7
+ import re
8
+ from pathlib import Path
9
+ from typing import Sequence
10
+
11
+ from manimpango import Alignment, MarkupUtils, TextSetting, text2svg
12
+
13
+
14
+ class MarkupText:
15
+ def __init__(
16
+ self,
17
+ text: str,
18
+ *,
19
+ size: int = 1,
20
+ line_spacing: int = None,
21
+ font: str = None,
22
+ slant: str = "NORMAL",
23
+ weight: str = "NORMAL",
24
+ tab_width: int = 4,
25
+ disable_ligatures: bool = False,
26
+ justify: bool = None,
27
+ indent: float = None,
28
+ alignment: Alignment = None,
29
+ # for the tests
30
+ filename: str = "test.svg",
31
+ wrap_text: bool = True,
32
+ **kwargs,
33
+ ):
34
+ self.text = text
35
+ self.size = size
36
+ self.line_spacing = line_spacing
37
+ self.font = font
38
+ self.slant = slant
39
+ self.weight = weight
40
+ self.tab_width = tab_width
41
+ self.filename = filename
42
+ self.original_text = text
43
+ self.disable_ligatures = disable_ligatures
44
+
45
+ self.justify = justify
46
+ self.indent = indent
47
+ self.alignment = alignment
48
+ self.wrap_text = wrap_text
49
+ if MarkupUtils.validate(self.text):
50
+ raise ValueError(
51
+ f"Pango cannot parse your markup in {self.text}. "
52
+ "Please check for typos, unmatched tags or unescaped "
53
+ "special chars like < and &."
54
+ )
55
+ self.text2svg()
56
+
57
+ def text2svg(self):
58
+ """Convert the text to SVG using Pango."""
59
+ size = self.size * 10
60
+ dir_name = Path(self.filename).parent
61
+ disable_liga = self.disable_ligatures
62
+ if not os.path.exists(dir_name):
63
+ os.makedirs(dir_name)
64
+ file_name = self.filename
65
+ if self.wrap_text:
66
+ return MarkupUtils.text2svg(
67
+ f"{self.text}",
68
+ self.font,
69
+ self.slant,
70
+ self.weight,
71
+ size,
72
+ True, # stray positional argument
73
+ disable_liga,
74
+ file_name,
75
+ 20,
76
+ 20,
77
+ 600, # width
78
+ 400, # height
79
+ justify=self.justify,
80
+ indent=self.indent,
81
+ line_spacing=self.line_spacing,
82
+ alignment=self.alignment,
83
+ )
84
+ else:
85
+ return MarkupUtils.text2svg(
86
+ f"{self.text}",
87
+ self.font,
88
+ self.slant,
89
+ self.weight,
90
+ size,
91
+ True, # stray positional argument
92
+ disable_liga,
93
+ file_name,
94
+ 20,
95
+ 20,
96
+ 600, # width
97
+ 400, # height
98
+ justify=self.justify,
99
+ indent=self.indent,
100
+ line_spacing=self.line_spacing,
101
+ alignment=self.alignment,
102
+ pango_width=-1,
103
+ )
104
+ # -1 for no wrapping
105
+ # default is full width and then wrap.
106
+
107
+ def __repr__(self):
108
+ return f"MarkupText({repr(self.original_text)})"
109
+
110
+
111
+ class Text:
112
+ def __init__(
113
+ self,
114
+ text: str,
115
+ fill_opacity: float = 1.0,
116
+ stroke_width: int = 0,
117
+ size: int = 1,
118
+ line_spacing: int = -1,
119
+ font: str = "",
120
+ slant: str = "NORMAL",
121
+ weight: str = "NORMAL",
122
+ gradient: tuple = None,
123
+ tab_width: int = 4,
124
+ disable_ligatures: bool = False,
125
+ filename: str = "text.svg",
126
+ color: str = "white",
127
+ **kwargs,
128
+ ) -> None:
129
+ self.color = color
130
+ self.size = size
131
+ self.filename = filename
132
+ self.line_spacing = line_spacing
133
+ self.font = font
134
+ self.slant = slant
135
+ self.weight = weight
136
+ self.gradient = gradient
137
+ self.tab_width = tab_width
138
+ self.original_text = text
139
+ self.disable_ligatures = disable_ligatures
140
+ text_without_tabs = text
141
+ self.t2f = self.t2s = self.t2w = self.t2c = {}
142
+ if text.find("\t") != -1:
143
+ text_without_tabs = text.replace("\t", " " * self.tab_width)
144
+ self.text = text_without_tabs
145
+ if self.line_spacing == -1:
146
+ self.line_spacing = self.size + self.size * 0.3
147
+ else:
148
+ self.line_spacing = self.size + self.size * self.line_spacing
149
+ self.text2svg()
150
+
151
+ def _merge_settings(
152
+ self, left_setting: TextSetting, right_setting: TextSetting, args: Sequence[str]
153
+ ) -> TextSetting:
154
+ contained = right_setting.end < left_setting.end
155
+ new_setting = copy.copy(left_setting) if contained else copy.copy(right_setting)
156
+
157
+ new_setting.start = right_setting.end if contained else left_setting.end
158
+ left_setting.end = right_setting.start
159
+ if not contained:
160
+ right_setting.end = new_setting.start
161
+
162
+ for arg in args:
163
+ left = getattr(left_setting, arg)
164
+ right = getattr(right_setting, arg)
165
+ default = getattr(self, arg)
166
+ if left != default and getattr(right_setting, arg) != default:
167
+ raise ValueError(
168
+ "Ambiguous style for text"
169
+ f"'{self.text[right_setting.start:right_setting.end]}':"
170
+ f"'{arg}' cannot be both '{left}' and '{right}'."
171
+ )
172
+ setattr(right_setting, arg, left if left != default else right)
173
+ return new_setting
174
+
175
+ def text2settings(self):
176
+ """Internally used function. Converts the texts and styles
177
+ to a setting for parsing."""
178
+ settings = []
179
+ t2xs = [
180
+ (self.t2f, "font"),
181
+ (self.t2s, "slant"),
182
+ (self.t2w, "weight"),
183
+ (self.t2c, "color"),
184
+ ]
185
+ t2xwords = {
186
+ *self.t2f.keys(),
187
+ *self.t2s.keys(),
188
+ *self.t2w.keys(),
189
+ *self.t2c.keys(),
190
+ }
191
+ for word in t2xwords:
192
+ setting_args = {
193
+ arg: t2x[word] if word in t2x else getattr(self, arg)
194
+ for t2x, arg in t2xs
195
+ }
196
+
197
+ for start, end in self.find_indexes(word, self.text):
198
+ settings.append(TextSetting(start, end, **setting_args))
199
+
200
+ # Handle overlaps
201
+ setting_args = {arg: getattr(self, arg) for _, arg in t2xs}
202
+
203
+ settings.sort(key=lambda setting: setting.start)
204
+ index = 0
205
+ for setting in settings:
206
+ index += 1
207
+ if index == len(settings):
208
+ break
209
+
210
+ next_setting = settings[index]
211
+ if setting.end > next_setting.start:
212
+ new_setting = self._merge_settings(setting, next_setting, setting_args)
213
+ new_index = index
214
+ while (
215
+ new_index < len(settings)
216
+ and settings[new_index].start < new_setting.start
217
+ ):
218
+ new_index += 1
219
+ settings.insert(new_index, new_setting)
220
+
221
+ # Set all text settings (default font, slant, weight)
222
+ temp_settings = settings.copy()
223
+ start = 0
224
+ for setting in settings:
225
+ if setting.start != start:
226
+ temp_settings.append(TextSetting(start, setting.start, **setting_args))
227
+ start = setting.end
228
+ if start != len(self.text):
229
+ temp_settings.append(TextSetting(start, len(self.text), **setting_args))
230
+ settings = sorted(temp_settings, key=lambda setting: setting.start)
231
+
232
+ if re.search(r"\n", self.text):
233
+ line_num = 0
234
+ for start, end in self.find_indexes("\n", self.text):
235
+ for setting in settings:
236
+ if setting.line_num == -1:
237
+ setting.line_num = line_num
238
+ if start < setting.end:
239
+ line_num += 1
240
+ new_setting = copy.copy(setting)
241
+ setting.end = end
242
+ new_setting.start = end
243
+ new_setting.line_num = line_num
244
+ settings.append(new_setting)
245
+ settings.sort(key=lambda setting: setting.start)
246
+ break
247
+ for setting in settings:
248
+ if setting.line_num == -1:
249
+ setting.line_num = 0
250
+ return settings
251
+
252
+ def text2svg(self):
253
+ """Internally used function.
254
+ Convert the text to SVG using Pango
255
+ """
256
+ size = self.size * 10
257
+ line_spacing = self.line_spacing * 10
258
+ dir_name = Path(self.filename).parent
259
+ disable_liga = self.disable_ligatures
260
+ if not os.path.exists(dir_name):
261
+ os.makedirs(dir_name)
262
+ file_name = self.filename
263
+ settings = self.text2settings()
264
+ width = 600
265
+ height = 400
266
+
267
+ return text2svg(
268
+ settings,
269
+ size,
270
+ line_spacing,
271
+ disable_liga,
272
+ file_name,
273
+ 30,
274
+ 30,
275
+ width,
276
+ height,
277
+ self.text,
278
+ )
@@ -0,0 +1,26 @@
1
+ # -*- coding: utf-8 -*-
2
+ from pathlib import Path
3
+
4
+ import pytest
5
+
6
+ from . import CASES_DIR
7
+ from ._manim import Text
8
+ from .svg_tester import SVGStyleTester
9
+
10
+
11
+ def test_invalid_color_fail(tmpdir):
12
+ loc = Path(tmpdir, "test.svg")
13
+ assert not loc.exists()
14
+ with pytest.raises(ValueError):
15
+ Text("color", color="invalid", filename=str(loc))
16
+
17
+
18
+ def test_colors(tmpdir):
19
+ expected = Path(CASES_DIR, "color_red.svg")
20
+ loc = Path(tmpdir, "test.svg")
21
+ assert not loc.exists()
22
+ Text("color", color="red", filename=str(loc))
23
+ assert loc.exists()
24
+ s = SVGStyleTester(gotSVG=loc, expectedSVG=expected)
25
+ assert len(s.got_svg_style) == len(s.expected_svg_style)
26
+ assert s.got_svg_style == s.expected_svg_style
@@ -1,9 +1,12 @@
1
1
  # -*- coding: utf-8 -*-
2
+ import os
3
+ import subprocess
2
4
  import sys
5
+ import textwrap
6
+ from contextlib import contextmanager
3
7
  from pathlib import Path
4
8
  from shutil import copyfile
5
9
 
6
- import manim
7
10
  import pytest
8
11
 
9
12
  import manimpango
@@ -11,13 +14,31 @@ import manimpango
11
14
  from . import FONT_DIR
12
15
  from ._manim import MarkupText
13
16
 
14
- font_lists = {
15
- (FONT_DIR / "AdobeVFPrototype.ttf").absolute(): "Adobe Variable Font Prototype",
16
- (
17
- FONT_DIR / "BungeeColor-Regular_colr_Windows.ttf"
18
- ).absolute(): "Bungee Color Regular",
19
- (FONT_DIR / "MaShanZheng-Regular.ttf").absolute(): "Ma Shan Zheng",
20
- }
17
+
18
+ @contextmanager
19
+ def register_font(font_file: Path):
20
+ font_file = os.fspath(font_file)
21
+ init = manimpango.list_fonts()
22
+ assert manimpango.register_font(font_file), "Invalid Font possibly."
23
+ final = manimpango.list_fonts()
24
+ yield list(set(final) - set(init))[0]
25
+ assert manimpango.unregister_font(font_file), "Can't unregister Font"
26
+
27
+
28
+ def font_list():
29
+ _t = [
30
+ (FONT_DIR / "AdobeVFPrototype.ttf").absolute(),
31
+ (FONT_DIR / "BungeeColor-Regular_colr_Windows.ttf").absolute(),
32
+ (FONT_DIR / "MaShanZheng-Regular.ttf").absolute(),
33
+ ]
34
+ _d = {}
35
+ for i in _t:
36
+ with register_font(i) as f:
37
+ _d[i] = f
38
+ return _d
39
+
40
+
41
+ font_lists_dict = font_list()
21
42
 
22
43
 
23
44
  def test_unicode_font_name(tmpdir):
@@ -27,46 +48,54 @@ def test_unicode_font_name(tmpdir):
27
48
  assert manimpango.unregister_font(final_font)
28
49
 
29
50
 
30
- @pytest.mark.parametrize("font_name", font_lists)
31
- def test_register_font(font_name):
51
+ @pytest.mark.parametrize("font_name", font_lists_dict)
52
+ def test_register_and_unregister_font(font_name):
32
53
  intial = manimpango.list_fonts()
33
54
  assert manimpango.register_font(str(font_name)), "Invalid Font possibly."
34
55
  final = manimpango.list_fonts()
35
56
  assert intial != final
36
-
37
-
38
- @pytest.mark.parametrize("font_name", font_lists.values())
39
- def test_warning(capfd, font_name):
40
- print(font_name)
41
- manim.Text("Testing", font=font_name)
42
- captured = capfd.readouterr()
43
- assert "Pango-WARNING **" not in captured.err, "Looks like pango raised a warning?"
44
-
45
-
46
- @pytest.mark.skipif(
47
- sys.platform.startswith("linux"), reason="unsupported api for linux"
48
- )
49
- @pytest.mark.parametrize("font_name", font_lists)
50
- def test_unregister_font(font_name):
51
- intial = manimpango.list_fonts()
52
- assert manimpango.unregister_font(str(font_name)), "Failed to unregister the font"
53
- final = manimpango.list_fonts()
54
- assert intial != final
57
+ assert manimpango.unregister_font(os.fspath(font_name)), "Can't unregister font."
58
+ assert intial == manimpango.list_fonts()
55
59
 
56
60
 
57
61
  @pytest.mark.skipif(
58
- sys.platform.startswith("linux"), reason="unsupported api for linux"
62
+ sys.platform.startswith("linux"), reason="no warning are raised for linux"
59
63
  )
60
- @pytest.mark.parametrize("font_name", font_lists)
61
- def test_register_and_unregister_font(font_name):
62
- assert manimpango.register_font(str(font_name)), "Invalid Font possibly."
63
- assert manimpango.unregister_font(str(font_name)), "Failed to unregister the font"
64
+ @pytest.mark.parametrize("font_file,font_name", font_lists_dict.items())
65
+ def test_warning(font_file, font_name):
66
+ # this tests need to be run in a separate subprocess because
67
+ # of fontmap cache in Pango.
68
+ command = textwrap.dedent(
69
+ f"""\
70
+ from tests import set_dll_search_path
71
+ set_dll_search_path() # this is needed on Windows to run
72
+ import manimpango
73
+ import os
74
+ from tests._manim import Text
75
+ font_file = r'{os.fspath(font_file)}'
76
+ font_name = r'{font_name}'
77
+ intial = manimpango.list_fonts()
78
+ manimpango.register_font(os.fspath(font_file))
79
+ final = manimpango.list_fonts()
80
+ assert intial != final
81
+ Text("Testing", font=font_name)
82
+ manimpango.unregister_font(os.fspath(font_file))
83
+ """
84
+ )
85
+ a = subprocess.run(
86
+ [sys.executable, "-c", command],
87
+ check=True,
88
+ stderr=subprocess.PIPE,
89
+ cwd=Path(__file__).parent.parent,
90
+ )
91
+ captured = a.stderr.decode()
92
+ assert "Pango-WARNING **" not in captured, "Looks like Pango raised a warning?"
64
93
 
65
94
 
66
95
  @pytest.mark.skipif(
67
96
  sys.platform.startswith("linux"), reason="unsupported api for linux"
68
97
  )
69
- @pytest.mark.parametrize("font_name", font_lists)
98
+ @pytest.mark.parametrize("font_name", font_lists_dict)
70
99
  @pytest.mark.skipif(sys.platform.startswith("darwin"), reason="always returns true")
71
100
  def test_fail_just_unregister(font_name):
72
101
  assert not manimpango.unregister_font(
@@ -78,7 +107,7 @@ def test_fail_just_unregister(font_name):
78
107
  sys.platform.startswith("win32"), reason="unsupported api for win32"
79
108
  )
80
109
  @pytest.mark.skipif(sys.platform.startswith("darwin"), reason="unsupported api for mac")
81
- def test_unregister_linux():
110
+ def test_unregister_not_fail_linux():
82
111
  assert manimpango.unregister_font("random")
83
112
 
84
113
 
@@ -90,6 +119,7 @@ def test_adding_dummy_font(tmpdir):
90
119
  with open(dummy, "wb") as f:
91
120
  f.write(b"dummy")
92
121
  assert not manimpango.register_font(str(dummy)), "Registered a dummy font?"
122
+ assert not manimpango.fc_register_font(str(dummy)), "Registered a dummy font?"
93
123
 
94
124
 
95
125
  def test_simple_fonts_render(tmpdir):
@@ -106,7 +136,7 @@ def test_both_fc_and_register_font_are_same():
106
136
  assert manimpango.fc_unregister_font == manimpango.unregister_font
107
137
 
108
138
 
109
- @pytest.mark.parametrize("font_file", font_lists)
139
+ @pytest.mark.parametrize("font_file", font_lists_dict)
110
140
  def test_fc_font_register(setup_fontconfig, font_file):
111
141
  intial = manimpango.list_fonts()
112
142
  assert manimpango.fc_register_font(str(font_file)), "Invalid Font possibly."
@@ -5,7 +5,7 @@ import pytest
5
5
 
6
6
  import manimpango
7
7
 
8
- from .test_fonts import font_lists
8
+ from .test_fonts import font_lists_dict as font_lists
9
9
 
10
10
 
11
11
  def test_whether_list():
@@ -1,2 +0,0 @@
1
- [build-system]
2
- requires = ["setuptools", "wheel","Cython>=0.27"]
@@ -1,5 +0,0 @@
1
- pytest-cov
2
- pytest
3
- Cython
4
- coverage
5
- manim>0.2.0
@@ -1,106 +0,0 @@
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
- wrap_text: bool = True,
30
- **kwargs,
31
- ):
32
- self.text = text
33
- self.size = size
34
- self.line_spacing = line_spacing
35
- self.font = font
36
- self.slant = slant
37
- self.weight = weight
38
- self.tab_width = tab_width
39
- self.filename = filename
40
- self.original_text = text
41
- self.disable_ligatures = disable_ligatures
42
-
43
- self.justify = justify
44
- self.indent = indent
45
- self.alignment = alignment
46
- self.wrap_text = wrap_text
47
- if MarkupUtils.validate(self.text):
48
- raise ValueError(
49
- f"Pango cannot parse your markup in {self.text}. "
50
- "Please check for typos, unmatched tags or unescaped "
51
- "special chars like < and &."
52
- )
53
- self.text2svg()
54
-
55
- def text2svg(self):
56
- """Convert the text to SVG using Pango."""
57
- size = self.size * 10
58
- dir_name = Path(self.filename).parent
59
- disable_liga = self.disable_ligatures
60
- if not os.path.exists(dir_name):
61
- os.makedirs(dir_name)
62
- file_name = self.filename
63
- if self.wrap_text:
64
- return MarkupUtils.text2svg(
65
- f"{self.text}",
66
- self.font,
67
- self.slant,
68
- self.weight,
69
- size,
70
- True, # stray positional argument
71
- disable_liga,
72
- file_name,
73
- 20,
74
- 20,
75
- 600, # width
76
- 400, # height
77
- justify=self.justify,
78
- indent=self.indent,
79
- line_spacing=self.line_spacing,
80
- alignment=self.alignment,
81
- )
82
- else:
83
- return MarkupUtils.text2svg(
84
- f"{self.text}",
85
- self.font,
86
- self.slant,
87
- self.weight,
88
- size,
89
- True, # stray positional argument
90
- disable_liga,
91
- file_name,
92
- 20,
93
- 20,
94
- 600, # width
95
- 400, # height
96
- justify=self.justify,
97
- indent=self.indent,
98
- line_spacing=self.line_spacing,
99
- alignment=self.alignment,
100
- pango_width=-1,
101
- )
102
- # -1 for no wrapping
103
- # default is full width and then wrap.
104
-
105
- def __repr__(self):
106
- return f"MarkupText({repr(self.original_text)})"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes