diff options
author | robot-piglet <robot-piglet@yandex-team.com> | 2024-04-01 04:03:58 +0300 |
---|---|---|
committer | robot-piglet <robot-piglet@yandex-team.com> | 2024-04-01 04:15:53 +0300 |
commit | 6e7835911e36724b4c14f4888d6f0222994eadf0 (patch) | |
tree | 7f6210d918014bc308e98934e896d34aadb9bac0 /contrib/python | |
parent | 8e91894b5642604c33982805651a0f59bcdaf137 (diff) | |
download | ydb-6e7835911e36724b4c14f4888d6f0222994eadf0.tar.gz |
Intermediate changes
Diffstat (limited to 'contrib/python')
-rw-r--r-- | contrib/python/fonttools/.dist-info/METADATA | 9 | ||||
-rw-r--r-- | contrib/python/fonttools/fontTools/__init__.py | 2 | ||||
-rw-r--r-- | contrib/python/fonttools/fontTools/cu2qu/ufo.py | 12 | ||||
-rw-r--r-- | contrib/python/fonttools/fontTools/pens/basePen.py | 50 | ||||
-rw-r--r-- | contrib/python/fonttools/fontTools/pens/filterPen.py | 86 | ||||
-rw-r--r-- | contrib/python/fonttools/fontTools/pens/pointPen.py | 79 | ||||
-rw-r--r-- | contrib/python/fonttools/fontTools/pens/recordingPen.py | 158 | ||||
-rw-r--r-- | contrib/python/fonttools/fontTools/varLib/instancer/__init__.py | 6 | ||||
-rw-r--r-- | contrib/python/fonttools/ya.make | 2 |
9 files changed, 360 insertions, 44 deletions
diff --git a/contrib/python/fonttools/.dist-info/METADATA b/contrib/python/fonttools/.dist-info/METADATA index a711f82b4e..b374ebc499 100644 --- a/contrib/python/fonttools/.dist-info/METADATA +++ b/contrib/python/fonttools/.dist-info/METADATA @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: fonttools -Version: 4.49.0 +Version: 4.50.0 Summary: Tools to manipulate font files Home-page: http://github.com/fonttools/fonttools Author: Just van Rossum @@ -375,6 +375,13 @@ Have fun! Changelog ~~~~~~~~~ +4.50.0 (released 2024-03-15) +---------------------------- + +- [pens] Added decomposing filter pens that draw components as regular contours (#3460). +- [instancer] Drop explicit no-op axes from TupleVariations (#3457). +- [cu2qu/ufo] Return set of modified glyph names from fonts_to_quadratic (#3456). + 4.49.0 (released 2024-02-15) ---------------------------- diff --git a/contrib/python/fonttools/fontTools/__init__.py b/contrib/python/fonttools/fontTools/__init__.py index e6a745bd52..ead49e26c8 100644 --- a/contrib/python/fonttools/fontTools/__init__.py +++ b/contrib/python/fonttools/fontTools/__init__.py @@ -3,6 +3,6 @@ from fontTools.misc.loggingTools import configLogger log = logging.getLogger(__name__) -version = __version__ = "4.49.0" +version = __version__ = "4.50.0" __all__ = ["version", "log", "configLogger"] diff --git a/contrib/python/fonttools/fontTools/cu2qu/ufo.py b/contrib/python/fonttools/fontTools/cu2qu/ufo.py index 10367cfecf..7a6dbc67f8 100644 --- a/contrib/python/fonttools/fontTools/cu2qu/ufo.py +++ b/contrib/python/fonttools/fontTools/cu2qu/ufo.py @@ -250,7 +250,7 @@ def fonts_to_quadratic( compatibility. If this is not required, calling fonts_to_quadratic with one font at a time may yield slightly more optimized results. - Return True if fonts were modified, else return False. + Return the set of modified glyph names if any, else return an empty set. By default, cu2qu stores the curve type in the fonts' lib, under a private key "com.github.googlei18n.cu2qu.curve_type", and will not try to convert @@ -296,7 +296,7 @@ def fonts_to_quadratic( elif max_err_em: max_errors = [f.info.unitsPerEm * max_err_em for f in fonts] - modified = False + modified = set() glyph_errors = {} for name in set().union(*(f.keys() for f in fonts)): glyphs = [] @@ -306,9 +306,10 @@ def fonts_to_quadratic( glyphs.append(font[name]) cur_max_errors.append(error) try: - modified |= _glyphs_to_quadratic( + if _glyphs_to_quadratic( glyphs, cur_max_errors, reverse_direction, stats, all_quadratic - ) + ): + modified.add(name) except IncompatibleGlyphsError as exc: logger.error(exc) glyph_errors[name] = exc @@ -329,7 +330,6 @@ def fonts_to_quadratic( new_curve_type = "quadratic" if all_quadratic else "mixed" if curve_type != new_curve_type: font.lib[CURVE_TYPE_LIB_KEY] = new_curve_type - modified = True return modified @@ -343,7 +343,7 @@ def glyph_to_quadratic(glyph, **kwargs): def font_to_quadratic(font, **kwargs): """Convenience wrapper around fonts_to_quadratic, for just one font. - Return True if the font was modified, else return False. + Return the set of modified glyph names if any, else return empty set. """ return fonts_to_quadratic([font], **kwargs) diff --git a/contrib/python/fonttools/fontTools/pens/basePen.py b/contrib/python/fonttools/fontTools/pens/basePen.py index 5d2cf5032c..ba38f70090 100644 --- a/contrib/python/fonttools/fontTools/pens/basePen.py +++ b/contrib/python/fonttools/fontTools/pens/basePen.py @@ -39,7 +39,7 @@ sequence of length 2 will do. from typing import Tuple, Dict from fontTools.misc.loggingTools import LogMixin -from fontTools.misc.transform import DecomposedTransform +from fontTools.misc.transform import DecomposedTransform, Identity __all__ = [ "AbstractPen", @@ -195,17 +195,40 @@ class DecomposingPen(LoggingPen): By default a warning message is logged when a base glyph is missing; set the class variable ``skipMissingComponents`` to False if you want - to raise a :class:`MissingComponentError` exception. + all instances of a sub-class to raise a :class:`MissingComponentError` + exception by default. """ skipMissingComponents = True + # alias error for convenience + MissingComponentError = MissingComponentError - def __init__(self, glyphSet): - """Takes a single 'glyphSet' argument (dict), in which the glyphs - that are referenced as components are looked up by their name. + def __init__( + self, + glyphSet, + *args, + skipMissingComponents=None, + reverseFlipped=False, + **kwargs, + ): + """Takes a 'glyphSet' argument (dict), in which the glyphs that are referenced + as components are looked up by their name. + + If the optional 'reverseFlipped' argument is True, components whose transformation + matrix has a negative determinant will be decomposed with a reversed path direction + to compensate for the flip. + + The optional 'skipMissingComponents' argument can be set to True/False to + override the homonymous class attribute for a given pen instance. """ - super(DecomposingPen, self).__init__() + super(DecomposingPen, self).__init__(*args, **kwargs) self.glyphSet = glyphSet + self.skipMissingComponents = ( + self.__class__.skipMissingComponents + if skipMissingComponents is None + else skipMissingComponents + ) + self.reverseFlipped = reverseFlipped def addComponent(self, glyphName, transformation): """Transform the points of the base glyph and draw it onto self.""" @@ -218,8 +241,19 @@ class DecomposingPen(LoggingPen): raise MissingComponentError(glyphName) self.log.warning("glyph '%s' is missing from glyphSet; skipped" % glyphName) else: - tPen = TransformPen(self, transformation) - glyph.draw(tPen) + pen = self + if transformation != Identity: + pen = TransformPen(pen, transformation) + if self.reverseFlipped: + # if the transformation has a negative determinant, it will + # reverse the contour direction of the component + a, b, c, d = transformation[:4] + det = a * d - b * c + if det < 0: + from fontTools.pens.reverseContourPen import ReverseContourPen + + pen = ReverseContourPen(pen) + glyph.draw(pen) def addVarComponent(self, glyphName, transformation, location): # GlyphSet decomposes for us diff --git a/contrib/python/fonttools/fontTools/pens/filterPen.py b/contrib/python/fonttools/fontTools/pens/filterPen.py index 6c8712c261..f104e67dd3 100644 --- a/contrib/python/fonttools/fontTools/pens/filterPen.py +++ b/contrib/python/fonttools/fontTools/pens/filterPen.py @@ -1,5 +1,7 @@ -from fontTools.pens.basePen import AbstractPen -from fontTools.pens.pointPen import AbstractPointPen +from __future__ import annotations + +from fontTools.pens.basePen import AbstractPen, DecomposingPen +from fontTools.pens.pointPen import AbstractPointPen, DecomposingPointPen from fontTools.pens.recordingPen import RecordingPen @@ -150,8 +152,8 @@ class FilterPointPen(_PassThruComponentsMixin, AbstractPointPen): ('endPath', (), {}) """ - def __init__(self, outPointPen): - self._outPen = outPointPen + def __init__(self, outPen): + self._outPen = outPen def beginPath(self, **kwargs): self._outPen.beginPath(**kwargs) @@ -161,3 +163,79 @@ class FilterPointPen(_PassThruComponentsMixin, AbstractPointPen): def addPoint(self, pt, segmentType=None, smooth=False, name=None, **kwargs): self._outPen.addPoint(pt, segmentType, smooth, name, **kwargs) + + +class _DecomposingFilterPenMixin: + """Mixin class that decomposes components as regular contours. + + Shared by both DecomposingFilterPen and DecomposingFilterPointPen. + + Takes two required parameters, another (segment or point) pen 'outPen' to draw + with, and a 'glyphSet' dict of drawable glyph objects to draw components from. + + The 'skipMissingComponents' and 'reverseFlipped' optional arguments work the + same as in the DecomposingPen/DecomposingPointPen. Both are False by default. + + In addition, the decomposing filter pens also take the following two options: + + 'include' is an optional set of component base glyph names to consider for + decomposition; the default include=None means decompose all components no matter + the base glyph name). + + 'decomposeNested' (bool) controls whether to recurse decomposition into nested + components of components (this only matters when 'include' was also provided); + if False, only decompose top-level components included in the set, but not + also their children. + """ + + # raises MissingComponentError if base glyph is not found in glyphSet + skipMissingComponents = False + + def __init__( + self, + outPen, + glyphSet, + skipMissingComponents=None, + reverseFlipped=False, + include: set[str] | None = None, + decomposeNested: bool = True, + ): + super().__init__( + outPen=outPen, + glyphSet=glyphSet, + skipMissingComponents=skipMissingComponents, + reverseFlipped=reverseFlipped, + ) + self.include = include + self.decomposeNested = decomposeNested + + def addComponent(self, baseGlyphName, transformation, **kwargs): + # only decompose the component if it's included in the set + if self.include is None or baseGlyphName in self.include: + # if we're decomposing nested components, temporarily set include to None + include_bak = self.include + if self.decomposeNested and self.include: + self.include = None + try: + super().addComponent(baseGlyphName, transformation, **kwargs) + finally: + if self.include != include_bak: + self.include = include_bak + else: + _PassThruComponentsMixin.addComponent( + self, baseGlyphName, transformation, **kwargs + ) + + +class DecomposingFilterPen(_DecomposingFilterPenMixin, DecomposingPen, FilterPen): + """Filter pen that draws components as regular contours.""" + + pass + + +class DecomposingFilterPointPen( + _DecomposingFilterPenMixin, DecomposingPointPen, FilterPointPen +): + """Filter point pen that draws components as regular contours.""" + + pass diff --git a/contrib/python/fonttools/fontTools/pens/pointPen.py b/contrib/python/fonttools/fontTools/pens/pointPen.py index eb1ebc2048..93a9201c99 100644 --- a/contrib/python/fonttools/fontTools/pens/pointPen.py +++ b/contrib/python/fonttools/fontTools/pens/pointPen.py @@ -15,8 +15,9 @@ For instance, whether or not a point is smooth, and its name. import math from typing import Any, Optional, Tuple, Dict -from fontTools.pens.basePen import AbstractPen, PenError -from fontTools.misc.transform import DecomposedTransform +from fontTools.misc.loggingTools import LogMixin +from fontTools.pens.basePen import AbstractPen, MissingComponentError, PenError +from fontTools.misc.transform import DecomposedTransform, Identity __all__ = [ "AbstractPointPen", @@ -523,3 +524,77 @@ class ReverseContourPointPen(AbstractPointPen): if self.currentContour is not None: raise PenError("Components must be added before or after contours") self.pen.addComponent(glyphName, transform, identifier=identifier, **kwargs) + + +class DecomposingPointPen(LogMixin, AbstractPointPen): + """Implements a 'addComponent' method that decomposes components + (i.e. draws them onto self as simple contours). + It can also be used as a mixin class (e.g. see DecomposingRecordingPointPen). + + You must override beginPath, addPoint, endPath. You may + additionally override addVarComponent and addComponent. + + By default a warning message is logged when a base glyph is missing; + set the class variable ``skipMissingComponents`` to False if you want + all instances of a sub-class to raise a :class:`MissingComponentError` + exception by default. + """ + + skipMissingComponents = True + # alias error for convenience + MissingComponentError = MissingComponentError + + def __init__( + self, + glyphSet, + *args, + skipMissingComponents=None, + reverseFlipped=False, + **kwargs, + ): + """Takes a 'glyphSet' argument (dict), in which the glyphs that are referenced + as components are looked up by their name. + + If the optional 'reverseFlipped' argument is True, components whose transformation + matrix has a negative determinant will be decomposed with a reversed path direction + to compensate for the flip. + + The optional 'skipMissingComponents' argument can be set to True/False to + override the homonymous class attribute for a given pen instance. + """ + super().__init__(*args, **kwargs) + self.glyphSet = glyphSet + self.skipMissingComponents = ( + self.__class__.skipMissingComponents + if skipMissingComponents is None + else skipMissingComponents + ) + self.reverseFlipped = reverseFlipped + + def addComponent(self, baseGlyphName, transformation, identifier=None, **kwargs): + """Transform the points of the base glyph and draw it onto self. + + The `identifier` parameter and any extra kwargs are ignored. + """ + from fontTools.pens.transformPen import TransformPointPen + + try: + glyph = self.glyphSet[baseGlyphName] + except KeyError: + if not self.skipMissingComponents: + raise MissingComponentError(baseGlyphName) + self.log.warning( + "glyph '%s' is missing from glyphSet; skipped" % baseGlyphName + ) + else: + pen = self + if transformation != Identity: + pen = TransformPointPen(pen, transformation) + if self.reverseFlipped: + # if the transformation has a negative determinant, it will + # reverse the contour direction of the component + a, b, c, d = transformation[:4] + det = a * d - b * c + if a * d - b * c < 0: + pen = ReverseContourPointPen(pen) + glyph.drawPoints(pen) diff --git a/contrib/python/fonttools/fontTools/pens/recordingPen.py b/contrib/python/fonttools/fontTools/pens/recordingPen.py index 4f44a4d59f..ba165e1951 100644 --- a/contrib/python/fonttools/fontTools/pens/recordingPen.py +++ b/contrib/python/fonttools/fontTools/pens/recordingPen.py @@ -1,13 +1,14 @@ """Pen recording operations that can be accessed or replayed.""" from fontTools.pens.basePen import AbstractPen, DecomposingPen -from fontTools.pens.pointPen import AbstractPointPen +from fontTools.pens.pointPen import AbstractPointPen, DecomposingPointPen __all__ = [ "replayRecording", "RecordingPen", "DecomposingRecordingPen", + "DecomposingRecordingPointPen", "RecordingPointPen", "lerpRecordings", ] @@ -85,28 +86,55 @@ class DecomposingRecordingPen(DecomposingPen, RecordingPen): """Same as RecordingPen, except that it doesn't keep components as references, but draws them decomposed as regular contours. - The constructor takes a single 'glyphSet' positional argument, + The constructor takes a required 'glyphSet' positional argument, a dictionary of glyph objects (i.e. with a 'draw' method) keyed - by thir name:: - - >>> class SimpleGlyph(object): - ... def draw(self, pen): - ... pen.moveTo((0, 0)) - ... pen.curveTo((1, 1), (2, 2), (3, 3)) - ... pen.closePath() - >>> class CompositeGlyph(object): - ... def draw(self, pen): - ... pen.addComponent('a', (1, 0, 0, 1, -1, 1)) - >>> glyphSet = {'a': SimpleGlyph(), 'b': CompositeGlyph()} - >>> for name, glyph in sorted(glyphSet.items()): - ... pen = DecomposingRecordingPen(glyphSet) - ... glyph.draw(pen) - ... print("{}: {}".format(name, pen.value)) - a: [('moveTo', ((0, 0),)), ('curveTo', ((1, 1), (2, 2), (3, 3))), ('closePath', ())] - b: [('moveTo', ((-1, 1),)), ('curveTo', ((0, 2), (1, 3), (2, 4))), ('closePath', ())] + by thir name; other arguments are forwarded to the DecomposingPen's + constructor:: + + >>> class SimpleGlyph(object): + ... def draw(self, pen): + ... pen.moveTo((0, 0)) + ... pen.curveTo((1, 1), (2, 2), (3, 3)) + ... pen.closePath() + >>> class CompositeGlyph(object): + ... def draw(self, pen): + ... pen.addComponent('a', (1, 0, 0, 1, -1, 1)) + >>> class MissingComponent(object): + ... def draw(self, pen): + ... pen.addComponent('foobar', (1, 0, 0, 1, 0, 0)) + >>> class FlippedComponent(object): + ... def draw(self, pen): + ... pen.addComponent('a', (-1, 0, 0, 1, 0, 0)) + >>> glyphSet = { + ... 'a': SimpleGlyph(), + ... 'b': CompositeGlyph(), + ... 'c': MissingComponent(), + ... 'd': FlippedComponent(), + ... } + >>> for name, glyph in sorted(glyphSet.items()): + ... pen = DecomposingRecordingPen(glyphSet) + ... try: + ... glyph.draw(pen) + ... except pen.MissingComponentError: + ... pass + ... print("{}: {}".format(name, pen.value)) + a: [('moveTo', ((0, 0),)), ('curveTo', ((1, 1), (2, 2), (3, 3))), ('closePath', ())] + b: [('moveTo', ((-1, 1),)), ('curveTo', ((0, 2), (1, 3), (2, 4))), ('closePath', ())] + c: [] + d: [('moveTo', ((0, 0),)), ('curveTo', ((-1, 1), (-2, 2), (-3, 3))), ('closePath', ())] + >>> for name, glyph in sorted(glyphSet.items()): + ... pen = DecomposingRecordingPen( + ... glyphSet, skipMissingComponents=True, reverseFlipped=True, + ... ) + ... glyph.draw(pen) + ... print("{}: {}".format(name, pen.value)) + a: [('moveTo', ((0, 0),)), ('curveTo', ((1, 1), (2, 2), (3, 3))), ('closePath', ())] + b: [('moveTo', ((-1, 1),)), ('curveTo', ((0, 2), (1, 3), (2, 4))), ('closePath', ())] + c: [] + d: [('moveTo', ((0, 0),)), ('lineTo', ((-3, 3),)), ('curveTo', ((-2, 2), (-1, 1), (0, 0))), ('closePath', ())] """ - # raises KeyError if base glyph is not found in glyphSet + # raises MissingComponentError(KeyError) if base glyph is not found in glyphSet skipMissingComponents = False @@ -174,6 +202,96 @@ class RecordingPointPen(AbstractPointPen): drawPoints = replay +class DecomposingRecordingPointPen(DecomposingPointPen, RecordingPointPen): + """Same as RecordingPointPen, except that it doesn't keep components + as references, but draws them decomposed as regular contours. + + The constructor takes a required 'glyphSet' positional argument, + a dictionary of pointPen-drawable glyph objects (i.e. with a 'drawPoints' method) + keyed by thir name; other arguments are forwarded to the DecomposingPointPen's + constructor:: + + >>> from pprint import pprint + >>> class SimpleGlyph(object): + ... def drawPoints(self, pen): + ... pen.beginPath() + ... pen.addPoint((0, 0), "line") + ... pen.addPoint((1, 1)) + ... pen.addPoint((2, 2)) + ... pen.addPoint((3, 3), "curve") + ... pen.endPath() + >>> class CompositeGlyph(object): + ... def drawPoints(self, pen): + ... pen.addComponent('a', (1, 0, 0, 1, -1, 1)) + >>> class MissingComponent(object): + ... def drawPoints(self, pen): + ... pen.addComponent('foobar', (1, 0, 0, 1, 0, 0)) + >>> class FlippedComponent(object): + ... def drawPoints(self, pen): + ... pen.addComponent('a', (-1, 0, 0, 1, 0, 0)) + >>> glyphSet = { + ... 'a': SimpleGlyph(), + ... 'b': CompositeGlyph(), + ... 'c': MissingComponent(), + ... 'd': FlippedComponent(), + ... } + >>> for name, glyph in sorted(glyphSet.items()): + ... pen = DecomposingRecordingPointPen(glyphSet) + ... try: + ... glyph.drawPoints(pen) + ... except pen.MissingComponentError: + ... pass + ... pprint({name: pen.value}) + {'a': [('beginPath', (), {}), + ('addPoint', ((0, 0), 'line', False, None), {}), + ('addPoint', ((1, 1), None, False, None), {}), + ('addPoint', ((2, 2), None, False, None), {}), + ('addPoint', ((3, 3), 'curve', False, None), {}), + ('endPath', (), {})]} + {'b': [('beginPath', (), {}), + ('addPoint', ((-1, 1), 'line', False, None), {}), + ('addPoint', ((0, 2), None, False, None), {}), + ('addPoint', ((1, 3), None, False, None), {}), + ('addPoint', ((2, 4), 'curve', False, None), {}), + ('endPath', (), {})]} + {'c': []} + {'d': [('beginPath', (), {}), + ('addPoint', ((0, 0), 'line', False, None), {}), + ('addPoint', ((-1, 1), None, False, None), {}), + ('addPoint', ((-2, 2), None, False, None), {}), + ('addPoint', ((-3, 3), 'curve', False, None), {}), + ('endPath', (), {})]} + >>> for name, glyph in sorted(glyphSet.items()): + ... pen = DecomposingRecordingPointPen( + ... glyphSet, skipMissingComponents=True, reverseFlipped=True, + ... ) + ... glyph.drawPoints(pen) + ... pprint({name: pen.value}) + {'a': [('beginPath', (), {}), + ('addPoint', ((0, 0), 'line', False, None), {}), + ('addPoint', ((1, 1), None, False, None), {}), + ('addPoint', ((2, 2), None, False, None), {}), + ('addPoint', ((3, 3), 'curve', False, None), {}), + ('endPath', (), {})]} + {'b': [('beginPath', (), {}), + ('addPoint', ((-1, 1), 'line', False, None), {}), + ('addPoint', ((0, 2), None, False, None), {}), + ('addPoint', ((1, 3), None, False, None), {}), + ('addPoint', ((2, 4), 'curve', False, None), {}), + ('endPath', (), {})]} + {'c': []} + {'d': [('beginPath', (), {}), + ('addPoint', ((0, 0), 'curve', False, None), {}), + ('addPoint', ((-3, 3), 'line', False, None), {}), + ('addPoint', ((-2, 2), None, False, None), {}), + ('addPoint', ((-1, 1), None, False, None), {}), + ('endPath', (), {})]} + """ + + # raises MissingComponentError(KeyError) if base glyph is not found in glyphSet + skipMissingComponents = False + + def lerpRecordings(recording1, recording2, factor=0.5): """Linearly interpolate between two recordings. The recordings must be decomposed, i.e. they must not contain any components. diff --git a/contrib/python/fonttools/fontTools/varLib/instancer/__init__.py b/contrib/python/fonttools/fontTools/varLib/instancer/__init__.py index 89427dc534..c5de81cad0 100644 --- a/contrib/python/fonttools/fontTools/varLib/instancer/__init__.py +++ b/contrib/python/fonttools/fontTools/varLib/instancer/__init__.py @@ -531,9 +531,13 @@ def changeTupleVariationsAxisLimits(variations, axisLimits): def changeTupleVariationAxisLimit(var, axisTag, axisLimit): assert isinstance(axisLimit, NormalizedAxisTripleAndDistances) - # Skip when current axis is missing (i.e. doesn't participate), + # Skip when current axis is missing or peaks at 0 (i.e. doesn't participate) lower, peak, upper = var.axes.get(axisTag, (-1, 0, 1)) if peak == 0: + # explicitly defined, no-op axes can be omitted + # https://github.com/fonttools/fonttools/issues/3453 + if axisTag in var.axes: + del var.axes[axisTag] return [var] # Drop if the var 'tent' isn't well-formed if not (lower <= peak <= upper) or (lower < 0 and upper > 0): diff --git a/contrib/python/fonttools/ya.make b/contrib/python/fonttools/ya.make index e5986f9d03..a6872287a9 100644 --- a/contrib/python/fonttools/ya.make +++ b/contrib/python/fonttools/ya.make @@ -2,7 +2,7 @@ PY3_LIBRARY() -VERSION(4.49.0) +VERSION(4.50.0) LICENSE(MIT) |