Source code for fontParts.base.normalizers

# -*- coding: utf8 -*-

from collections import Counter
from fontTools.misc.fixedTools import otRound

# ----
# Font
# ----


[docs] def normalizeFileFormatVersion(value): """ Normalizes a font's file format version. * **value** must be a :ref:`type-int`. * Returned value will be a ``int``. """ if not isinstance(value, int): raise TypeError("File format versions must be instances of " ":ref:`type-int`, not %s." % type(value).__name__) return value
def normalizeFileStructure(value): """ Normalizes a font's file structure. * **value** must be a :ref:`type-string`. * Returned value will be a ``string``. """ allowedFileStructures = ["zip", "package"] if value not in allowedFileStructures: raise TypeError("File Structure must be %s, not %s" % (", ".join(allowedFileStructures), value)) return value
[docs] def normalizeLayerOrder(value, font): """ Normalizes layer order. ** **value** must be a ``tuple`` or ``list``. * **value** items must normalize as layer names with :func:`normalizeLayerName`. * **value** must contain layers that exist in **font**. * **value** must not contain duplicate layers. * Returned ``tuple`` will be unencoded ``unicode`` strings for each layer name. """ if not isinstance(value, (tuple, list)): raise TypeError("Layer order must be a list, not %s." % type(value).__name__) for v in value: normalizeLayerName(v) fontLayers = [layer.name for layer in font.layers] for name in value: if name not in fontLayers: raise ValueError("Layer must exist in font. %s does not exist " "in font.layers." % name) duplicates = [v for v, count in Counter(value).items() if count > 1] if len(duplicates) != 0: raise ValueError("Duplicate layers are not allowed. Layer name(s) " "'%s' are duplicate(s)." % ", ".join(duplicates)) return tuple(value)
def normalizeDefaultLayerName(value, font): """ Normalizes default layer name. * **value** must normalize as layer name with :func:`normalizeLayerName`. * **value** must be a layer in **font**. * Returned value will be an unencoded ``unicode`` string. """ value = normalizeLayerName(value) if value not in font.layerOrder: raise ValueError("No layer with the name '%s' exists." % value) return str(value)
[docs] def normalizeGlyphOrder(value): """ Normalizes glyph order. ** **value** must be a ``tuple`` or ``list``. * **value** items must normalize as glyph names with :func:`normalizeGlyphName`. * **value** must not repeat glyph names. * Returned value will be a ``tuple`` of unencoded ``unicode`` strings. """ if not isinstance(value, (tuple, list)): raise TypeError("Glyph order must be a list, not %s." % type(value).__name__) for v in value: normalizeGlyphName(v) duplicates = sorted(v for v, count in Counter(value).items() if count > 1) if len(duplicates) != 0: raise ValueError("Duplicate glyph names are not allowed. Glyph " "name(s) '%s' are duplicate." % ", ".join(duplicates)) return tuple(value)
# ------- # Kerning # -------
[docs] def normalizeKerningKey(value): """ Normalizes kerning key. * **value** must be a ``tuple`` or ``list``. * **value** must contain only two members. * **value** items must be :ref:`type-string`. * **value** items must be at least one character long. * Returned value will be a two member ``tuple`` of unencoded ``unicode`` strings. """ if not isinstance(value, (tuple, list)): raise TypeError("Kerning key must be a tuple instance, not %s." % type(value).__name__) if len(value) != 2: raise ValueError("Kerning key must be a tuple containing two items, " "not %d." % len(value)) for v in value: if not isinstance(v, str): raise TypeError("Kerning key items must be strings, not %s." % type(v).__name__) if len(v) < 1: raise ValueError("Kerning key items must be at least one character long") if value[0].startswith("public.") and not value[0].startswith( "public.kern1."): raise ValueError("Left Kerning key group must start with " "public.kern1.") if value[1].startswith("public.") and not value[1].startswith( "public.kern2."): raise ValueError("Right Kerning key group must start with " "public.kern2.") return tuple(value)
[docs] def normalizeKerningValue(value): """ Normalizes kerning value. * **value** must be an :ref:`type-int-float`. * Returned value is the same type as input value. """ if not isinstance(value, (int, float)): raise TypeError("Kerning value must be a int or a float, not %s." % type(value).__name__) return value
# ------ # Groups # ------
[docs] def normalizeGroupKey(value): """ Normalizes group key. * **value** must be a :ref:`type-string`. * **value** must be least one character long. * Returned value will be an unencoded ``unicode`` string. """ if not isinstance(value, str): raise TypeError("Group key must be a string, not %s." % type(value).__name__) if len(value) < 1: raise ValueError("Group key must be at least one character long.") return value
[docs] def normalizeGroupValue(value): """ Normalizes group value. * **value** must be a ``list``. * **value** items must normalize as glyph names with :func:`normalizeGlyphName`. * Returned value will be a ``tuple`` of unencoded ``unicode`` strings. """ if not isinstance(value, (tuple, list)): raise TypeError("Group value must be a list, not %s." % type(value).__name__) value = [normalizeGlyphName(v) for v in value] return tuple(value)
# -------- # Features # --------
[docs] def normalizeFeatureText(value): """ Normalizes feature text. * **value** must be a :ref:`type-string`. * Returned value will be an unencoded ``unicode`` string. """ if not isinstance(value, str): raise TypeError("Feature text must be a string, not %s." % type(value).__name__) return value
# --- # Lib # ---
[docs] def normalizeLibKey(value): """ Normalizes lib key. * **value** must be a :ref:`type-string`. * **value** must be at least one character long. * Returned value will be an unencoded ``unicode`` string. """ if not isinstance(value, str): raise TypeError("Lib key must be a string, not %s." % type(value).__name__) if len(value) < 1: raise ValueError("Lib key must be at least one character.") return value
[docs] def normalizeLibValue(value): """ Normalizes lib value. * **value** must not be ``None``. * Returned value is the same type as the input value. """ if value is None: raise ValueError("Lib value must not be None.") if isinstance(value, (list, tuple)): for v in value: normalizeLibValue(v) elif isinstance(value, dict): for k, v in value.items(): normalizeLibKey(k) normalizeLibValue(v) return value
# ----- # Layer # ----- def normalizeLayer(value): """ Normalizes layer. * **value** must be a instance of :class:`BaseLayer` * Returned value is the same type as the input value. """ from fontParts.base.layer import BaseLayer return normalizeInternalObjectType(value, BaseLayer, "Layer")
[docs] def normalizeLayerName(value): """ Normalizes layer name. * **value** must be a :ref:`type-string`. * **value** must be at least one character long. * Returned value will be an unencoded ``unicode`` string. """ if not isinstance(value, str): raise TypeError("Layer names must be strings, not %s." % type(value).__name__) if len(value) < 1: raise ValueError("Layer names must be at least one character long.") return value
# ----- # Glyph # ----- def normalizeGlyph(value): """ Normalizes glyph. * **value** must be a instance of :class:`BaseGlyph` * Returned value is the same type as the input value. """ from fontParts.base.glyph import BaseGlyph return normalizeInternalObjectType(value, BaseGlyph, "Glyph")
[docs] def normalizeGlyphName(value): """ Normalizes glyph name. * **value** must be a :ref:`type-string`. * **value** must be at least one character long. * Returned value will be an unencoded ``unicode`` string. """ if not isinstance(value, str): raise TypeError("Glyph names must be strings, not %s." % type(value).__name__) if len(value) < 1: raise ValueError("Glyph names must be at least one character long.") return value
[docs] def normalizeGlyphUnicodes(value): """ Normalizes glyph unicodes. * **value** must be a ``list``. * **value** items must normalize as glyph unicodes with :func:`normalizeGlyphUnicode`. * **value** must not repeat unicode values. * Returned value will be a ``tuple`` of ints. """ if not isinstance(value, (tuple, list)): raise TypeError("Glyph unicodes must be a list, not %s." % type(value).__name__) values = [normalizeGlyphUnicode(v) for v in value] duplicates = [v for v, count in Counter(value).items() if count > 1] if len(duplicates) != 0: raise ValueError("Duplicate unicode values are not allowed.") return tuple(values)
[docs] def normalizeGlyphUnicode(value): """ Normalizes glyph unicode. * **value** must be an int or hex (represented as a string). * **value** must be in a unicode range. * Returned value will be an ``int``. """ if not isinstance(value, (int, str)) or isinstance(value, bool): raise TypeError("Glyph unicode must be a int or hex string, not %s." % type(value).__name__) if isinstance(value, str): try: value = int(value, 16) except ValueError: raise ValueError("Glyph unicode hex must be a valid hex string.") if value < 0 or value > 1114111: raise ValueError("Glyph unicode must be in the Unicode range.") return value
[docs] def normalizeGlyphWidth(value): """ Normalizes glyph width. * **value** must be a :ref:`type-int-float`. * Returned value is the same type as the input value. """ if not isinstance(value, (int, float)): raise TypeError("Glyph width must be an :ref:`type-int-float`, not %s." % type(value).__name__) return value
[docs] def normalizeGlyphLeftMargin(value): """ Normalizes glyph left margin. * **value** must be a :ref:`type-int-float` or `None`. * Returned value is the same type as the input value. """ if not isinstance(value, (int, float)) and value is not None: raise TypeError("Glyph left margin must be an :ref:`type-int-float`, " "not %s." % type(value).__name__) return value
[docs] def normalizeGlyphRightMargin(value): """ Normalizes glyph right margin. * **value** must be a :ref:`type-int-float` or `None`. * Returned value is the same type as the input value. """ if not isinstance(value, (int, float)) and value is not None: raise TypeError("Glyph right margin must be an :ref:`type-int-float`, " "not %s." % type(value).__name__) return value
[docs] def normalizeGlyphHeight(value): """ Normalizes glyph height. * **value** must be a :ref:`type-int-float`. * Returned value is the same type as the input value. """ if not isinstance(value, (int, float)): raise TypeError("Glyph height must be an :ref:`type-int-float`, not " "%s." % type(value).__name__) return value
[docs] def normalizeGlyphBottomMargin(value): """ Normalizes glyph bottom margin. * **value** must be a :ref:`type-int-float` or `None`. * Returned value is the same type as the input value. """ if not isinstance(value, (int, float)) and value is not None: raise TypeError("Glyph bottom margin must be an " ":ref:`type-int-float`, not %s." % type(value).__name__) return value
[docs] def normalizeGlyphTopMargin(value): """ Normalizes glyph top margin. * **value** must be a :ref:`type-int-float` or `None`. * Returned value is the same type as the input value. """ if not isinstance(value, (int, float)) and value is not None: raise TypeError("Glyph top margin must be an :ref:`type-int-float`, " "not %s." % type(value).__name__) return value
def normalizeGlyphFormatVersion(value): """ Normalizes glyph format version for saving to XML string. * **value** must be a :ref:`type-int-float` of either 1 or 2. * Returned value will be an int. """ if not isinstance(value, (int, float)): raise TypeError("Glyph Format Version must be an " ":ref:`type-int-float`, not %s." % type(value).__name__) value = int(value) if value not in (1, 2): raise ValueError("Glyph Format Version must be either 1 or 2, not %s." % value) return value # ------- # Contour # -------
[docs] def normalizeContour(value): """ Normalizes contour. * **value** must be a instance of :class:`BaseContour` * Returned value is the same type as the input value. """ from fontParts.base.contour import BaseContour return normalizeInternalObjectType(value, BaseContour, "Contour")
# ----- # Point # -----
[docs] def normalizePointType(value): """ Normalizes point type. * **value** must be an string. * **value** must be one of the following: +----------+ | move | +----------+ | line | +----------+ | offcurve | +----------+ | curve | +----------+ | qcurve | +----------+ * Returned value will be an unencoded ``unicode`` string. """ allowedTypes = ['move', 'line', 'offcurve', 'curve', 'qcurve'] if not isinstance(value, str): raise TypeError("Point type must be a string, not %s." % type(value).__name__) if value not in allowedTypes: raise ValueError("Point type must be '%s'; not %r." % ("', '".join(allowedTypes), value)) return value
[docs] def normalizePointName(value): """ Normalizes point name. * **value** must be a :ref:`type-string`. * **value** must be at least one character long. * Returned value will be an unencoded ``unicode`` string. """ if not isinstance(value, str): raise TypeError("Point names must be strings, not %s." % type(value).__name__) if len(value) < 1: raise ValueError("Point names must be at least one character long.") return value
def normalizePoint(value): """ Normalizes point. * **value** must be a instance of :class:`BasePoint` * Returned value is the same type as the input value. """ from fontParts.base.point import BasePoint return normalizeInternalObjectType(value, BasePoint, "Point") # ------- # Segment # ------- def normalizeSegment(value): """ Normalizes segment. * **value** must be a instance of :class:`BaseSegment` * Returned value is the same type as the input value. """ from fontParts.base.segment import BaseSegment return normalizeInternalObjectType(value, BaseSegment, "Segment")
[docs] def normalizeSegmentType(value): """ Normalizes segment type. * **value** must be a :ref:`type-string`. * **value** must be one of the following: +--------+ | move | +--------+ | line | +--------+ | curve | +--------+ | qcurve | +--------+ * Returned value will be an unencoded ``unicode`` string. """ allowedTypes = ['move', 'line', 'curve', 'qcurve'] if not isinstance(value, str): raise TypeError("Segment type must be a string, not %s." % type(value).__name__) if value not in allowedTypes: raise ValueError("Segment type must be '%s'; not %r." % ("', '".join(allowedTypes), value)) return value
# ------ # BPoint # ------ def normalizeBPoint(value): """ Normalizes bPoint. * **value** must be a instance of :class:`BaseBPoint` * Returned value is the same type as the input value. """ from fontParts.base.bPoint import BaseBPoint return normalizeInternalObjectType(value, BaseBPoint, "bPoint")
[docs] def normalizeBPointType(value): """ Normalizes bPoint type. * **value** must be an string. * **value** must be one of the following: +--------+ | corner | +--------+ | curve | +--------+ * Returned value will be an unencoded ``unicode`` string. """ allowedTypes = ['corner', 'curve'] if not isinstance(value, str): raise TypeError("bPoint type must be a string, not %s." % type(value).__name__) if value not in allowedTypes: raise ValueError("bPoint type must be 'corner' or 'curve', not %r." % value) return value
# --------- # Component # --------- def normalizeComponent(value): """ Normalizes component. * **value** must be a instance of :class:`BaseComponent` * Returned value is the same type as the input value. """ from fontParts.base.component import BaseComponent return normalizeInternalObjectType(value, BaseComponent, "Component") def normalizeComponentScale(value): """ Normalizes component scale. * **value** must be a `tuple`` or ``list``. * **value** must have exactly two items. These items must be instances of :ref:`type-int-float`. * Returned value is a ``tuple`` of two ``float``\s. """ if not isinstance(value, (list, tuple)): raise TypeError("Component scale must be a tuple " "instance, not %s." % type(value).__name__) else: if not len(value) == 2: raise ValueError("Transformation scale tuple must contain two " "values, not %d." % len(value)) for v in value: if not isinstance(v, (int, float)): raise TypeError("Transformation scale tuple values must be an " ":ref:`type-int-float`, not %s." % type(value).__name__) value = tuple([float(v) for v in value]) return value # ------ # Anchor # ------ def normalizeAnchor(value): """ Normalizes anchor. * **value** must be a instance of :class:`BaseAnchor` * Returned value is the same type as the input value. """ from fontParts.base.anchor import BaseAnchor return normalizeInternalObjectType(value, BaseAnchor, "Anchor")
[docs] def normalizeAnchorName(value): """ Normalizes anchor name. * **value** must be a :ref:`type-string` or ``None``. * **value** must be at least one character long if :ref:`type-string`. * Returned value will be an unencoded ``unicode`` string or ``None``. """ if value is None: return None if not isinstance(value, str): raise TypeError("Anchor names must be strings, not %s." % type(value).__name__) if len(value) < 1: raise ValueError(("Anchor names must be at least one character " "long or None.")) return value
# --------- # Guideline # --------- def normalizeGuideline(value): """ Normalizes guideline. * **value** must be a instance of :class:`BaseGuideline` * Returned value is the same type as the input value. """ from fontParts.base.guideline import BaseGuideline return normalizeInternalObjectType(value, BaseGuideline, "Guideline")
[docs] def normalizeGuidelineName(value): """ Normalizes guideline name. * **value** must be a :ref:`type-string`. * **value** must be at least one character long. * Returned value will be an unencoded ``unicode`` string. """ if not isinstance(value, str): raise TypeError("Guideline names must be strings, not %s." % type(value).__name__) if len(value) < 1: raise ValueError("Guideline names must be at least one character " "long.") return value
# ------- # Generic # ------- def normalizeInternalObjectType(value, cls, name): """ Normalizes an internal object type. * **value** must be a instance of **cls**. * Returned value is the same type as the input value. """ if not isinstance(value, cls): raise TypeError("%s must be a %s instance, not %s." % (name, name, type(value).__name__)) return value
[docs] def normalizeBoolean(value): """ Normalizes a boolean. * **value** must be an ``int`` with value of 0 or 1, or a ``bool``. * Returned value will be a boolean. """ if isinstance(value, int) and value in (0, 1): value = bool(value) if not isinstance(value, bool): raise ValueError("Boolean values must be True or False, not '%s'." % value) return value
# Identification
[docs] def normalizeIndex(value): """ Normalizes index. * **value** must be an ``int`` or ``None``. * Returned value is the same type as the input value. """ if value is not None: if not isinstance(value, int): raise TypeError("Indexes must be None or integers, not %s." % type(value).__name__) return value
[docs] def normalizeIdentifier(value): """ Normalizes identifier. * **value** must be an :ref:`type-string` or `None`. * **value** must not be longer than 100 characters. * **value** must not contain a character out the range of 0x20 - 0x7E. * Returned value is an unencoded ``unicode`` string. """ if value is None: return value if not isinstance(value, str): raise TypeError("Identifiers must be strings, not %s." % type(value).__name__) if len(value) == 0: raise ValueError("The identifier string is empty.") if len(value) > 100: raise ValueError("The identifier string has a length (%d) greater " "than the maximum allowed (100)." % len(value)) for c in value: v = ord(c) if v < 0x20 or v > 0x7E: raise ValueError("The identifier string ('%s') contains a " "character out size of the range 0x20 - 0x7E." % value) return value
# Coordinates
[docs] def normalizeX(value): """ Normalizes x coordinate. * **value** must be an :ref:`type-int-float`. * Returned value is the same type as the input value. """ if not isinstance(value, (int, float)): raise TypeError("X coordinates must be instances of " ":ref:`type-int-float`, not %s." % type(value).__name__) return value
[docs] def normalizeY(value): """ Normalizes y coordinate. * **value** must be an :ref:`type-int-float`. * Returned value is the same type as the input value. """ if not isinstance(value, (int, float)): raise TypeError("Y coordinates must be instances of " ":ref:`type-int-float`, not %s." % type(value).__name__) return value
[docs] def normalizeCoordinateTuple(value): """ Normalizes coordinate tuple. * **value** must be a ``tuple`` or ``list``. * **value** must have exactly two items. * **value** items must be an :ref:`type-int-float`. * Returned value is a ``tuple`` of two values of the same type as the input values. """ if not isinstance(value, (tuple, list)): raise TypeError("Coordinates must be tuple instances, not %s." % type(value).__name__) if len(value) != 2: raise ValueError("Coordinates must be tuples containing two items, " "not %d." % len(value)) x, y = value x = normalizeX(x) y = normalizeY(y) return (x, y)
[docs] def normalizeBoundingBox(value): """ Normalizes bounding box. * **value** must be an ``tuple`` or ``list``. * **value** must have exactly four items. * **value** items must be :ref:`type-int-float`. * xMin and yMin must be less than or equal to the corresponding xMax, yMax. * Returned value will be a tuple of four ``float``. """ if not isinstance(value, (tuple, list)): raise TypeError("Bounding box be tuple instances, not %s." % type(value).__name__) if len(value) != 4: raise ValueError("Bounding box be tuples containing four items, not " "%d." % len(value)) for v in value: if not isinstance(v, (int, float)): raise TypeError("Bounding box values must be instances of " ":ref:`type-int-float`, not %s." % type(value).__name__) if value[0] > value[2]: raise ValueError("Bounding box xMin must be less than or equal to " "xMax.") if value[1] > value[3]: raise ValueError("Bounding box yMin must be less than or equal to " "yMax.") return tuple([float(v) for v in value])
def normalizeArea(value): """ Normalizes area. * **value** must be a positive :ref:`type-int-float`. """ if not isinstance(value, (int, float)): raise TypeError("Area must be an instance of :ref:`type-int-float`, " "not %s." % type(value).__name__) if value < 0: raise ValueError("Area must be a positive :ref:`type-int-float`, " "not %s." % repr(value)) return float(value) def normalizeRotationAngle(value): """ Normalizes an angle. * Value must be a :ref:`type-int-float`. * Value must be between -360 and 360. * If the value is negative, it is normalized by adding it to 360 * Returned value is a ``float`` between 0 and 360. """ if not isinstance(value, (int, float)): raise TypeError("Angle must be instances of " ":ref:`type-int-float`, not %s." % type(value).__name__) if abs(value) > 360: raise ValueError("Angle must be between -360 and 360.") if value < 0: value = value + 360 return float(value) # Color
[docs] def normalizeColor(value): """ Normalizes :ref:`type-color`. * **value** must be an ``tuple`` or ``list``. * **value** must have exactly four items. * **value** color components must be between 0 and 1. * Returned value is a ``tuple`` containing four ``float`` values. """ from fontParts.base.color import Color if not isinstance(value, (tuple, list, Color)): raise TypeError("Colors must be tuple instances, not %s." % type(value).__name__) if not len(value) == 4: raise ValueError("Colors must contain four values, not %d." % len(value)) for component, v in zip("rgba", value): if not isinstance(v, (int, float)): raise TypeError("The value for the %s component (%s) is not " "an int or float." % (component, v)) if v < 0 or v > 1: raise ValueError("The value for the %s component (%s) is not " "between 0 and 1." % (component, v)) return tuple([float(v) for v in value])
# Note
[docs] def normalizeGlyphNote(value): """ Normalizes Glyph Note. * **value** must be a :ref:`type-string`. * Returned value is an unencoded ``unicode`` string """ if not isinstance(value, str): raise TypeError("Note must be a string, not %s." % type(value).__name__) return value
# File Path
[docs] def normalizeFilePath(value): """ Normalizes file path. * **value** must be a :ref:`type-string`. * Returned value is an unencoded ``unicode`` string """ if not isinstance(value, str): raise TypeError("File paths must be strings, not %s." % type(value).__name__) return value
# Interpolation
[docs] def normalizeInterpolationFactor(value): """ Normalizes interpolation factor. * **value** must be an :ref:`type-int-float`, ``tuple`` or ``list``. * If **value** is a ``tuple`` or ``list``, it must have exactly two items. These items must be instances of :ref:`type-int-float`. * Returned value is a ``tuple`` of two ``float``. """ if not isinstance(value, (int, float, list, tuple)): raise TypeError("Interpolation factor must be an int, float, or tuple " "instances, not %s." % type(value).__name__) if isinstance(value, (int, float)): value = (float(value), float(value)) else: if not len(value) == 2: raise ValueError("Interpolation factor tuple must contain two " "values, not %d." % len(value)) for v in value: if not isinstance(v, (int, float)): raise TypeError("Interpolation factor tuple values must be an " ":ref:`type-int-float`, not %s." % type(value).__name__) value = tuple([float(v) for v in value]) return value
# --------------- # Transformations # ---------------
[docs] def normalizeTransformationMatrix(value): """ Normalizes transformation matrix. * **value** must be an ``tuple`` or ``list``. * **value** must have exactly six items. Each of these items must be an instance of :ref:`type-int-float`. * Returned value is a ``tuple`` of six ``float``. """ if not isinstance(value, (tuple, list)): raise TypeError("Transformation matrices must be tuple instances, " "not %s." % type(value).__name__) if not len(value) == 6: raise ValueError("Transformation matrices must contain six values, " "not %d." % len(value)) for v in value: if not isinstance(v, (int, float)): raise TypeError("Transformation matrix values must be instances " "of :ref:`type-int-float`, not %s." % type(v).__name__) return tuple([float(v) for v in value])
[docs] def normalizeTransformationOffset(value): """ Normalizes transformation offset. * **value** must be an ``tuple``. * **value** must have exactly two items. Each item must be an instance of :ref:`type-int-float`. * Returned value is a ``tuple`` of two ``float``. """ return normalizeCoordinateTuple(value)
[docs] def normalizeTransformationSkewAngle(value): """ Normalizes transformation skew angle. * **value** must be an :ref:`type-int-float`, ``tuple`` or ``list``. * If **value** is a ``tuple`` or ``list``, it must have exactly two items. These items must be instances of :ref:`type-int-float`. * **value** items must be between -360 and 360. * If the value is negative, it is normalized by adding it to 360 * Returned value is a ``tuple`` of two ``float`` between 0 and 360. """ if not isinstance(value, (int, float, list, tuple)): raise TypeError("Transformation skew angle must be an int, float, or " "tuple instances, not %s." % type(value).__name__) if isinstance(value, (int, float)): value = (float(value), 0) else: if not len(value) == 2: raise ValueError("Transformation skew angle tuple must contain " "two values, not %d." % len(value)) for v in value: if not isinstance(v, (int, float)): raise TypeError("Transformation skew angle tuple values must " "be an :ref:`type-int-float`, not %s." % type(value).__name__) value = tuple([float(v) for v in value]) for v in value: if abs(v) > 360: raise ValueError("Transformation skew angle must be between -360 " "and 360.") return tuple([float(v + 360) if v < 0 else float(v) for v in value])
[docs] def normalizeTransformationScale(value): """ Normalizes transformation scale. * **value** must be an :ref:`type-int-float`, ``tuple`` or ``list``. * If **value** is a ``tuple`` or ``list``, it must have exactly two items. These items must be instances of :ref:`type-int-float`. * Returned value is a ``tuple`` of two ``float``\s. """ if not isinstance(value, (int, float, list, tuple)): raise TypeError("Transformation scale must be an int, float, or tuple " "instances, not %s." % type(value).__name__) if isinstance(value, (int, float)): value = (float(value), float(value)) else: if not len(value) == 2: raise ValueError("Transformation scale tuple must contain two " "values, not %d." % len(value)) for v in value: if not isinstance(v, (int, float)): raise TypeError("Transformation scale tuple values must be an " ":ref:`type-int-float`, not %s." % type(value).__name__) value = tuple([float(v) for v in value]) return value
def normalizeVisualRounding(value): """ Normalizes rounding. Python 3 uses banker’s rounding, meaning anything that is at 0.5 will go to the even number. This isn't always ideal for point coordinates, so instead round to the higher number. * **value** must be an :ref:`type-int-float` * Returned value is a ``int`` """ if not isinstance(value, (int, float)): raise TypeError("Value to round must be an int or float, not %s." % type(value).__name__) return otRound(value)