Commits

Manfred Moitzi committed 7a03c4b

added gradients module with tests and doc

  • Participants
  • Parent commits c73879e

Comments (0)

Files changed (31)

   * new elements:
 
     * Marker
+    * paint service: LinearGradient
+    * paint service: RadialGradient
 
 Version 0.2.0 - 24 October 2010
 

File doc/classes/base.rst

-:class:`BaseElement` objects
-============================
+:class:`BaseElement`
+====================
 
 .. autoclass:: svgwrite.base.BaseElement
 
 
 .. automethod:: svgwrite.base.BaseElement.get_xml()
 
+.. automethod:: svgwrite.base.BaseElement.get_id()
+
+.. automethod:: svgwrite.base.BaseElement.get_iri()
+
 .. automethod:: svgwrite.base.BaseElement.get_funciri()
 
 .. automethod:: svgwrite.base.BaseElement.__getitem__(key)

File doc/classes/defs.rst

-:class:`Defs` objects --- <defs>
-================================
+:class:`Defs`
+=============
 
 .. autoclass:: svgwrite.container.Defs
 

File doc/classes/drawing.rst

-:class:`Drawing` objects
-========================
+:class:`Drawing`
+================
 
 .. automodule:: svgwrite.drawing
 

File doc/classes/gradients.rst

+:mod:`gradients`
+================
+
+.. automodule:: svgwrite.gradients
+
+:class:`LinearGradient`
+-----------------------
+
+.. seealso:: http://www.w3.org/TR/SVG11/pservers.html#LinearGradients
+
+.. autoclass:: svgwrite.gradients.LinearGradient
+
+Methods
+~~~~~~~
+
+.. automethod:: svgwrite.gradients.LinearGradient.__init__(start=None, end=None, inherit=None, attribs=None, \*\*extra)
+
+.. automethod:: svgwrite.gradients.LinearGradient.add_stop_color(offset=None, color=None, opacity=None)
+
+.. automethod:: svgwrite.gradients.LinearGradient.get_paint_server()
+
+SVG Attributes
+~~~~~~~~~~~~~~
+
+* **gradientUnits** -- ``'userSpaceOnUse | objectBoundingBox'``
+
+  Defines the coordinate system for attributes **x1**, **y1**, **x2** and **y2**.
+
+  .. seealso:: http://www.w3.org/TR/SVG11/pservers.html#LinearGradientElementGradientUnitsAttribute
+
+* **gradientTransform** -- *<transform-list>*
+
+  Use the :class:`~svgwrite.interface.ITransform` interface to set transformations.
+
+  Contains the definition of an optional additional transformation from the
+  gradient coordinate system onto the target coordinate system (i.e.,
+  userSpaceOnUse or objectBoundingBox). This allows for things such as skewing
+  the gradient. This additional transformation matrix is post-multiplied to
+  (i.e., inserted to the right of) any previously defined transformations,
+  including the implicit transformation necessary to convert from object
+  bounding box units to user space.
+
+* **x1** -- *<coordinate>*
+
+  **x1**, **y1**, **x2** and **y2** define a gradient vector for the linear
+  gradient. This gradient vector provides starting and ending points onto
+  which the gradient stops are mapped. The values of **x1**, **y1**, **x2**
+  and **y2** can be either numbers or percentages.
+
+  default is ``'0%'``
+
+* **y1** -- *<coordinate>*
+
+  See **x1**. Default is ``'0%'``
+
+* **x2** -- *<coordinate>*
+
+  See **x1**. Default is ``'100%'``
+
+* **y2** -- *<coordinate>*
+
+  See **x1**. Default is ``'0%'``
+
+* **spreadMethod** -- ``'pad | reflect | repeat'``
+
+  Indicates what happens if the gradient starts or ends inside the bounds of
+  the target rectangle. Possible values are: ``'pad'``, which says to use the
+  terminal colors of the gradient to fill the remainder of the target region,
+  ``'reflect'``, which says to reflect the gradient pattern start-to-end,
+  end-to-start, start-to-end, etc. continuously until the target rectangle is
+  filled, and ``'repeat'``, which says to repeat the gradient pattern start-to-end,
+  start-to-end, start-to-end, etc. continuously until the target region is
+  filled.
+
+  default is ``'pad'``
+
+* **xlink:href** -- *<iri>* -- set by the 'inherit' parameter on :meth:`__init__`
+
+  A URI reference to a different :class:`LinearGradient` or :class:`RadialGradient`
+  element within the current SVG document fragment. Any :class:`LinearGradient`
+  attributes which are defined on the referenced element which are not defined
+  on this element are inherited by this element. If this element has no defined
+  gradient stops, and the referenced element does (possibly due to its own
+  **xlink:href** attribute), then this element inherits the gradient stop from
+  the referenced element. Inheritance can be indirect to an arbitrary level;
+  thus, if the referenced element inherits attribute or gradient stops due to
+  its own **xlink:href** attribute, then the current element can inherit those
+  attributes or gradient stops.
+
+:class:`RadialGradient`
+-----------------------
+
+.. seealso:: http://www.w3.org/TR/SVG11/pservers.html#RadialGradients
+
+.. autoclass:: svgwrite.gradients.RadialGradient
+
+Methods
+~~~~~~~
+
+.. automethod:: svgwrite.gradients.RadialGradient.__init__(center=None, r=None, focal=None, inherit=None, attribs=None, \*\*extra)
+
+.. automethod:: svgwrite.gradients.RadialGradient.add_stop_color(offset=None, color=None, opacity=None)
+
+.. automethod:: svgwrite.gradients.RadialGradient.get_paint_server()
+
+SVG Attributes
+~~~~~~~~~~~~~~
+
+* **gradientUnits** -- ``'userSpaceOnUse | objectBoundingBox'``
+
+  Defines the coordinate system for attributes **cx**, **cy**, **r**, **fx**
+  and **fy**.
+
+  .. seealso:: http://www.w3.org/TR/SVG11/pservers.html#RadialGradientElementGradientUnitsAttribute
+
+* **cx** -- *<coordinate>*
+
+  **cx**, **cy** and **r** define the largest (i.e., outermost) circle for
+  the radial gradient. The gradient will be drawn such that the 100% gradient
+  stop is mapped to the perimeter of this largest (i.e., outermost) circle.
+
+  default is ``'50%'``
+
+* **cy** -- *<coordinate>*
+
+  See **cx**. Default is ``'50%'``.
+
+* **r** -- *<length>*
+
+  See **cx**.
+
+  A value of zero will cause the area to be painted as a single color using
+  the color and opacity of the last gradient stop.
+
+  Default is ``'50%'``.
+
+* **fx** -- *<coordinate>*
+
+  **fx** and **fy** define the focal point for the radial gradient. The
+  gradient will be drawn such that the 0% gradient stop is mapped to (fx, fy).
+  If attribute **fx** is not specified, **fx** will coincide with the
+  presentational value of **cx** for the element whether the value for **cx**
+  was inherited or not. If the element references an element that specifies a
+  value for **fx**, then the value of 'fx' is inherited from the referenced
+  element.
+
+* **fy** -- *<coordinate>*
+
+  See **fx**.
+  If attribute **fy** is not specified, **fy** will coincide with the
+  presentational vlaue of **cy** for the element whether the value for **cy**
+  was inherited or not. If the element references an element that specifies a
+  value for **fy**, then the value of **fy** is inherited from the referenced
+  element.
+
+* **gradientTransform** -- *<transform-list>*
+
+  Use the :class:`~svgwrite.interface.ITransform` interface to set transformations.
+
+  See :class:`LinearGradient`
+
+* **spreadMethod** -- ``'pad | reflect | repeat'``
+
+  See :class:`LinearGradient`
+
+* **xlink:href** -- *<iri>* -- set by the 'inherit' parameter on :meth:`__init__`
+
+  See :class:`LinearGradient`

File doc/classes/group.rst

-:class:`Group` objects --- <g>
-==============================
+:class:`Group`
+==============
+
+The :class:`Group` represents the SVG <g> element.
 
 .. autoclass:: svgwrite.container.Group
 

File doc/classes/hyperlink.rst

-:class:`Hyperlink` objects --- <a>
-==================================
+:class:`Hyperlink`
+==================
+
+The :class:`Hyperlink` represents the SVG <a> element.
 
 .. autoclass:: svgwrite.container.Hyperlink
 

File doc/classes/image.rst

-:class:`Image` objects --- <image>
-==================================
+:class:`Image`
+==============
 
 .. autoclass:: svgwrite.image.Image
 

File doc/classes/marker.rst

-:class:`Marker` objects --- <marker>
-====================================
+:class:`Marker`
+===============
 
 .. autoclass:: svgwrite.container.Marker
 

File doc/classes/path.rst

-:class:`Path` objects --- <path>
-================================
+:class:`Path`
+=============
 
 The <path> element represent the outline of a shape which can be filled,
 stroked, used as a clipping path, or any combination of the three.

File doc/classes/shapes.rst

-:class:`Line` objects --- <line>
-================================
+:class:`Line`
+=============
 
 .. autoclass:: svgwrite.shapes.Line
 
 
     :meth:`set_markers`
 
-:class:`Rect` objects --- <rect>
-================================
+:class:`Rect`
+=============
 
 .. autoclass:: svgwrite.shapes.Rect
 
-:class:`Circle` objects --- <circle>
-====================================
+:class:`Circle`
+===============
 
 .. autoclass:: svgwrite.shapes.Circle
 
-:class:`Ellipse` objects --- <ellipse>
-======================================
+:class:`Ellipse`
+================
 
 .. autoclass:: svgwrite.shapes.Ellipse
 
-:class:`Polyline` objects --- <polyline>
-========================================
+:class:`Polyline`
+=================
 
 .. autoclass:: svgwrite.shapes.Polyline
 
 
     :meth:`set_markers`
 
-:class:`Polygon` objects --- <polygon>
-======================================
+:class:`Polygon`
+================
 
 .. autoclass:: svgwrite.shapes.Polygon
 

File doc/classes/svg.rst

-:class:`SVG` objects --- <svg>
-==============================
+:class:`SVG`
+============
 
 .. autoclass:: svgwrite.container.SVG
 

File doc/classes/symbol.rst

-:class:`Symbol` objects --- <symbol>
-====================================
+:class:`Symbol`
+===============
 
 .. autoclass:: svgwrite.container.Symbol
 

File doc/classes/text.rst

 
 .. automodule:: svgwrite.text
 
-:class:`Text` objects
-=====================
+:class:`Text`
+=============
 
 .. autoclass:: svgwrite.text.Text
 
 
     :meth:`fill`, :meth:`stroke`, :meth:`dasharray`
 
-:class:`TSpan` objects
-======================
+:class:`TSpan`
+==============
 
 .. autoclass:: svgwrite.text.TSpan
 
 * :doc:`Graphical Event Attributes </attributes/graphical_event>`
 * :doc:`Presentation Attributes </attributes/presentation>`
 
-:class:`TRef` objects
-=====================
+:class:`TRef`
+=============
 
 .. autoclass:: svgwrite.text.TRef
 
 * :doc:`Graphical Event Attributes </attributes/graphical_event>`
 * :doc:`Presentation Attributes </attributes/presentation>`
 
-:class:`TextPath` objects
-=========================
+:class:`TextPath`
+=================
 
 .. autoclass:: svgwrite.text.TextPath
 
 * :doc:`Graphical Event Attributes </attributes/graphical_event>`
 * :doc:`Presentation Attributes </attributes/presentation>`
 
-:class:`TextArea` objects
-=========================
+:class:`TextArea`
+=================
 
 .. autoclass:: svgwrite.text.TextArea
 

File doc/classes/use.rst

-:class:`Use` objects --- <use>
-===============================
+:class:`Use`
+============
 
 .. autoclass:: svgwrite.container.Use
 

File doc/index.rst

    svgwrite
    utils/utils
 
-Structural objects
+Structural Objects
 ------------------
 
 .. toctree::
    classes/use
    classes/hyperlink
 
-Graphical objects
+Graphical Objects
 -----------------
 
 .. toctree::
    classes/shapes
    classes/image
 
-Text objects
+Text Objects
 ------------
 
 .. toctree::
 
    classes/text
 
+Paint Server
+------------
+
+.. toctree::
+   :maxdepth: 1
+
+   classes/gradients
+
 Interfaces
 ----------
 
     dwg.save()
 
 def main():
-    longrun = False
+    longrun = True
     # short time running
     print("start short time running examples!\n")
 

File svgwrite/base.py

     def set_parameter(self, parameter):
         self._parameter = parameter
 
-    def nextid(self, value=None):
-        return AutoID.nextid(value)
+    def next_id(self, value=None):
+        return AutoID.next_id(value)
 
-    def get_funciri(self):
-        """
-        Get the `FuncIRI` reference string of the object. (e.g. ``'url(#id)'``).
+    def get_id(self):
+        """ Get the object `id` string, if the object does not have an `id`,
+        a new `id` will be created.
 
         :returns: `string`
         """
         if 'id' not in self.attribs:
-            self['id'] = self.nextid()
-        return "url(#%s)" % self['id']
+            self.attribs['id'] = self.next_id()
+        return self.attribs['id']
+
+    def get_iri(self):
+        """
+        Get the `IRI` reference string of the object. (i.e., ``'#id'``).
+
+        :returns: `string`
+        """
+        return "#%s" % self.get_id()
+
+    def get_funciri(self):
+        """
+        Get the `FuncIRI` reference string of the object. (i.e. ``'url(#id)'``).
+
+        :returns: `string`
+        """
+        return "url(%s)" % self.get_iri()
 
     def __getitem__(self, key):
         """ Get SVG attribute by `key`.

File svgwrite/container.py

         if orient is not None:
             self['orient'] = orient
         if 'id' not in self.attribs: # an 'id' is necessary
-            self['id'] = self.nextid()
+            self['id'] = self.next_id()
+        if self.debug:
+            self.validator.check_all_svg_attribute_values(self.elementname, self.attribs)
 
 class SVG(Symbol):
     """ An SVG document fragment consists of any number of SVG elements contained

File svgwrite/data/full11.py

     children=frozenset(['desc', 'metadata', 'title'])),
 
     'stop': SVGElement('stop',
-    attributes=frozenset(['a', 'c', 'xml:base', 'f', 'xml:space', 'l', 'o', 's', 'xml:lang', 't', 'y', 'e', 'id']),
+    attributes=frozenset(['xml:base', 'xml:space', 'xml:lang', 'offset', 'style', 'class']),
     properties=presentation_attributes,
     children=frozenset(['animate', 'set', 'animateColor'])),
 

File svgwrite/elementfactory.py

 import path
 import image
 import text
+import gradients
 
 factoryelements = {
     'g': container.Group,
     'tref': text.TRef,
     'textPath': text.TextPath,
     'textArea': text.TextArea,
+    'linearGradient': gradients.LinearGradient,
+    'radialGradient': gradients.RadialGradient,
 }
 
 class ElementBuilder(object):

File svgwrite/gradients.py

+#!/usr/bin/env python
+#coding:utf-8
+# Author:  mozman --<mozman@gmx.at>
+# Purpose: gradients module
+# Created: 26.10.2010
+# Copyright (C) 2010, Manfred Moitzi
+# License: GPLv3
+"""
+Gradients consist of continuously smooth color transitions along a vector
+from one color to another, possibly followed by additional transitions along
+the same vector to other colors. SVG provides for two types of gradients:
+linear gradients and radial gradients.
+
+.. seealso:: http://www.w3.org/TR/SVG11/pservers.html#Gradients
+
+"""
+
+from base import BaseElement
+from interface import ITransform, IXLink
+
+class _GradientStop(BaseElement):
+    elementname = 'stop'
+    def __init__(self, offset=None, color=None, opacity=None, **extra):
+        super(_GradientStop, self).__init__(**extra)
+
+        if offset is not None:
+            self['offset'] = offset
+        if color is not None:
+            self['stop-color'] = color
+        if opacity is not None:
+            self['stop-opacity'] = opacity
+
+        if self.debug:
+            self.validator.check_all_svg_attribute_values(self.elementname, self.attribs)
+
+
+class _AbstractGradient(BaseElement, ITransform, IXLink):
+    transformname = 'gradientTransform'
+    def __init__(self, inherit=None, attribs=None, **extra):
+        super(_AbstractGradient, self).__init__(attribs=attribs, **extra)
+        if inherit is not None:
+            if isinstance(inherit, basestring):
+                self.set_href(inherit)
+            else:
+                self.set_href(inherit.get_iri())
+
+    def get_paint_server(self):
+        """ Returns the <FuncIRI> of the gradient. """
+        return self.get_funciri()
+
+    def add_stop_color(self, offset=None, color=None, opacity=None):
+        """ Adds a stop-color to the gradient.
+
+        :param offset: is either a <number> (usually ranging from 0 to 1) or
+          a <percentage> (usually ranging from 0% to 100%) which indicates where
+          the gradient stop is placed. Represents a location along the gradient
+          vector. For radial gradients, it represents a percentage distance from
+          (fx,fy) to the edge of the outermost/largest circle.
+        :param color: indicates what color to use at that gradient stop
+        :param opacity: defines the opacity of a given gradient stop
+        """
+        self.add(_GradientStop(offset, color, opacity, factory=self))
+
+    def get_xml(self):
+        if hasattr(self, 'href'):
+            self.update_id()
+        return super(_AbstractGradient, self).get_xml()
+
+class LinearGradient(_AbstractGradient):
+    """ Linear gradients are defined by a SVG <linearGradient> element.
+    """
+    elementname = 'linearGradient'
+    def __init__(self, start=None, end=None, inherit=None, attribs=None, **extra):
+        """
+        :param 2-tuple start: start point of the gradient (**x1**, **y1**)
+        :param 2-tuple end: end point of the gradient (**x2**, **y2**)
+        :param inherit: gradient inherits properties from `inherit` see: **xlink:href**
+
+        """
+        super(LinearGradient, self).__init__(inherit=inherit, attribs=attribs, **extra)
+        if start is not None:
+            self['x1'] = start[0]
+            self['y1'] = start[1]
+        if end is not None:
+            self['x2'] = end[0]
+            self['y2'] = end[1]
+
+        if self.debug:
+            self.validator.check_all_svg_attribute_values(self.elementname, self.attribs)
+
+class RadialGradient(_AbstractGradient):
+    """ Radial gradients are defined by a SVG <radialGradient> element.
+    """
+    elementname = 'radialGradient'
+    def __init__(self, center=None, r=None, focal=None, inherit=None, attribs=None, **extra):
+        """
+        :param 2-tuple center: center point for the gradient (**cx**, **cy**)
+        :param r: radius for the gradient
+        :param 2-tuple focal: focal point for the radial gradient (**fx**, **fy**)
+        :param inherit: gradient inherits properties from `inherit` see: **xlink:href**
+
+        """
+
+        super(RadialGradient, self).__init__(inherit=inherit, attribs=attribs, **extra)
+        if center is not None:
+            self['cx'] = center[0]
+            self['cy'] = center[1]
+        if r is not None:
+            self['r'] = r
+        if focal is not None:
+            self['fx'] = focal[0]
+            self['fy'] = focal[1]
+
+        if self.debug:
+            self.validator.check_all_svg_attribute_values(self.elementname, self.attribs)

File svgwrite/interface.py

     All coordinates are **user space coordinates**.
 
     """
+    transformname = 'transform'
     def translate(self, tx, ty=None):
         """
         Specifies a translation by *tx* and *ty*. If *ty* is not provided,
     def matrix(self, a, b, c, d, e, f):
         self._add_transformation("matrix(%s)" % strlist( [a, b, c, d, e, f] ))
 
-    def del_transform(self):
-        self.attribs.pop('transform', None)
-
     def _add_transformation(self, new_transform):
-        old_transform = self.attribs.get('transform', '')
-        self['transform'] = ("%s %s" % (old_transform, new_transform)).strip()
+        old_transform = self.attribs.get(self.transformname, '')
+        self[self.transformname] = ("%s %s" % (old_transform, new_transform)).strip()
 
 class IXLink(object):
     """ Xlink interface """
         if isinstance(self.href, basestring):
             idstr = self.href
         else:
-            idstr = self.href.attribs.setdefault('id', self.nextid())
-        self.attribs['xlink:href'] =  "#%s" % idstr
+            idstr = self.href.get_iri()
+        self.attribs['xlink:href'] = idstr

File svgwrite/mixins.py

 
         """
         if color:
-            self['fill'] = color
+            if isinstance(color, basestring):
+                self['fill'] = color
+            else:
+                self['fill'] = color.get_paint_sever()
         if rule:
             self['fill-rule'] = rule
         if opacity:
         """
 
         if color:
-            self['stroke'] = color
+            if isinstance(color, basestring):
+                self['stroke'] = color
+            else:
+                self['stroke'] = color.get_paint_server()
         if width:
             self['stroke-width'] = width
         if opacity:

File svgwrite/utils.py

             cls._nextid = value
 
     @classmethod
-    def nextid(cls, value=None):
+    def next_id(cls, value=None):
         cls._set_value(value)
         retval = "id%d" % cls._nextid
         cls._nextid += 1

File tests/test_gradients.py

+#!/usr/bin/env python
+#coding:utf-8
+# Author:  mozman --<mozman@gmx.at>
+# Purpose: test gradients module
+# Created: 26.10.2010
+# Copyright (C) 2010, Manfred Moitzi
+# License: GPLv3
+
+import unittest
+import re
+
+from svgwrite.gradients import _GradientStop, LinearGradient, RadialGradient
+
+class TestGradientStop(unittest.TestCase):
+    def test_constructor1(self):
+        stop = _GradientStop(offset=0.5, color='red', opacity=1.0, debug=True, profile='full')
+        self.assertEqual(stop.tostring(), '<stop offset="0.5" stop-color="red" stop-opacity="1.0" />')
+
+    def test_constructor2(self):
+        stop = _GradientStop(offset='50%', color='red', opacity=0.63, debug=True, profile='full')
+        self.assertEqual(stop.tostring(), '<stop offset="50%" stop-color="red" stop-opacity="0.63" />')
+
+    def test_constructor3(self):
+        stop = _GradientStop(debug=True, profile='full')
+        self.assertEqual(stop.tostring(), '<stop />')
+
+class TestLinearGradient(unittest.TestCase):
+    def test_constructor(self):
+        lg = LinearGradient(start=(1, 2), end=(10, 20), inherit='#test', debug=True, profile='full')
+        self.assertEqual(
+            '<linearGradient x1="1" x2="10" xlink:href="#test" y1="2" y2="20" />',
+            lg.tostring())
+
+    def test_get_paint_server(self):
+        lg = LinearGradient()
+        self.assertTrue(re.match("^url\(#id\d+\)$", lg.get_paint_server()))
+
+    def test_add_stop_color(self):
+        lg = LinearGradient()
+        lg.add_stop_color(offset=0.5, color='red', opacity=1.0)
+        self.assertEqual(lg.tostring(), '<linearGradient><stop offset="0.5" stop-color="red" stop-opacity="1.0" /></linearGradient>')
+
+    def test_inherit(self):
+        inherit_from = LinearGradient(id='test')
+        lg = LinearGradient(inherit=inherit_from)
+        self.assertTrue('<linearGradient xlink:href="#test"/>', lg.tostring())
+
+class TestRadialGradient(unittest.TestCase):
+    def test_constructor(self):
+        rg = RadialGradient(center=(10, 20), r=10, focal=(15, 25), inherit='#test', debug=True, profile='full')
+        self.assertEqual(rg.tostring(),
+            '<radialGradient cx="10" cy="20" fx="15" fy="25" r="10" xlink:href="#test" />')
+
+    def test_get_paint_server(self):
+        rg = RadialGradient()
+        self.assertTrue(re.match("^url\(#id\d+\)$", rg.get_paint_server()))
+
+    def test_add_stop_color(self):
+        rg = RadialGradient()
+        rg.add_stop_color(offset=0.5, color='red', opacity=1.0)
+        self.assertEqual(rg.tostring(), '<radialGradient><stop offset="0.5" stop-color="red" stop-opacity="1.0" /></radialGradient>')
+
+if __name__=='__main__':
+    unittest.main()

File tests/test_itransform.py

         m.scale(2,2)
         self.assertEqual(m.tostring(), '<g transform="translate(10,20) scale(2,2)" />')
 
-    def test_del_tranformation(self):
-        m = Mock()
-        m.translate(10,20)
-        m.scale(2,2)
-        m.del_transform()
-        self.assertEqual(m.tostring(), '<g />')
-
 if __name__=='__main__':
     unittest.main()

File tests/test_ixlink.py

 
 import sys
 import unittest
+import re
 
 from svgwrite.container import Group
 from svgwrite.params import Parameter
     elementname = 'use'
     _parameter = Parameter(True, 'full')
 
-    def nextid(self):
+    def next_id(self):
         return "id999"
 
 class TestIXLink(unittest.TestCase):
 
     def test_href(self):
         m = Mock()
-        m.set_href('an_id')
+        m.set_href('#an_id')
         self.assertEqual(m.tostring(), '<use xlink:href="#an_id" />')
 
     def test_object_link(self):
         g = Group()
         m = Mock()
         m.set_href(g)
-        self.assertEqual(m.tostring(), '<use xlink:href="#id999" />')
+        self.assertTrue(re.match('^<use xlink:href="#id\d+" />$', m.tostring()))
 
 if __name__=='__main__':
     unittest.main()

File tests/test_text.py

 
 class TestTRef(unittest.TestCase):
     def test_constructor(self):
-        tref = TRef('test')
+        tref = TRef('#test')
         self.assertEqual(tref.tostring(), '<tref xlink:href="#test" />')
 
 class TestTextPath(unittest.TestCase):
     def test_constructor(self):
-        tref = TextPath('test', 'The Text', startOffset=10, spacing='auto', method='stretch')
+        tref = TextPath('#test', 'The Text', startOffset=10, spacing='auto', method='stretch')
         self.assertEqual(tref.tostring(), '<textPath method="stretch" spacing="auto"' \
                          ' startOffset="10" xlink:href="#test">The Text</textPath>')
 
     def test_subelement_tspan(self):
-        txt = TextPath('test', 'text')
+        txt = TextPath('#test', 'text')
         txt.add(TSpan('subtext'))
         self.assertEqual(txt.tostring(), '<textPath xlink:href="#test">text<tspan>subtext</tspan></textPath>')
 

File tests/test_use.py

 
 class TestUse(unittest.TestCase):
     def test_constructor(self):
-        use = Use('an_id', x=10, y=20, width=100, height=200)
+        use = Use('#an_id', x=10, y=20, width=100, height=200)
         self.assertTrue(isinstance(use, ITransform))
         self.assertTrue(isinstance(use, IXLink))
         self.assertEqual(use.tostring(), '<use height="200" width="100" x="10" xlink:href="#an_id" y="20" />')
 
     def test_constructor2(self):
-        use = Use('an_id', insert=(10, 20), size=(100, 200))
+        use = Use('#an_id', insert=(10, 20), size=(100, 200))
         self.assertTrue(isinstance(use, ITransform))
         self.assertTrue(isinstance(use, IXLink))
         self.assertEqual(use.tostring(), '<use height="200" width="100" x="10" xlink:href="#an_id" y="20" />')

File tests/test_utils.py

         self.assertRaises(ValueError, split_angle, '1.0.0deg')
 
 class TestAutoID(unittest.TestCase):
-    def test_nextid(self):
+    def test_next_id(self):
         getter = AutoID(1)
-        self.assertEqual('id1', getter.nextid())
+        self.assertEqual('id1', getter.next_id())
         getter = AutoID()
-        self.assertEqual('id2', getter.nextid())
-        self.assertEqual('id3', AutoID.nextid())
+        self.assertEqual('id2', getter.next_id())
+        self.assertEqual('id3', AutoID.next_id())
 
-    def test_set_nextid(self):
+    def test_set_next_id(self):
         #getter = AutoID()
-        self.assertEqual('id7', AutoID.nextid(7))
-        self.assertEqual('id8', AutoID.nextid())
+        self.assertEqual('id7', AutoID.next_id(7))
+        self.assertEqual('id8', AutoID.next_id())
 
 class TestGetUnit(unittest.TestCase):
     def test_number(self):