Source code for fontParts.base.groups

from fontParts.base.base import BaseDict, dynamicProperty, reference
from fontParts.base import normalizers
from fontParts.base.deprecated import DeprecatedGroups, RemovedGroups


[docs]class BaseGroups(BaseDict, DeprecatedGroups, RemovedGroups): """ A Groups object. This object normally created as part of a :class:`BaseFont`. An orphan Groups object can be created like this:: >>> groups = RGroups() This object behaves like a Python dictionary. Most of the dictionary functionality comes from :class:`BaseDict`, look at that object for the required environment implementation details. Groups uses :func:`normalizers.normalizeGroupKey` to normalize the key of the ``dict``, and :func:`normalizers.normalizeGroupValue` to normalize the value of the ``dict``. """ keyNormalizer = normalizers.normalizeGroupKey valueNormalizer = normalizers.normalizeGroupValue def _reprContents(self): contents = [] if self.font is not None: contents.append("for font") contents += self.font._reprContents() return contents # ------- # Parents # ------- # Font _font = None font = dynamicProperty("font", "The Groups' parent :class:`BaseFont`.") def _get_font(self): if self._font is None: return None return self._font() def _set_font(self, font): if self._font is not None and self._font != font: raise AssertionError("font for groups already set and is not same as font") if font is not None: font = reference(font) self._font = font # --------- # Searching # ---------
[docs] def findGlyph(self, glyphName): """ Returns a ``list`` of the group or groups associated with **glyphName**. **glyphName** will be an :ref:`type-string`. If no group is found to contain **glyphName** an empty ``list`` will be returned. :: >>> font.groups.findGlyph("A") ["A_accented"] """ glyphName = normalizers.normalizeGlyphName(glyphName) groupNames = self._findGlyph(glyphName) groupNames = [self.keyNormalizer.__func__( groupName) for groupName in groupNames] return groupNames
[docs] def _findGlyph(self, glyphName): """ This is the environment implementation of :meth:`BaseGroups.findGlyph`. **glyphName** will be an :ref:`type-string`. Subclasses may override this method. """ found = [] for key, groupList in self.items(): if glyphName in groupList: found.append(key) return found
# -------------- # Kerning Groups # -------------- side1KerningGroups = dynamicProperty( "base_side1KerningGroups", """ All groups marked as potential side 1 kerning members. >>> side1Groups = groups.side1KerningGroups The value will be a :ref:`dict` with :ref:`string` keys representing group names and :ref:`tuple` contaning glyph names. """ ) def _get_base_side1KerningGroups(self): kerningGroups = self._get_side1KerningGroups() normalized = {} for name, members in kerningGroups.items(): name = normalizers.normalizeGroupKey(name) members = normalizers.normalizeGroupValue(members) normalized[name] = members return normalized def _get_side1KerningGroups(self): """ Subclasses may override this method. """ found = {} for name, contents in self.items(): if name.startswith("public.kern1."): found[name] = contents return found side2KerningGroups = dynamicProperty( "base_side2KerningGroups", """ All groups marked as potential side 1 kerning members. >>> side2Groups = groups.side2KerningGroups The value will be a :ref:`dict` with :ref:`string` keys representing group names and :ref:`tuple` contaning glyph names. """ ) def _get_base_side2KerningGroups(self): kerningGroups = self._get_side2KerningGroups() normalized = {} for name, members in kerningGroups.items(): name = normalizers.normalizeGroupKey(name) members = normalizers.normalizeGroupValue(members) normalized[name] = members return normalized def _get_side2KerningGroups(self): """ Subclasses may override this method. """ found = {} for name, contents in self.items(): if name.startswith("public.kern2."): found[name] = contents return found # --------------------- # RoboFab Compatibility # --------------------- def remove(self, groupName): """ Removes a group from the Groups. **groupName** will be a :ref:`type-string` that is the group name to be removed. This is a backwards compatibility method. """ del self[groupName] def asDict(self): """ Return the Groups as a ``dict``. This is a backwards compatibility method. """ d = {} for k, v in self.items(): d[k] = v return d # ------------------- # Inherited Functions # -------------------
[docs] def __contains__(self, groupName): """ Tests to see if a group name is in the Groups. **groupName** will be a :ref:`type-string`. This returns a ``bool`` indicating if the **groupName** is in the Groups. :: >>> "myGroup" in font.groups True """ return super(BaseGroups, self).__contains__(groupName)
[docs] def __delitem__(self, groupName): """ Removes **groupName** from the Groups. **groupName** is a :ref:`type-string`.:: >>> del font.groups["myGroup"] """ super(BaseGroups, self).__delitem__(groupName)
[docs] def __getitem__(self, groupName): """ Returns the contents of the named group. **groupName** is a :ref:`type-string`. The returned value will be a :ref:`type-immutable-list` of the group contents.:: >>> font.groups["myGroup"] ("A", "B", "C") It is important to understand that any changes to the returned group contents will not be reflected in the Groups object. If one wants to make a change to the group contents, one should do the following:: >>> group = font.groups["myGroup"] >>> group.remove("A") >>> font.groups["myGroup"] = group """ return super(BaseGroups, self).__getitem__(groupName)
[docs] def __iter__(self): """ Iterates through the Groups, giving the key for each iteration. The order that the Groups will iterate though is not fixed nor is it ordered.:: >>> for groupName in font.groups: >>> print groupName "myGroup" "myGroup3" "myGroup2" """ return super(BaseGroups, self).__iter__()
[docs] def __len__(self): """ Returns the number of groups in Groups as an ``int``.:: >>> len(font.groups) 5 """ return super(BaseGroups, self).__len__()
[docs] def __setitem__(self, groupName, glyphNames): """ Sets the **groupName** to the list of **glyphNames**. **groupName** is the group name as a :ref:`type-string` and **glyphNames** is a ``list`` of glyph names as :ref:`type-string`. >>> font.groups["myGroup"] = ["A", "B", "C"] """ super(BaseGroups, self).__setitem__(groupName, glyphNames)
[docs] def clear(self): """ Removes all group information from Groups, resetting the Groups to an empty dictionary. :: >>> font.groups.clear() """ super(BaseGroups, self).clear()
[docs] def get(self, groupName, default=None): """ Returns the contents of the named group. **groupName** is a :ref:`type-string`, and the returned values will either be :ref:`type-immutable-list` of group contents or ``None`` if no group was found. :: >>> font.groups["myGroup"] ("A", "B", "C") It is important to understand that any changes to the returned group contents will not be reflected in the Groups object. If one wants to make a change to the group contents, one should do the following:: >>> group = font.groups["myGroup"] >>> group.remove("A") >>> font.groups["myGroup"] = group """ return super(BaseGroups, self).get(groupName, default)
[docs] def items(self): """ Returns a list of ``tuple`` of each group name and group members. Group names are :ref:`type-string` and group members are a :ref:`type-immutable-list` of :ref:`type-string`. The initial list will be unordered. >>> font.groups.items() [("myGroup", ("A", "B", "C"), ("myGroup2", ("D", "E", "F"))] """ return super(BaseGroups, self).items()
[docs] def keys(self): """ Returns a ``list`` of all the group names in Groups. This list will be unordered.:: >>> font.groups.keys() ["myGroup4", "myGroup1", "myGroup5"] """ return super(BaseGroups, self).keys()
[docs] def pop(self, groupName, default=None): """ Removes the **groupName** from the Groups and returns the list of group members. If no group is found, **default** is returned. **groupName** is a :ref:`type-string`. This must return either **default** or a :ref:`type-immutable-list` of glyph names as :ref:`type-string`. >>> font.groups.pop("myGroup") ("A", "B", "C") """ return super(BaseGroups, self).pop(groupName, default)
[docs] def update(self, otherGroups): """ Updates the Groups based on **otherGroups**. *otherGroups** is a ``dict`` of groups information. If a group from **otherGroups** is in Groups, the group members will be replaced by the group members from **otherGroups**. If a group from **otherGroups** is not in the Groups, it is added to the Groups. If Groups contain a group name that is not in *otherGroups**, it is not changed. >>> font.groups.update(newGroups) """ super(BaseGroups, self).update(otherGroups)
[docs] def values(self): """ Returns a ``list`` of each named group's members. This will be a list of lists, the group members will be a :ref:`type-immutable-list` of :ref:`type-string`. The initial list will be unordered. >>> font.groups.items() [("A", "B", "C"), ("D", "E", "F")] """ return super(BaseGroups, self).values()