Skip to content

Commit efdbbee

Browse files
authored
Merge pull request #39 from fonttools/copy-data-from-glyph
add methods to copy glyphs
2 parents 85e5764 + 9784d98 commit efdbbee

File tree

4 files changed

+114
-10
lines changed

4 files changed

+114
-10
lines changed

src/ufoLib2/objects/glyph.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import attr
2+
from copy import deepcopy
23
from typing import Union, List, Any, Dict, Optional
34
from ufoLib2.objects.anchor import Anchor
45
from ufoLib2.objects.guideline import Guideline
@@ -145,6 +146,36 @@ def appendGuideline(self, guideline):
145146
guideline = Guideline(**guideline)
146147
self._guidelines.append(guideline)
147148

149+
def copy(self, name=None):
150+
"""Return a new Glyph (deep) copy, optionally override the new glyph name.
151+
"""
152+
other = deepcopy(self)
153+
if name is not None:
154+
other._name = name
155+
return other
156+
157+
def copyDataFromGlyph(self, glyph):
158+
"""Deep-copy everything from the other glyph, except for the name.
159+
Existing glyph data is overwritten.
160+
161+
This method was added for compatibility with the defcon API, and
162+
it may be removed in the future.
163+
"""
164+
self.width = glyph.width
165+
self.height = glyph.height
166+
self.unicodes = list(glyph.unicodes)
167+
self.image = deepcopy(glyph.image)
168+
self.note = glyph.note
169+
self.lib = deepcopy(glyph.lib)
170+
self.anchors = deepcopy(glyph.anchors)
171+
self.guidelines = deepcopy(glyph.guidelines)
172+
# NOTE: defcon's copyDataFromGlyph appends instead of overwrites here,
173+
# but we do the right thing, for consistency with the rest.
174+
self.clearContours()
175+
self.clearComponents()
176+
pointPen = self.getPointPen()
177+
glyph.drawPoints(pointPen)
178+
148179
# -----------
149180
# Pen methods
150181
# -----------

tests/conftest.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
1-
import py
1+
import pathlib
2+
import shutil
23
import pytest
34
import ufoLib2
45

56

67
@pytest.fixture
78
def datadir(request):
8-
return py.path.local(request.fspath.dirname).join("data")
9+
return pathlib.Path(__file__).parent / "data"
910

1011

1112
@pytest.fixture
12-
def ufo_UbuTestData(tmpdir, datadir):
13-
ufo_path = tmpdir.join("UbuTestData.ufo")
14-
datadir.join("UbuTestData.ufo").copy(ufo_path)
15-
return ufoLib2.Font.open(str(ufo_path))
13+
def ufo_UbuTestData(tmp_path, datadir):
14+
ufo_path = tmp_path / "UbuTestData.ufo"
15+
shutil.copytree(datadir / "UbuTestData.ufo", ufo_path)
16+
return ufoLib2.Font.open(ufo_path)

tests/objects/test_glyph.py

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
from ufoLib2.objects import Anchor, Component, Glyph, Guideline, Image
2+
3+
4+
def test_copyDataFromGlyph(ufo_UbuTestData):
5+
font = ufo_UbuTestData
6+
7+
a = font["a"]
8+
a.height = 500
9+
a.image = Image("a.png")
10+
a.note = "a note"
11+
a.lib = {"bar": [3, 2, 1]}
12+
a.anchors = [Anchor(250, 0, "bottom")]
13+
a.guidelines = [Guideline(y=500)]
14+
a.components = [Component("A")]
15+
16+
b = Glyph("b")
17+
b.width = 350
18+
b.height = 1000
19+
b.image = Image("b.png")
20+
b.note = "b note"
21+
b.lib = {"foo": [1, 2, 3]}
22+
b.anchors = [Anchor(350, 800, "top")]
23+
b.guidelines = [Guideline(x=50)]
24+
25+
assert b.name != a.name
26+
assert b.width != a.width
27+
assert b.height != a.height
28+
assert b.unicodes != a.unicodes
29+
assert b.image != a.image
30+
assert b.note != a.note
31+
assert b.lib != a.lib
32+
assert b.anchors != a.anchors
33+
assert b.guidelines != a.guidelines
34+
assert b.contours != a.contours
35+
assert b.components != a.components
36+
37+
def _assert_equal_but_distinct_objects(glyph1, glyph2):
38+
assert glyph1.width == glyph2.width
39+
assert glyph1.height == glyph2.height
40+
assert glyph1.unicodes == glyph2.unicodes
41+
assert glyph1.unicodes is not glyph2.unicodes
42+
assert glyph1.image == glyph2.image
43+
assert glyph1.image is not glyph2.image
44+
assert glyph1.note == glyph2.note
45+
assert glyph1.lib == glyph2.lib
46+
assert glyph1.lib is not glyph2.lib
47+
assert glyph1.lib["bar"] == glyph2.lib["bar"]
48+
assert glyph1.lib["bar"] is not glyph2.lib["bar"]
49+
assert glyph1.anchors == glyph2.anchors
50+
assert glyph1.anchors is not glyph2.anchors
51+
assert glyph1.anchors[0] is not glyph2.anchors[0]
52+
assert glyph1.guidelines == glyph2.guidelines
53+
assert glyph1.guidelines is not glyph2.guidelines
54+
assert glyph1.guidelines[0] is not glyph2.guidelines[0]
55+
assert glyph1.contours == glyph2.contours
56+
assert glyph1.contours is not glyph2.contours
57+
assert glyph1.contours[0] is not glyph2.contours[0]
58+
assert glyph1.components == glyph2.components
59+
assert glyph1.components is not glyph2.components
60+
assert glyph1.components[0] is not glyph2.components[0]
61+
62+
b.copyDataFromGlyph(a)
63+
assert b.name != a.name
64+
_assert_equal_but_distinct_objects(b, a)
65+
66+
c = a.copy()
67+
assert c.name == a.name
68+
_assert_equal_but_distinct_objects(c, a)
69+
70+
d = a.copy(name="d")
71+
assert d.name == "d"
72+
_assert_equal_but_distinct_objects(d, a)

tests/test_ufoLib2.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,19 @@ def test_import_version():
77
assert isinstance(ufoLib2.__version__, str)
88

99

10-
def test_LayerSet_load_layers_on_iteration(tmpdir):
10+
def test_LayerSet_load_layers_on_iteration(tmp_path):
1111
ufo = ufoLib2.Font()
1212
ufo.layers.newLayer("test")
13-
ufo_save_path = str(tmpdir.join("test.ufo"))
13+
ufo_save_path = tmp_path / "test.ufo"
1414
ufo.save(ufo_save_path)
1515
ufo = ufoLib2.Font.open(ufo_save_path)
1616
for layer in ufo.layers:
1717
assert layer is not _NOT_LOADED
1818

1919

20-
def test_lazy_data_loading_saveas(ufo_UbuTestData, tmpdir):
20+
def test_lazy_data_loading_saveas(ufo_UbuTestData, tmp_path):
2121
ufo = ufo_UbuTestData
22-
ufo_path = str(tmpdir.join("UbuTestData2.ufo"))
22+
ufo_path = tmp_path / "UbuTestData2.ufo"
2323
ufo.save(ufo_path)
2424
assert all(v is not _NOT_LOADED for v in ufo.data._data.values())
2525

0 commit comments

Comments
 (0)