<commit_before>import os
from copy import deepcopy
from fontTools.misc.py23 import basestring
from fontParts.base.errors import FontPartsError
from fontParts.base.base import (
    BaseObject,
    TransformationMixin,
    InterpolationMixin,
    SelectionMixin,
    dynamicProperty,
    interpolate
)
from fontParts.base import normalizers
from fontParts.base.compatibility import GlyphCompatibilityReporter
from fontParts.base.color import Color
from fontParts.base.deprecated import DeprecatedGlyph, RemovedGlyph


class BaseGlyph(BaseObject,
                TransformationMixin,
                InterpolationMixin,
                SelectionMixin,
                DeprecatedGlyph,
                RemovedGlyph
                ):

    """
    A glyph object. This object will almost always
    be created by retrieving it from a font object.
    """

    copyAttributes = (
        "name",
        "unicodes",
        "width",
        "height",
        "note",
        "markColor",
        "lib"
    )

    def _reprContents(self):
        contents = [
            "'%s'" % self.name,
        ]
        if self.layer is not None:
            contents.append("('%s')" % self.layer.name)
        return contents

    def __hash__(self):
        """
        Allow glyph object to be used as a key
        in a dictionary.

        Subclasses may override this method.
        """
        return id(self.naked())

    def copy(self):
        """
        Copy this glyph's data into a new glyph object.
        This new glyph object will not belong to a font.

            >>> copiedGlyph = glyph.copy()

        This will copy:

        - name
        - unicodes
        - width
        - height
        - note
        - markColor
        - lib
        - contours
        - components
        - anchors
        - guidelines
        - image
        """
        return super(BaseGlyph, self).copy()

    def copyData(self, source):
        super(BaseGlyph, self).copyData(source)
        pen = self.getPointPen()
        source.drawPoints(pen)
        for sourceAnchor in source.anchors:
            self.appendAnchor(
                sourceAnchor.name,
                (sourceAnchor.x, sourceAnchor.y),
                sourceAnchor.color
            )
        for sourceGuideline in source.guidelines:
            self.appendGuideline(
                (sourceGuideline.x, sourceGuideline.y),
                sourceGuideline.angle,
                sourceGuideline.name,
                sourceGuideline.color
            )
        sourceImage = source.image
        if sourceImage.data is not None:
            selfImage = self.addImage(data=sourceImage.data)
            selfImage.transformation = sourceImage.transformation
            selfImage.color = sourceImage.color

    # -------
    # Parents
    # -------

    # Layer

    _layer = None

    layer = dynamicProperty(
        "layer",
        """
        The glyph's parent layer.

            >>> layer = glyph.layer
        """
    )

    def _get_layer(self):
        if self._layer is None:
            return None
        return self._layer

    def _set_layer(self, layer):
        self._layer = layer

    # Font

    font = dynamicProperty(
        "font",
        """
        The glyph's parent font.

            >>> font = glyph.font
        """
    )

    def _get_font(self):
        if self._layer is None:
            return None
        return self.layer.font

    # --------------
    # Identification
    # --------------

    # Name

    name = dynamicProperty(
        "base_name",
        """
        The glyph's name. This will be a :ref:`type-string`.

            >>> glyph.name
            "A"
            >>> glyph.name = "A.alt"
        """
    )

    def _get_base_name(self):
        value = self._get_name()
        if value is not None:
            value = normalizers.normalizeGlyphName(value)
        return value

    def _set_base_name(self, value):
        if value == self.name:
            return
        value = normalizers.normalizeGlyphName(value)
        layer = self.layer
        if layer is not None and value in layer:
            raise ValueError("A glyph with the name '%s' already exists."
                             % value)
        self._set_name(value)

    def _get_name(self):
        """
        Get the name of the glyph.
        This must return a unicode string.

        Subclasses must override this method.
        """
        self.raiseNotImplementedError()

    def _set_name(self, value):
        """
        Set the name of the glyph.
        This will be a unicode string.

        Subclasses must override this method.
        """
        self.raiseNotImplementedError()

    # Unicodes

    unicodes = dynamicProperty(
        "base_unicodes",
        """
        The glyph's unicode values in order from most to least important.

            >>> glyph.unicodes
            (65,)
            >>> glyph.unicodes = [65, 66]
            >>> glyph.unicodes = []

        The values in the returned tuple will be :ref:`type-int`.
        When setting you may use a list of :ref:`type-int` or
        :ref:`type-hex` values.
        """
    )

    def _get_base_unicodes(self):
        value = self._get_unicodes()
        value = normalizers.normalizeGlyphUnicodes(value)
        return value

    def _set_base_unicodes(self, value):
        value = list(value)
        value = normalizers.normalizeGlyphUnicodes(value)
        self._set_unicodes(value)

    def _get_unicodes(self):
        """
        Get the unicodes assigned to the glyph.
        This must return a tuple of zero or more integers.

        Subclasses must override this method.
        """
        self.raiseNotImplementedError()

    def _set_unicodes(self, value):
        """
        Assign the unicodes to the glyph.
        This will be a list of zero or more integers.

        Subclasses must override this method.
        """
        self.raiseNotImplementedError()

    unicode = dynamicProperty(
        "base_unicode",
        """
        The glyph's primary unicode value.

            >>> glyph.unicode
            65
            >>> glyph.unicode = None

        The returned value will be an :ref:`type-int` or ``None``.
        When setting you may send :ref:`type-int` or :ref:`type-hex`
        values or ``None``.
        """
    )

    def _get_base_unicode(self):
        value = self._get_unicode()
        if value is not None:
            value = normalizers.normalizeGlyphUnicode(value)
        return value

    def _set_base_unicode(self, value):
        if value is not None:
            value = normalizers.normalizeGlyphUnicode(value)
            self._set_unicode(value)
        else:
            self._set_unicodes(())

    def _get_unicode(self):
        """
        Get the primary unicode assigned to the glyph.
        This must return an integer or None.

        Subclasses may override this method.
        """
        values = self.unicodes
        if values:
            return values[0]
        return None

    def _set_unicode(self, value):
        """
        Assign the primary unicode to the glyph.
        This will be an integer or None.

        Subclasses may override this method.
        """
        values = list(self.unicodes)
        if value in values:
            values.remove(value)
        values.insert(0, value)
        self.unicodes = values

    def autoUnicodes(self):
        """
        Use heuristics to set the Unicode values in the glyph.

            >>> glyph.autoUnicodes()

        Environments will define their own heuristics for
        automatically determining values.
        """
        self._autoUnicodes()

    def _autoUnicodes(self):
        """
        Subclasses must override this method.
        """
        self.raiseNotImplementedError()

    # -------
    # Metrics
    # -------

    # horizontal

    width = dynamicProperty(
        "base_width",
        """
        The glyph's width.

            >>> glyph.width
            500
            >>> glyph.width = 200

        The value will be a :ref:`type-int-float`.
        """
    )

    def _get_base_width(self):
        value = self._get_width()
        value = normalizers.normalizeGlyphWidth(value)
        return value

    def _set_base_width(self, value):
        value = normalizers.normalizeGlyphWidth(value)
        self._set_width(value)

    def _get_width(self):
        """
        This must return an int or float.

        Subclasses must override this method.
        """
        self.raiseNotImplementedError()

    def _set_width(self, value):
        """
        value will be an int or float.

        Subclasses must override this method.
        """
        self.raiseNotImplementedError()

    leftMargin = dynamicProperty(
        "base_leftMargin",
        """
        The glyph's left margin.

            >>> glyph.leftMargin
            35
            >>> glyph.leftMargin = 45

        The value will be a :ref:`type-int-float`.
        """
    )

    def _get_base_leftMargin(self):
        value = self._get_leftMargin()
        value = normalizers.normalizeGlyphLeftMargin(value)
        return value

    def _set_base_leftMargin(self, value):
        value = normalizers.normalizeGlyphLeftMargin(value)
        self._set_leftMargin(value)

    def _get_leftMargin(self):
        """
        This must return an int or float.

        Subclasses may override this method.
        """
        bounds = self.bounds
        if bounds is None:
            return 0
        xMin, yMin, xMax, yMax = bounds
        return xMin

    def _set_leftMargin(self, value):
        """
        value will be an int or float.

        Subclasses may override this method.
        """
        diff = value - self.leftMargin
        self.moveBy((diff, 0))
        self.width += diff

    rightMargin = dynamicProperty(
        "base_rightMargin",
        """
        The glyph's right margin.

            >>> glyph.rightMargin
            35
            >>> glyph.rightMargin = 45

        The value will be a :ref:`type-int-float`.
        """
    )

    def _get_base_rightMargin(self):
        value = self._get_rightMargin()
        value = normalizers.normalizeGlyphRightMargin(value)
        return value

    def _set_base_rightMargin(self, value):
        value = normalizers.normalizeGlyphRightMargin(value)
        self._set_rightMargin(value)

    def _get_rightMargin(self):
        """
        This must return an int or float.

        Subclasses may override this method.
        """
        bounds = self.bounds
        if bounds is None:
            return self.width
        xMin, yMin, xMax, yMax = bounds
        return self.width - xMax

    def _set_rightMargin(self, value):
        """
        value will be an int or float.

        Subclasses may override this method.
        """
        bounds = self.bounds
        if bounds is None:
            self.width = value
        else:
            xMin, yMin, xMax, yMax = bounds
            self.width = xMax + value

    # vertical

    height = dynamicProperty(
        "base_height",
        """
        The glyph's height.

            >>> glyph.height
            500
            >>> glyph.height = 200

        The value will be a :ref:`type-int-float`.
        """
    )

    def _get_base_height(self):
        value = self._get_height()
        value = normalizers.normalizeGlyphHeight(value)
        return value

    def _set_base_height(self, value):
        value = normalizers.normalizeGlyphHeight(value)
        self._set_height(value)

    def _get_height(self):
        """
        This must return an int or float.

        Subclasses must override this method.
        """
        self.raiseNotImplementedError()

    def _set_height(self, value):
        """
        value will be an int or float.

        Subclasses must override this method.
        """
        self.raiseNotImplementedError()

    bottomMargin = dynamicProperty(
        "base_bottomMargin",
        """
        The glyph's bottom margin.

            >>> glyph.bottomMargin
            35
            >>> glyph.bottomMargin = 45

        The value will be a :ref:`type-int-float`.
        """
    )

    def _get_base_bottomMargin(self):
        value = self._get_bottomMargin()
        value = normalizers.normalizeGlyphBottomMargin(value)
        return value

    def _set_base_bottomMargin(self, value):
        value = normalizers.normalizeGlyphBottomMargin(value)
        self._set_bottomMargin(value)

    def _get_bottomMargin(self):
        """
        This must return an int or float.

        Subclasses may override this method.
        """
        bounds = self.bounds
        if bounds is None:
            return 0
        xMin, yMin, xMax, yMax = bounds
        return yMin

    def _set_bottomMargin(self, value):
        """
        value will be an int or float.

        Subclasses may override this method.
        """
        diff = value - self.bottomMargin
        self.moveBy((0, diff))
        self.height += diff

    topMargin = dynamicProperty(
        "base_topMargin",
        """
        The glyph's top margin.

            >>> glyph.topMargin
            35
            >>> glyph.topMargin = 45

        The value will be a :ref:`type-int-float`.
        """
    )

    def _get_base_topMargin(self):
        value = self._get_topMargin()
        value = normalizers.normalizeGlyphTopMargin(value)
        return value

    def _set_base_topMargin(self, value):
        value = normalizers.normalizeGlyphTopMargin(value)
        self._set_topMargin(value)

    def _get_topMargin(self):
        """
        This must return an int or float.

        Subclasses may override this method.
        """
        bounds = self.bounds
        if bounds is None:
            return self.height
        xMin, yMin, xMax, yMax = bounds
        return self.height - yMax

    def _set_topMargin(self, value):
        """
        value will be an int or float.

        Subclasses may override this method.
        """
        bounds = self.bounds
        if bounds is None:
            self.height = value
        else:
            xMin, yMin, xMax, yMax = bounds
            self.height = yMax + value

    # ----
    # Pens
    # ----

    def getPen(self):
        """
        Return a :ref:`type-pen` object for adding outline data
        to the glyph.

            >>> pen = glyph.getPen()
        """
        self.raiseNotImplementedError()

    def getPointPen(self):
        """
        Return a :ref:`type-pointpen` object for adding outline data
        to the glyph.

            >>> pointPen = glyph.getPointPen()
        """
        self.raiseNotImplementedError()

    def draw(self, pen, contours=True, components=True):
        """
        Draw the glyph's outline data (contours and components) to
        the given :ref:`type-pen`.

            >>> glyph.draw(pen)

        If ``contours`` is set to ``False``, the glyph's
        contours will not be drawn.

            >>> glyph.draw(pen, contours=False)

        If ``components`` is set to ``False``, the glyph's
        components will not be drawn.

            >>> glyph.draw(pen, components=False)
        """
        if contours:
            for contour in self:
                contour.draw(pen)
        if components:
            for component in self.components:
                component.draw(pen)

    def drawPoints(self, pen, contours=True, components=True):
        """
        Draw the glyph's outline data (contours and components) to
        the given :ref:`type-pointpen`.

            >>> glyph.drawPoints(pointPen)

        If ``contours`` is set to ``False``, the glyph's
        contours will not be drawn.

            >>> glyph.drawPoints(pointPen, contours=False)

        If ``components`` is set to ``False``, the glyph's
        components will not be drawn.

            >>> glyph.drawPoints(pointPen, components=False)
        """
        if contours:
            for contour in self:
                contour.drawPoints(pen)
        if components:
            for component in self.components:
                component.drawPoints(pen)

    # -----------------------------------------
    # Contour, Component and Anchor Interaction
    # -----------------------------------------

    def clear(self, contours=True, components=True, anchors=True,
              guidelines=True, image=True):
        """
        Clear the glyph.

            >>> glyph.clear()

        This clears:

        - contours
        - components
        - anchors
        - guidelines
        - image

        It's possible to turn off the clearing of portions of
        the glyph with the listed arguments.

            >>> glyph.clear(guidelines=False)
        """
        self._clear(contours=contours, components=components,
                    anchors=anchors, guidelines=guidelines, image=image)

    def _clear(self, contours=True, components=True, anchors=True,
               guidelines=True, image=True):
        """
        Subclasses may override this method.
        """
        if contours:
            self.clearContours()
        if components:
            self.clearComponents()
        if anchors:
            self.clearAnchors()
        if guidelines:
            self.clearGuidelines()
        if image:
            self.clearImage()

    def appendGlyph(self, other, offset=None):
        """
        Append the data from ``other`` to new objects in this glyph.
        This will append:

        - contours
        - components
        - anchors
        - guidelines

            >>> glyph.appendGlyph(otherGlyph)

        ``offset`` indicates the x and y shift values that should
        be applied to the appended data. It must be a :ref:`type-coordinate`
        value or ``None``. If ``None`` is given, the offset will be ``(0, 0)``.

            >>> glyph.appendGlyph(otherGlyph, (100, 0))
        """
        if offset is None:
            offset = (0, 0)
        offset = normalizers.normalizeTransformationOffset(offset)
        self._appendGlyph(other, offset)

    def _appendGlyph(self, other, offset=None):
        """
        Subclasses may override this method.
        """
        other = other.copy()
        if offset != (0, 0):
            other.moveBy(offset)
        pen = self.getPointPen()
        other.drawPoints(pen)
        for anchor in other.anchors:
            self.appendAnchor(
                anchor.name,
                (anchor.x, anchor.y),
                anchor.color
            )
        for guideline in other.guidelines:
            self.appendGuideline(
                (guideline.x, guideline.y),
                guideline.angle,
                guideline.name,
                guideline.color
            )

    # Contours
<commit_msg>Don't use drawPoints in copyData and appendGlyph.<commit_after>import os
from copy import deepcopy
from fontTools.misc.py23 import basestring
from fontParts.base.errors import FontPartsError
from fontParts.base.base import (
    BaseObject,
    TransformationMixin,
    InterpolationMixin,
    SelectionMixin,
    dynamicProperty,
    interpolate
)
from fontParts.base import normalizers
from fontParts.base.compatibility import GlyphCompatibilityReporter
from fontParts.base.color import Color
from fontParts.base.deprecated import DeprecatedGlyph, RemovedGlyph


class BaseGlyph(BaseObject,
                TransformationMixin,
                InterpolationMixin,
                SelectionMixin,
                DeprecatedGlyph,
                RemovedGlyph
                ):

    """
    A glyph object. This object will almost always
    be created by retrieving it from a font object.
    """

    copyAttributes = (
        "name",
        "unicodes",
        "width",
        "height",
        "note",
        "markColor",
        "lib"
    )

    def _reprContents(self):
        contents = [
            "'%s'" % self.name,
        ]
        if self.layer is not None:
            contents.append("('%s')" % self.layer.name)
        return contents

    def __hash__(self):
        """
        Allow glyph object to be used as a key
        in a dictionary.

        Subclasses may override this method.
        """
        return id(self.naked())

    def copy(self):
        """
        Copy this glyph's data into a new glyph object.
        This new glyph object will not belong to a font.

            >>> copiedGlyph = glyph.copy()

        This will copy:

        - name
        - unicodes
        - width
        - height
        - note
        - markColor
        - lib
        - contours
        - components
        - anchors
        - guidelines
        - image
        """
        return super(BaseGlyph, self).copy()

    def copyData(self, source):
        super(BaseGlyph, self).copyData(source)
        for contour in source.contours:
            contour = contour.copy()
            self.appendContour(contour)
        for component in source.components:
            c = self.appendComponent(component.baseGlyph)
            c.transformation = component.transformation
        for sourceAnchor in source.anchors:
            self.appendAnchor(
                sourceAnchor.name,
                (sourceAnchor.x, sourceAnchor.y),
                sourceAnchor.color
            )
        for sourceGuideline in source.guidelines:
            self.appendGuideline(
                (sourceGuideline.x, sourceGuideline.y),
                sourceGuideline.angle,
                sourceGuideline.name,
                sourceGuideline.color
            )
        sourceImage = source.image
        if sourceImage.data is not None:
            selfImage = self.addImage(data=sourceImage.data)
            selfImage.transformation = sourceImage.transformation
            selfImage.color = sourceImage.color

    # -------
    # Parents
    # -------

    # Layer

    _layer = None

    layer = dynamicProperty(
        "layer",
        """
        The glyph's parent layer.

            >>> layer = glyph.layer
        """
    )

    def _get_layer(self):
        if self._layer is None:
            return None
        return self._layer

    def _set_layer(self, layer):
        self._layer = layer

    # Font

    font = dynamicProperty(
        "font",
        """
        The glyph's parent font.

            >>> font = glyph.font
        """
    )

    def _get_font(self):
        if self._layer is None:
            return None
        return self.layer.font

    # --------------
    # Identification
    # --------------

    # Name

    name = dynamicProperty(
        "base_name",
        """
        The glyph's name. This will be a :ref:`type-string`.

            >>> glyph.name
            "A"
            >>> glyph.name = "A.alt"
        """
    )

    def _get_base_name(self):
        value = self._get_name()
        if value is not None:
            value = normalizers.normalizeGlyphName(value)
        return value

    def _set_base_name(self, value):
        if value == self.name:
            return
        value = normalizers.normalizeGlyphName(value)
        layer = self.layer
        if layer is not None and value in layer:
            raise ValueError("A glyph with the name '%s' already exists."
                             % value)
        self._set_name(value)

    def _get_name(self):
        """
        Get the name of the glyph.
        This must return a unicode string.

        Subclasses must override this method.
        """
        self.raiseNotImplementedError()

    def _set_name(self, value):
        """
        Set the name of the glyph.
        This will be a unicode string.

        Subclasses must override this method.
        """
        self.raiseNotImplementedError()

    # Unicodes

    unicodes = dynamicProperty(
        "base_unicodes",
        """
        The glyph's unicode values in order from most to least important.

            >>> glyph.unicodes
            (65,)
            >>> glyph.unicodes = [65, 66]
            >>> glyph.unicodes = []

        The values in the returned tuple will be :ref:`type-int`.
        When setting you may use a list of :ref:`type-int` or
        :ref:`type-hex` values.
        """
    )

    def _get_base_unicodes(self):
        value = self._get_unicodes()
        value = normalizers.normalizeGlyphUnicodes(value)
        return value

    def _set_base_unicodes(self, value):
        value = list(value)
        value = normalizers.normalizeGlyphUnicodes(value)
        self._set_unicodes(value)

    def _get_unicodes(self):
        """
        Get the unicodes assigned to the glyph.
        This must return a tuple of zero or more integers.

        Subclasses must override this method.
        """
        self.raiseNotImplementedError()

    def _set_unicodes(self, value):
        """
        Assign the unicodes to the glyph.
        This will be a list of zero or more integers.

        Subclasses must override this method.
        """
        self.raiseNotImplementedError()

    unicode = dynamicProperty(
        "base_unicode",
        """
        The glyph's primary unicode value.

            >>> glyph.unicode
            65
            >>> glyph.unicode = None

        The returned value will be an :ref:`type-int` or ``None``.
        When setting you may send :ref:`type-int` or :ref:`type-hex`
        values or ``None``.
        """
    )

    def _get_base_unicode(self):
        value = self._get_unicode()
        if value is not None:
            value = normalizers.normalizeGlyphUnicode(value)
        return value

    def _set_base_unicode(self, value):
        if value is not None:
            value = normalizers.normalizeGlyphUnicode(value)
            self._set_unicode(value)
        else:
            self._set_unicodes(())

    def _get_unicode(self):
        """
        Get the primary unicode assigned to the glyph.
        This must return an integer or None.

        Subclasses may override this method.
        """
        values = self.unicodes
        if values:
            return values[0]
        return None

    def _set_unicode(self, value):
        """
        Assign the primary unicode to the glyph.
        This will be an integer or None.

        Subclasses may override this method.
        """
        values = list(self.unicodes)
        if value in values:
            values.remove(value)
        values.insert(0, value)
        self.unicodes = values

    def autoUnicodes(self):
        """
        Use heuristics to set the Unicode values in the glyph.

            >>> glyph.autoUnicodes()

        Environments will define their own heuristics for
        automatically determining values.
        """
        self._autoUnicodes()

    def _autoUnicodes(self):
        """
        Subclasses must override this method.
        """
        self.raiseNotImplementedError()

    # -------
    # Metrics
    # -------

    # horizontal

    width = dynamicProperty(
        "base_width",
        """
        The glyph's width.

            >>> glyph.width
            500
            >>> glyph.width = 200

        The value will be a :ref:`type-int-float`.
        """
    )

    def _get_base_width(self):
        value = self._get_width()
        value = normalizers.normalizeGlyphWidth(value)
        return value

    def _set_base_width(self, value):
        value = normalizers.normalizeGlyphWidth(value)
        self._set_width(value)

    def _get_width(self):
        """
        This must return an int or float.

        Subclasses must override this method.
        """
        self.raiseNotImplementedError()

    def _set_width(self, value):
        """
        value will be an int or float.

        Subclasses must override this method.
        """
        self.raiseNotImplementedError()

    leftMargin = dynamicProperty(
        "base_leftMargin",
        """
        The glyph's left margin.

            >>> glyph.leftMargin
            35
            >>> glyph.leftMargin = 45

        The value will be a :ref:`type-int-float`.
        """
    )

    def _get_base_leftMargin(self):
        value = self._get_leftMargin()
        value = normalizers.normalizeGlyphLeftMargin(value)
        return value

    def _set_base_leftMargin(self, value):
        value = normalizers.normalizeGlyphLeftMargin(value)
        self._set_leftMargin(value)

    def _get_leftMargin(self):
        """
        This must return an int or float.

        Subclasses may override this method.
        """
        bounds = self.bounds
        if bounds is None:
            return 0
        xMin, yMin, xMax, yMax = bounds
        return xMin

    def _set_leftMargin(self, value):
        """
        value will be an int or float.

        Subclasses may override this method.
        """
        diff = value - self.leftMargin
        self.moveBy((diff, 0))
        self.width += diff

    rightMargin = dynamicProperty(
        "base_rightMargin",
        """
        The glyph's right margin.

            >>> glyph.rightMargin
            35
            >>> glyph.rightMargin = 45

        The value will be a :ref:`type-int-float`.
        """
    )

    def _get_base_rightMargin(self):
        value = self._get_rightMargin()
        value = normalizers.normalizeGlyphRightMargin(value)
        return value

    def _set_base_rightMargin(self, value):
        value = normalizers.normalizeGlyphRightMargin(value)
        self._set_rightMargin(value)

    def _get_rightMargin(self):
        """
        This must return an int or float.

        Subclasses may override this method.
        """
        bounds = self.bounds
        if bounds is None:
            return self.width
        xMin, yMin, xMax, yMax = bounds
        return self.width - xMax

    def _set_rightMargin(self, value):
        """
        value will be an int or float.

        Subclasses may override this method.
        """
        bounds = self.bounds
        if bounds is None:
            self.width = value
        else:
            xMin, yMin, xMax, yMax = bounds
            self.width = xMax + value

    # vertical

    height = dynamicProperty(
        "base_height",
        """
        The glyph's height.

            >>> glyph.height
            500
            >>> glyph.height = 200

        The value will be a :ref:`type-int-float`.
        """
    )

    def _get_base_height(self):
        value = self._get_height()
        value = normalizers.normalizeGlyphHeight(value)
        return value

    def _set_base_height(self, value):
        value = normalizers.normalizeGlyphHeight(value)
        self._set_height(value)

    def _get_height(self):
        """
        This must return an int or float.

        Subclasses must override this method.
        """
        self.raiseNotImplementedError()

    def _set_height(self, value):
        """
        value will be an int or float.

        Subclasses must override this method.
        """
        self.raiseNotImplementedError()

    bottomMargin = dynamicProperty(
        "base_bottomMargin",
        """
        The glyph's bottom margin.

            >>> glyph.bottomMargin
            35
            >>> glyph.bottomMargin = 45

        The value will be a :ref:`type-int-float`.
        """
    )

    def _get_base_bottomMargin(self):
        value = self._get_bottomMargin()
        value = normalizers.normalizeGlyphBottomMargin(value)
        return value

    def _set_base_bottomMargin(self, value):
        value = normalizers.normalizeGlyphBottomMargin(value)
        self._set_bottomMargin(value)

    def _get_bottomMargin(self):
        """
        This must return an int or float.

        Subclasses may override this method.
        """
        bounds = self.bounds
        if bounds is None:
            return 0
        xMin, yMin, xMax, yMax = bounds
        return yMin

    def _set_bottomMargin(self, value):
        """
        value will be an int or float.

        Subclasses may override this method.
        """
        diff = value - self.bottomMargin
        self.moveBy((0, diff))
        self.height += diff

    topMargin = dynamicProperty(
        "base_topMargin",
        """
        The glyph's top margin.

            >>> glyph.topMargin
            35
            >>> glyph.topMargin = 45

        The value will be a :ref:`type-int-float`.
        """
    )

    def _get_base_topMargin(self):
        value = self._get_topMargin()
        value = normalizers.normalizeGlyphTopMargin(value)
        return value

    def _set_base_topMargin(self, value):
        value = normalizers.normalizeGlyphTopMargin(value)
        self._set_topMargin(value)

    def _get_topMargin(self):
        """
        This must return an int or float.

        Subclasses may override this method.
        """
        bounds = self.bounds
        if bounds is None:
            return self.height
        xMin, yMin, xMax, yMax = bounds
        return self.height - yMax

    def _set_topMargin(self, value):
        """
        value will be an int or float.

        Subclasses may override this method.
        """
        bounds = self.bounds
        if bounds is None:
            self.height = value
        else:
            xMin, yMin, xMax, yMax = bounds
            self.height = yMax + value

    # ----
    # Pens
    # ----

    def getPen(self):
        """
        Return a :ref:`type-pen` object for adding outline data
        to the glyph.

            >>> pen = glyph.getPen()
        """
        self.raiseNotImplementedError()

    def getPointPen(self):
        """
        Return a :ref:`type-pointpen` object for adding outline data
        to the glyph.

            >>> pointPen = glyph.getPointPen()
        """
        self.raiseNotImplementedError()

    def draw(self, pen, contours=True, components=True):
        """
        Draw the glyph's outline data (contours and components) to
        the given :ref:`type-pen`.

            >>> glyph.draw(pen)

        If ``contours`` is set to ``False``, the glyph's
        contours will not be drawn.

            >>> glyph.draw(pen, contours=False)

        If ``components`` is set to ``False``, the glyph's
        components will not be drawn.

            >>> glyph.draw(pen, components=False)
        """
        if contours:
            for contour in self:
                contour.draw(pen)
        if components:
            for component in self.components:
                component.draw(pen)

    def drawPoints(self, pen, contours=True, components=True):
        """
        Draw the glyph's outline data (contours and components) to
        the given :ref:`type-pointpen`.

            >>> glyph.drawPoints(pointPen)

        If ``contours`` is set to ``False``, the glyph's
        contours will not be drawn.

            >>> glyph.drawPoints(pointPen, contours=False)

        If ``components`` is set to ``False``, the glyph's
        components will not be drawn.

            >>> glyph.drawPoints(pointPen, components=False)
        """
        if contours:
            for contour in self:
                contour.drawPoints(pen)
        if components:
            for component in self.components:
                component.drawPoints(pen)

    # -----------------------------------------
    # Contour, Component and Anchor Interaction
    # -----------------------------------------

    def clear(self, contours=True, components=True, anchors=True,
              guidelines=True, image=True):
        """
        Clear the glyph.

            >>> glyph.clear()

        This clears:

        - contours
        - components
        - anchors
        - guidelines
        - image

        It's possible to turn off the clearing of portions of
        the glyph with the listed arguments.

            >>> glyph.clear(guidelines=False)
        """
        self._clear(contours=contours, components=components,
                    anchors=anchors, guidelines=guidelines, image=image)

    def _clear(self, contours=True, components=True, anchors=True,
               guidelines=True, image=True):
        """
        Subclasses may override this method.
        """
        if contours:
            self.clearContours()
        if components:
            self.clearComponents()
        if anchors:
            self.clearAnchors()
        if guidelines:
            self.clearGuidelines()
        if image:
            self.clearImage()

    def appendGlyph(self, other, offset=None):
        """
        Append the data from ``other`` to new objects in this glyph.
        This will append:

        - contours
        - components
        - anchors
        - guidelines

            >>> glyph.appendGlyph(otherGlyph)

        ``offset`` indicates the x and y shift values that should
        be applied to the appended data. It must be a :ref:`type-coordinate`
        value or ``None``. If ``None`` is given, the offset will be ``(0, 0)``.

            >>> glyph.appendGlyph(otherGlyph, (100, 0))
        """
        if offset is None:
            offset = (0, 0)
        offset = normalizers.normalizeTransformationOffset(offset)
        self._appendGlyph(other, offset)

    def _appendGlyph(self, other, offset=None):
        """
        Subclasses may override this method.
        """
        other = other.copy()
        if offset != (0, 0):
            other.moveBy(offset)
        for contour in other.contours:
            contour = contour.copy()
            self.appendContour(contour)
        for component in other.components:
            c = self.appendComponent(component.baseGlyph)
            c.transformation = component.transformation
        for sourceAnchor in other.anchors:
            self.appendAnchor(
                sourceAnchor.name,
                (sourceAnchor.x, sourceAnchor.y),
                sourceAnchor.color
            )
        for sourceGuideline in other.guidelines:
            self.appendGuideline(
                (sourceGuideline.x, sourceGuideline.y),
                sourceGuideline.angle,
                sourceGuideline.name,
                sourceGuideline.color
            )

    # Contours

{'fraction_non_alphanumeric': 0.09448241548170844, 'fraction_numerical': 0.0028281876031110063, 'mean_word_length': 1.6434999307766855, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 213, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '785595', 'n_tokens_mistral': 10608, 'n_tokens_neox': 10042, 'n_words': 2856}