Commits

Manfred Moitzi  committed 105e7bf

more meaningful error msg for invalid svg elements

  • Participants
  • Parent commits 59e2026

Comments (0)

Files changed (5)

File examples/marker.py

-#!/usr/bin/env python
-#coding:utf-8
-# Author:  mozman
-# Purpose: svg examples
-# Created: 08.09.2010
-# Copyright (C) 2010, Manfred Moitzi
-# License: MIT License
-
-try:
-    import svgwrite
-except ImportError:
-    # if svgwrite is not 'installed' append parent dir of __file__ to sys.path
-    import sys, os
-    sys.path.insert(0, os.path.abspath(os.path.split(os.path.abspath(__file__))[0]+'/..'))
-
-import svgwrite
-
-def marker(name):
-    # Shows how to use the <marker> element.
-    # W3C reference: http://www.w3.org/TR/SVG11/painting.html#MarkerElement
-    #
-    dwg = svgwrite.Drawing(name, size=('20cm', '15cm'), profile='full', debug=True)
-    # set user coordinate space
-    dwg.viewbox(width=200, height=150)
-
-    #--start-- A red point as marker-start element
-    # 'insert' represents the insertation point in user coordinate space
-    # in this example its the midpoint of the circle, see below
-    marker_start = dwg.marker(insert=(0, 0), size=(5, 5)) # target size of the marker
-
-    # setting a user coordinate space for the appanded graphic elements
-    # bounding coordinates for this example:
-    # minx = -5, maxx = +5, miny = -5, maxy = +5
-    marker_start.viewbox(minx=-5, miny=-5, width=10, height=10) # the marker user coordinate space
-    marker_start.add(dwg.circle((0, 0), r=5)).fill('red', opacity=0.5)
-
-
-    #--end-- A blue point as marker-end element
-    # a shorter form of the code above:
-    marker_end = dwg.marker(size=(5, 5)) # marker defaults: insert=(0,0)
-    # set viewbox to the bounding coordinates of the circle
-    marker_end.viewbox(-1, -1, 2, 2)
-    marker_end.add(dwg.circle(fill='blue', fill_opacity=0.5)) # circle defaults: insert=(0,0), r=1
-
-    #--mid-- A green point as marker-mid element
-    # if you don't setup a user coordinate space, the default ucs is
-    # minx = 0, miny = 0, maxx=size[0], maxy=size[1]
-    # default size = (3, 3) defined by the SVG standard
-    # bounding coordinates for this example:
-    # minx = 0, maxx = 6, miny = 0, maxy = 6
-    # => center of the viewbox = (3, 3)!
-    marker_mid = dwg.marker(insert=(3, 3), size=(6, 6))
-    marker_mid.add(dwg.circle((3, 3), r=3)).fill('green', opacity=0.7)
-
-    # The drawing size of the 'start-marker' is greater than the drawing size of
-    # the 'marker-mid' (r=5 > r=3), but the resulting size is defined by the
-    # 'size' parameter of the marker object (size=(6,6) > size=(5,5)), so the
-    # 'marker-start' is smaller than the 'marker-mid'.
-
-    # add marker to defs section of the drawing
-    dwg.defs.add(marker_start)
-    dwg.defs.add(marker_mid)
-    dwg.defs.add(marker_end)
-
-    # create a new line object, fill='none' is important, because by default
-    # the polyline and the polygon object is filled (tested with FF, Chrome).
-    # I am not sure, if this is concurring to the SVG Standard.
-
-    line = dwg.add(dwg.polyline(
-        [(10, 10), (50, 20), (70, 50), (100, 30), (120, 140), (170, 100)],
-        stroke='black', fill='none'))
-
-    # set markers 3-tuple = ('marker-start', 'marker-mid', 'marker-end')
-    line.set_markers( (marker_start, marker_mid, marker_end) )
-
-    # or set markers direct as SVG Attributes 'marker-start', 'marker-mid',
-    # 'marker-end' or 'marker' if all markers are the same.
-    # line['marker'] = marker.get_funciri() # but 'marker' works only with Firefox (26.10.2010)
-    dwg.save()
-
-if __name__ == '__main__':
-    marker("marker.svg")
+#!/usr/bin/env python
+#coding:utf-8
+# Author:  mozman
+# Purpose: svg examples
+# Created: 08.09.2010
+# Copyright (C) 2010, Manfred Moitzi
+# License: MIT License
+
+try:
+    import svgwrite
+except ImportError:
+    # if svgwrite is not 'installed' append parent dir of __file__ to sys.path
+    import sys, os
+    sys.path.insert(0, os.path.abspath(os.path.split(os.path.abspath(__file__))[0]+'/..'))
+
+import svgwrite
+
+def marker(name):
+    # Shows how to use the <marker> element.
+    # W3C reference: http://www.w3.org/TR/SVG11/painting.html#MarkerElement
+    #
+    dwg = svgwrite.Drawing(name, size=('20cm', '15cm'), profile='tiny', debug=True)
+    # set user coordinate space
+    dwg.viewbox(width=200, height=150)
+
+    #--start-- A red point as marker-start element
+    # 'insert' represents the insertation point in user coordinate space
+    # in this example its the midpoint of the circle, see below
+    marker_start = dwg.marker(insert=(0, 0), size=(5, 5)) # target size of the marker
+
+    # setting a user coordinate space for the appanded graphic elements
+    # bounding coordinates for this example:
+    # minx = -5, maxx = +5, miny = -5, maxy = +5
+    marker_start.viewbox(minx=-5, miny=-5, width=10, height=10) # the marker user coordinate space
+    marker_start.add(dwg.circle((0, 0), r=5)).fill('red', opacity=0.5)
+
+
+    #--end-- A blue point as marker-end element
+    # a shorter form of the code above:
+    marker_end = dwg.marker(size=(5, 5)) # marker defaults: insert=(0,0)
+    # set viewbox to the bounding coordinates of the circle
+    marker_end.viewbox(-1, -1, 2, 2)
+    marker_end.add(dwg.circle(fill='blue', fill_opacity=0.5)) # circle defaults: insert=(0,0), r=1
+
+    #--mid-- A green point as marker-mid element
+    # if you don't setup a user coordinate space, the default ucs is
+    # minx = 0, miny = 0, maxx=size[0], maxy=size[1]
+    # default size = (3, 3) defined by the SVG standard
+    # bounding coordinates for this example:
+    # minx = 0, maxx = 6, miny = 0, maxy = 6
+    # => center of the viewbox = (3, 3)!
+    marker_mid = dwg.marker(insert=(3, 3), size=(6, 6))
+    marker_mid.add(dwg.circle((3, 3), r=3)).fill('green', opacity=0.7)
+
+    # The drawing size of the 'start-marker' is greater than the drawing size of
+    # the 'marker-mid' (r=5 > r=3), but the resulting size is defined by the
+    # 'size' parameter of the marker object (size=(6,6) > size=(5,5)), so the
+    # 'marker-start' is smaller than the 'marker-mid'.
+
+    # add marker to defs section of the drawing
+    dwg.defs.add(marker_start)
+    dwg.defs.add(marker_mid)
+    dwg.defs.add(marker_end)
+
+    # create a new line object, fill='none' is important, because by default
+    # the polyline and the polygon object is filled (tested with FF, Chrome).
+    # I am not sure, if this is concurring to the SVG Standard.
+
+    line = dwg.add(dwg.polyline(
+        [(10, 10), (50, 20), (70, 50), (100, 30), (120, 140), (170, 100)],
+        stroke='black', fill='none'))
+
+    # set markers 3-tuple = ('marker-start', 'marker-mid', 'marker-end')
+    line.set_markers( (marker_start, marker_mid, marker_end) )
+
+    # or set markers direct as SVG Attributes 'marker-start', 'marker-mid',
+    # 'marker-end' or 'marker' if all markers are the same.
+    # line['marker'] = marker.get_funciri() # but 'marker' works only with Firefox (26.10.2010)
+    dwg.save()
+
+if __name__ == '__main__':
+    marker("marker.svg")

File svgwrite/base.py

 
         """
         # Attribute checking is only done by using the __setitem__() method or
-        # by self['attibute'] = value
+        # by self['attribute'] = value
         if self.debug:
             self.validator.check_svg_attribute_value(self.elementname, key, value)
         self.attribs[key] = value

File svgwrite/container.py

-#coding:utf-8
-# Author:  mozman
-# Purpose: svg container classes
-# Created: 15.09.2010
-# Copyright (C) 2010, Manfred Moitzi
-# License: MIT License
-"""
-The **container** module provides following structural objects:
-
-* :class:`svgwrite.Group`
-* :class:`svgwrite.SVG`
-* :class:`svgwrite.Defs`
-* :class:`svgwrite.Symbol`
-* :class:`svgwrite.Marker`
-* :class:`svgwrite.Use`
-* :class:`svgwrite.Hyperlink`
-* :class:`svgwrite.Script`
-* :class:`svgwrite.Style`
-
-set/get SVG attributes::
-
-    element['attribute'] = value
-    value = element['attribute']
-
-"""
-
-from svgwrite.base import BaseElement
-from svgwrite.mixins import ViewBox, Transform, XLink
-from svgwrite.mixins import Presentation, Clipping
-from svgwrite.etree import CDATA
-
-class Group(BaseElement, Transform, Presentation):
-    """ The **Group** (SVG **g**) element is a container element for grouping
-    together related graphics elements.
-
-    Grouping constructs, when used in conjunction with the **desc** and **title**
-    elements, provide information about document structure and semantics.
-    Documents that are rich in structure may be rendered graphically, as speech,
-    or as braille, and thus promote accessibility.
-
-    A group of elements, as well as individual objects, can be given a name using
-    the **id** attribute. Named groups are needed for several purposes such as
-    animation and re-usable objects.
-
-    """
-    elementname = 'g'
-
-class Defs(Group):
-    """ The **defs** element is a container element for referenced elements. For
-    understandability and accessibility reasons, it is recommended that, whenever
-    possible, referenced elements be defined inside of a **defs**.
-    """
-    elementname= 'defs'
-
-class Symbol(BaseElement, ViewBox, Presentation, Clipping):
-    """ The **symbol** element is used to define graphical template objects which
-    can be instantiated by a **use** element. The use of **symbol** elements for
-    graphics that are used multiple times in the same document adds structure and
-    semantics. Documents that are rich in structure may be rendered graphically,
-    as speech, or as braille, and thus promote accessibility.
-    """
-    # ITransform interface is not valid for Symbol -> do not inherit from Group
-    elementname = 'symbol'
-
-class Marker(BaseElement, ViewBox, Presentation):
-    """ The **marker** element defines the graphics that is to be used for
-    drawing arrowheads or polymarkers on a given **path**, **line**, **polyline**
-    or **polygon** element.
-
-    Add Marker definitions to a **defs** section, preferred to the **defs** section
-    of the **main drawing**.
-
-    """
-    elementname = 'marker'
-    def __init__(self, insert=None, size=None, orient=None, **extra):
-        """
-        :param 2-tuple insert: reference point (**refX**, **refY**)
-        :param 2-tuple size: (**markerWidth**, **markerHeight**)
-        :param orient: ``'auto'`` | `angle`
-        :param extra: additional SVG attributes as keyword-arguments
-        """
-        super(Marker, self).__init__(**extra)
-        if insert:
-            self['refX'] = insert[0]
-            self['refY'] = insert[1]
-        if size:
-            self['markerWidth'] = size[0]
-            self['markerHeight'] = size[1]
-        if orient is not None:
-            self['orient'] = orient
-        if 'id' not in self.attribs: # an 'id' is necessary
-            self['id'] = self.next_id()
-
-class SVG(Symbol):
-    """ An SVG document fragment consists of any number of SVG elements contained
-    within an **svg** element.
-
-    An SVG document fragment can range from an empty fragment (i.e., no content
-    inside of the **svg** element), to a very simple SVG document fragment containing
-    a single SVG graphics element such as a **rect**, to a complex, deeply nested
-    collection of container elements and graphics elements.
-    """
-    elementname = 'svg'
-
-    def __init__(self, insert=None, size=None, **extra):
-        """
-        :param 2-tuple insert: insert position (**x**, **y**)
-        :param 2-tuple size: (**width**, **height**)
-        :param extra: additional SVG attributes as keyword-arguments
-        """
-        super(SVG, self).__init__(**extra)
-        if insert:
-            self['x'] = insert[0]
-            self['y'] = insert[1]
-        if size:
-            self['width'] = size[0]
-            self['height'] = size[1]
-
-        self.defs = Defs(factory=self) # defs container
-        self.add(self.defs) # add defs as first element
-
-class Use(BaseElement, Transform, XLink, Presentation):
-    """ The **use** element references another element and indicates that the graphical
-    contents of that element is included/drawn at that given point in the document.
-
-    Link to objects by href = ``'#object-id'`` or use the object itself as
-    href-argument, if the given element has no **id** attribute it gets an
-    automatic generated id.
-
-    """
-    elementname = 'use'
-
-    def __init__(self, href, insert=None, size=None, **extra):
-        """
-        :param string href: object link (id-string) or an object with an id-attribute
-        :param 2-tuple insert: insert point (**x**, **y**)
-        :param 2-tuple size: (**width**, **height**)
-        :param extra: additional SVG attributes as keyword-arguments
-        """
-        super(Use, self).__init__(**extra)
-        self.set_href(href)
-        if insert:
-            self['x'] = insert[0]
-            self['y'] = insert[1]
-        if size:
-            self['width'] = size[0]
-            self['height'] = size[1]
-
-    def get_xml(self):
-        self.update_id() # if href is an object - 'id' - attribute may be changed!
-        return super(Use, self).get_xml()
-
-class Hyperlink(BaseElement, Transform, Presentation):
-    """ The **a** element indicate links (also known as Hyperlinks or Web links).
-
-    The remote resource (the destination for the link) is defined by a `<URI>`
-    specified by the XLink **xlink:href** attribute. The remote resource may be
-    any Web resource (e.g., an image, a video clip, a sound bite, a program,
-    another SVG document, an HTML document, an element within the current
-    document, an element within a different document, etc.). By activating
-    these links (by clicking with the mouse, through keyboard input, voice
-    commands, etc.), users may visit these resources.
-
-    A **Hyperlink** is defined for each separate rendered element
-    contained within the **Hyperlink** class; add sublements as usual with
-    the `add` method.
-
-    """
-    elementname = 'a'
-    def __init__(self, href, target='_blank', **extra):
-        """
-        :param string href: hyperlink to the target resource
-        :param string target: ``'_blank|_replace|_self|_parent|_top|<XML-name>'``
-        :param extra: additional SVG attributes as keyword-arguments
-        """
-        super(Hyperlink, self).__init__(**extra)
-        self['xlink:href'] = href
-        self['target'] = target
-
-
-class Script(BaseElement):
-    """ The **script** element indicate links to a client-side language.  This
-    is normally a  (also known as Hyperlinks or Web links).
-
-    The remote resource (the source of the script) is defined by a `<URI>`
-    specified by the XLink **xlink:href** attribute. The remote resource must
-    be a text-file that contains the script contents.  This script can be used
-    within the SVG file by catching events or adding the mouseover/mousedown/
-    mouseup elements to the markup.
-
-    """
-
-    elementname = 'script'
-    def __init__(self, href=None, content="", **extra):
-        """
-        :param string href: hyperlink to the target resource or *None* if using *content*
-        :param string content: script content
-        :param extra: additional attributes as keyword-arguments
-
-        Use *href* **or** *content*, but not both at the same time.
-
-        """
-        # removed type parameter, default is "application/ecmascript"
-        super(Script, self).__init__(**extra)
-        if href:
-            self['xlink:href'] = href
-        self._content = content
-
-    def get_xml(self):
-        xml = super(Script, self).get_xml()
-        if self._content:
-            xml.append(CDATA(self._content))
-        return xml
-
-    def append(self, content):
-        """ Append content to the existing element-content. """
-        self._content += content
-
-class Style(Script):
-    """ The *style* element allows style sheets to be embedded directly within
-    SVG content. SVG's *style* element has the same attributes as the
-    corresponding element in HTML.
-
-    """
-    elementname = 'style'
-    def __init__(self, content="", **extra):
-        """
-        :param string content: stylesheet content
-        """
-        super(Style, self).__init__(content=content, **extra)
-        self['type'] = "text/css"
-
+#coding:utf-8
+# Author:  mozman
+# Purpose: svg container classes
+# Created: 15.09.2010
+# Copyright (C) 2010, Manfred Moitzi
+# License: MIT License
+"""
+The **container** module provides following structural objects:
+
+* :class:`svgwrite.Group`
+* :class:`svgwrite.SVG`
+* :class:`svgwrite.Defs`
+* :class:`svgwrite.Symbol`
+* :class:`svgwrite.Marker`
+* :class:`svgwrite.Use`
+* :class:`svgwrite.Hyperlink`
+* :class:`svgwrite.Script`
+* :class:`svgwrite.Style`
+
+set/get SVG attributes::
+
+    element['attribute'] = value
+    value = element['attribute']
+
+"""
+
+from svgwrite.base import BaseElement
+from svgwrite.mixins import ViewBox, Transform, XLink
+from svgwrite.mixins import Presentation, Clipping
+from svgwrite.etree import CDATA
+
+
+class Group(BaseElement, Transform, Presentation):
+    """ The **Group** (SVG **g**) element is a container element for grouping
+    together related graphics elements.
+
+    Grouping constructs, when used in conjunction with the **desc** and **title**
+    elements, provide information about document structure and semantics.
+    Documents that are rich in structure may be rendered graphically, as speech,
+    or as braille, and thus promote accessibility.
+
+    A group of elements, as well as individual objects, can be given a name using
+    the **id** attribute. Named groups are needed for several purposes such as
+    animation and re-usable objects.
+
+    """
+    elementname = 'g'
+
+
+class Defs(Group):
+    """ The **defs** element is a container element for referenced elements. For
+    understandability and accessibility reasons, it is recommended that, whenever
+    possible, referenced elements be defined inside of a **defs**.
+    """
+    elementname = 'defs'
+
+
+class Symbol(BaseElement, ViewBox, Presentation, Clipping):
+    """ The **symbol** element is used to define graphical template objects which
+    can be instantiated by a **use** element. The use of **symbol** elements for
+    graphics that are used multiple times in the same document adds structure and
+    semantics. Documents that are rich in structure may be rendered graphically,
+    as speech, or as braille, and thus promote accessibility.
+    """
+    # ITransform interface is not valid for Symbol -> do not inherit from Group
+    elementname = 'symbol'
+
+
+class Marker(BaseElement, ViewBox, Presentation):
+    """ The **marker** element defines the graphics that is to be used for
+    drawing arrowheads or polymarkers on a given **path**, **line**, **polyline**
+    or **polygon** element.
+
+    Add Marker definitions to a **defs** section, preferred to the **defs** section
+    of the **main drawing**.
+
+    """
+    elementname = 'marker'
+
+    def __init__(self, insert=None, size=None, orient=None, **extra):
+        """
+        :param 2-tuple insert: reference point (**refX**, **refY**)
+        :param 2-tuple size: (**markerWidth**, **markerHeight**)
+        :param orient: ``'auto'`` | `angle`
+        :param extra: additional SVG attributes as keyword-arguments
+        """
+        super(Marker, self).__init__(**extra)
+        if insert:
+            self['refX'] = insert[0]
+            self['refY'] = insert[1]
+        if size:
+            self['markerWidth'] = size[0]
+            self['markerHeight'] = size[1]
+        if orient is not None:
+            self['orient'] = orient
+        if 'id' not in self.attribs: # an 'id' is necessary
+            self['id'] = self.next_id()
+
+
+class SVG(Symbol):
+    """ An SVG document fragment consists of any number of SVG elements contained
+    within an **svg** element.
+
+    An SVG document fragment can range from an empty fragment (i.e., no content
+    inside of the **svg** element), to a very simple SVG document fragment containing
+    a single SVG graphics element such as a **rect**, to a complex, deeply nested
+    collection of container elements and graphics elements.
+    """
+    elementname = 'svg'
+
+    def __init__(self, insert=None, size=None, **extra):
+        """
+        :param 2-tuple insert: insert position (**x**, **y**)
+        :param 2-tuple size: (**width**, **height**)
+        :param extra: additional SVG attributes as keyword-arguments
+        """
+        super(SVG, self).__init__(**extra)
+        if insert:
+            self['x'] = insert[0]
+            self['y'] = insert[1]
+        if size:
+            self['width'] = size[0]
+            self['height'] = size[1]
+
+        self.defs = Defs(factory=self) # defs container
+        self.add(self.defs) # add defs as first element
+
+
+class Use(BaseElement, Transform, XLink, Presentation):
+    """ The **use** element references another element and indicates that the graphical
+    contents of that element is included/drawn at that given point in the document.
+
+    Link to objects by href = ``'#object-id'`` or use the object itself as
+    href-argument, if the given element has no **id** attribute it gets an
+    automatic generated id.
+
+    """
+    elementname = 'use'
+
+    def __init__(self, href, insert=None, size=None, **extra):
+        """
+        :param string href: object link (id-string) or an object with an id-attribute
+        :param 2-tuple insert: insert point (**x**, **y**)
+        :param 2-tuple size: (**width**, **height**)
+        :param extra: additional SVG attributes as keyword-arguments
+        """
+        super(Use, self).__init__(**extra)
+        self.set_href(href)
+        if insert:
+            self['x'] = insert[0]
+            self['y'] = insert[1]
+        if size:
+            self['width'] = size[0]
+            self['height'] = size[1]
+
+    def get_xml(self):
+        self.update_id() # if href is an object - 'id' - attribute may be changed!
+        return super(Use, self).get_xml()
+
+
+class Hyperlink(BaseElement, Transform, Presentation):
+    """ The **a** element indicate links (also known as Hyperlinks or Web links).
+
+    The remote resource (the destination for the link) is defined by a `<URI>`
+    specified by the XLink **xlink:href** attribute. The remote resource may be
+    any Web resource (e.g., an image, a video clip, a sound bite, a program,
+    another SVG document, an HTML document, an element within the current
+    document, an element within a different document, etc.). By activating
+    these links (by clicking with the mouse, through keyboard input, voice
+    commands, etc.), users may visit these resources.
+
+    A **Hyperlink** is defined for each separate rendered element
+    contained within the **Hyperlink** class; add sublements as usual with
+    the `add` method.
+
+    """
+    elementname = 'a'
+
+    def __init__(self, href, target='_blank', **extra):
+        """
+        :param string href: hyperlink to the target resource
+        :param string target: ``'_blank|_replace|_self|_parent|_top|<XML-name>'``
+        :param extra: additional SVG attributes as keyword-arguments
+        """
+        super(Hyperlink, self).__init__(**extra)
+        self['xlink:href'] = href
+        self['target'] = target
+
+
+class Script(BaseElement):
+    """ The **script** element indicate links to a client-side language.  This
+    is normally a  (also known as Hyperlinks or Web links).
+
+    The remote resource (the source of the script) is defined by a `<URI>`
+    specified by the XLink **xlink:href** attribute. The remote resource must
+    be a text-file that contains the script contents.  This script can be used
+    within the SVG file by catching events or adding the mouseover/mousedown/
+    mouseup elements to the markup.
+
+    """
+    elementname = 'script'
+
+    def __init__(self, href=None, content="", **extra):
+        """
+        :param string href: hyperlink to the target resource or *None* if using *content*
+        :param string content: script content
+        :param extra: additional attributes as keyword-arguments
+
+        Use *href* **or** *content*, but not both at the same time.
+
+        """
+        # removed type parameter, default is "application/ecmascript"
+        super(Script, self).__init__(**extra)
+        if href:
+            self['xlink:href'] = href
+        self._content = content
+
+    def get_xml(self):
+        xml = super(Script, self).get_xml()
+        if self._content:
+            xml.append(CDATA(self._content))
+        return xml
+
+    def append(self, content):
+        """ Append content to the existing element-content. """
+        self._content += content
+
+
+class Style(Script):
+    """ The *style* element allows style sheets to be embedded directly within
+    SVG content. SVG's *style* element has the same attributes as the
+    corresponding element in HTML.
+
+    """
+    elementname = 'style'
+
+    def __init__(self, content="", **extra):
+        """
+        :param string content: stylesheet content
+        """
+        super(Style, self).__init__(content=content, **extra)
+        self['type'] = "text/css"
+

File svgwrite/validator2.py

 
 validator_cache = {}
 
+
 def cache_key(profile, debug):
     return str(profile) + str(debug)
 
+
 def get_validator(profile, debug=True):
     """ Validator factory """
     try:
 
 
 class Tiny12Validator(object):
+    profilename = "Tiny 1.2"
+
     def __init__(self, debug=True):
         self.debug = debug
         self.attributes = tiny12.attributes
         if not self.is_valid_svg_attribute(elementname, attributename):
             raise ValueError("Invalid attribute '%s' for svg-element <%s>." % (attributename, elementname))
 
+    def _get_element(self, elementname):
+        try:
+            return self.elements[elementname]
+        except KeyError:
+            raise KeyError("<%s> is not valid for selected profile: '%s'." % (elementname, self.profilename))
+
     def check_svg_type(self, value, typename='string'):
         """
         Check if 'value' matches svg type 'typename'.
         """ True if 'attributename' is a valid svg-attribute for svg-element
         'elementname'.
         """
-        element = self.elements[elementname]
+        element = self._get_element(elementname)
         return attributename in element.valid_attributes
 
     def is_valid_children(self, elementname, childrenname):
         """ True if svg-element 'childrenname' is a valid children of
         svg-element 'elementname'.
         """
-        element = self.elements[elementname]
+        element = self._get_element(elementname)
         return childrenname in element.valid_children
 
     def check_valid_children(self, elementname, childrenname):
             raise ValueError("%s is not a valid number for: %s." % (value, version))
     get_length = get_coordinate
 
+
 class Full11Validator(Tiny12Validator):
+    profilename = "Full 1.1"
+
     def __init__(self, debug=True):
         self.debug = debug
         self.attributes = full11.attributes

File tests/test_textarea.py

-#!/usr/bin/env python
-#coding:utf-8
-# Author:  mozman --<mozman@gmx.at>
-# Purpose: test TextArea class
-# Created: 14.10.2010
-# Copyright (C) 2010, Manfred Moitzi
-# License: MIT License
-
-import sys
-import unittest
-
-from svgwrite.text import TextArea
-from svgwrite.text import TBreak
-
-class TestTBreak(unittest.TestCase):
-    def test_tostring(self):
-        br = TBreak(profile='tiny')
-        self.assertEqual(br.tostring(), "<tbreak />")
-
-    def test_errors(self):
-        br = TBreak()
-        self.assertRaises(NotImplementedError, br.add, None)
-        self.assertRaises(NotImplementedError, br.__getitem__, 'key')
-        self.assertRaises(NotImplementedError, br.__setitem__, 'key', 'value')
-
-class TestTextAreaFullProfile(unittest.TestCase):
-    def test_constructor(self):
-        self.assertRaises(KeyError, TextArea, (0,0))
-
-class TestTextAreaTinyProfile(unittest.TestCase):
-    def test_constructor(self):
-        textarea = TextArea(insert=(1, 2), size=(10,20), profile='tiny')
-        self.assertEqual(textarea.tostring(), '<textArea height="20" width="10" x="1" y="2" />')
-
-    def test_write_one_line(self):
-        textarea = TextArea(profile='tiny')
-        self.assertEqual(textarea.tostring(), '<textArea />')
-        textarea.write('a line.')
-        self.assertEqual(textarea.tostring(), '<textArea><tspan>a line.</tspan></textArea>')
-
-    def test_write_linebreaks(self):
-        textarea = TextArea('\n', profile='tiny')
-        self.assertEqual(textarea.tostring(), '<textArea><tbreak /></textArea>')
-        textarea = TextArea('\n\n', profile='tiny')
-        self.assertEqual(textarea.tostring(), '<textArea><tbreak /><tbreak /></textArea>')
-
-    def test_write_lines(self):
-        textarea = TextArea('line1\n', profile='tiny')
-        self.assertEqual(textarea.tostring(), '<textArea><tspan>line1</tspan><tbreak /></textArea>')
-
-        textarea = TextArea('line1\nline2', profile='tiny')
-        self.assertEqual(textarea.tostring(), '<textArea><tspan>line1</tspan><tbreak />' \
-                         '<tspan>line2</tspan></textArea>')
-
-        textarea = TextArea('line1\nline2\n', profile='tiny')
-        self.assertEqual(textarea.tostring(), '<textArea><tspan>line1</tspan><tbreak />' \
-                         '<tspan>line2</tspan><tbreak /></textArea>')
-
-        textarea = TextArea('line1\n \nline2\n', profile='tiny')
-        self.assertEqual(textarea.tostring(), '<textArea><tspan>line1</tspan><tbreak />' \
-                         '<tspan> </tspan><tbreak /><tspan>line2</tspan><tbreak /></textArea>')
-    def test_line_increment(self):
-        textarea = TextArea('line1\n', profile='tiny')
-        textarea.line_increment('14')
-        self.assertEqual(textarea.tostring(), '<textArea line-increment="14"><tspan>line1</tspan><tbreak /></textArea>')
-
-    def test_write_lines_prepending_linebreak(self):
-        textarea = TextArea('\nline1\n', profile='tiny')
-        self.assertEqual(textarea.tostring(), '<textArea><tbreak /><tspan>line1</tspan><tbreak /></textArea>')
-
-        textarea = TextArea('\nline1\nline2', profile='tiny')
-        self.assertEqual(textarea.tostring(), '<textArea><tbreak /><tspan>line1</tspan><tbreak />' \
-                         '<tspan>line2</tspan></textArea>')
-
-        textarea = TextArea('\nline1\nline2\n', profile='tiny')
-        self.assertEqual(textarea.tostring(), '<textArea><tbreak /><tspan>line1</tspan><tbreak />' \
-                         '<tspan>line2</tspan><tbreak /></textArea>')
-
-        textarea = TextArea('\nline1\n\nline2\n', profile='tiny')
-        self.assertEqual(textarea.tostring(), '<textArea><tbreak /><tspan>line1</tspan><tbreak />' \
-                         '<tbreak /><tspan>line2</tspan><tbreak /></textArea>')
-
-
-if __name__=='__main__':
-    unittest.main()
+#!/usr/bin/env python
+#coding:utf-8
+# Author:  mozman --<mozman@gmx.at>
+# Purpose: test TextArea class
+# Created: 14.10.2010
+# Copyright (C) 2010, Manfred Moitzi
+# License: MIT License
+
+import sys
+import unittest
+
+from svgwrite.text import TextArea
+from svgwrite.text import TBreak
+
+
+class TestTBreak(unittest.TestCase):
+    def test_tostring(self):
+        br = TBreak(profile='tiny')
+        self.assertEqual(br.tostring(), "<tbreak />")
+
+    def test_errors(self):
+        br = TBreak()
+        self.assertRaises(NotImplementedError, br.add, None)
+        self.assertRaises(NotImplementedError, br.__getitem__, 'key')
+        self.assertRaises(NotImplementedError, br.__setitem__, 'key', 'value')
+
+
+class TestTextAreaFullProfile(unittest.TestCase):
+    def test_constructor(self):
+        self.assertRaises(KeyError, TextArea, (0, 0))
+
+
+class TestTextAreaTinyProfile(unittest.TestCase):
+    def test_constructor(self):
+        textarea = TextArea(insert=(1, 2), size=(10,20), profile='tiny')
+        self.assertEqual(textarea.tostring(), '<textArea height="20" width="10" x="1" y="2" />')
+
+    def test_write_one_line(self):
+        textarea = TextArea(profile='tiny')
+        self.assertEqual(textarea.tostring(), '<textArea />')
+        textarea.write('a line.')
+        self.assertEqual(textarea.tostring(), '<textArea><tspan>a line.</tspan></textArea>')
+
+    def test_write_linebreaks(self):
+        textarea = TextArea('\n', profile='tiny')
+        self.assertEqual(textarea.tostring(), '<textArea><tbreak /></textArea>')
+        textarea = TextArea('\n\n', profile='tiny')
+        self.assertEqual(textarea.tostring(), '<textArea><tbreak /><tbreak /></textArea>')
+
+    def test_write_lines(self):
+        textarea = TextArea('line1\n', profile='tiny')
+        self.assertEqual(textarea.tostring(), '<textArea><tspan>line1</tspan><tbreak /></textArea>')
+
+        textarea = TextArea('line1\nline2', profile='tiny')
+        self.assertEqual(textarea.tostring(), '<textArea><tspan>line1</tspan><tbreak />'
+                         '<tspan>line2</tspan></textArea>')
+
+        textarea = TextArea('line1\nline2\n', profile='tiny')
+        self.assertEqual(textarea.tostring(), '<textArea><tspan>line1</tspan><tbreak />'
+                         '<tspan>line2</tspan><tbreak /></textArea>')
+
+        textarea = TextArea('line1\n \nline2\n', profile='tiny')
+        self.assertEqual(textarea.tostring(), '<textArea><tspan>line1</tspan><tbreak />'
+                         '<tspan> </tspan><tbreak /><tspan>line2</tspan><tbreak /></textArea>')
+
+    def test_line_increment(self):
+        textarea = TextArea('line1\n', profile='tiny')
+        textarea.line_increment('14')
+        self.assertEqual(textarea.tostring(), '<textArea line-increment="14"><tspan>line1</tspan><tbreak /></textArea>')
+
+    def test_write_lines_prepending_linebreak(self):
+        textarea = TextArea('\nline1\n', profile='tiny')
+        self.assertEqual(textarea.tostring(), '<textArea><tbreak /><tspan>line1</tspan><tbreak /></textArea>')
+
+        textarea = TextArea('\nline1\nline2', profile='tiny')
+        self.assertEqual(textarea.tostring(), '<textArea><tbreak /><tspan>line1</tspan><tbreak />'
+                         '<tspan>line2</tspan></textArea>')
+
+        textarea = TextArea('\nline1\nline2\n', profile='tiny')
+        self.assertEqual(textarea.tostring(), '<textArea><tbreak /><tspan>line1</tspan><tbreak />'
+                         '<tspan>line2</tspan><tbreak /></textArea>')
+
+        textarea = TextArea('\nline1\n\nline2\n', profile='tiny')
+        self.assertEqual(textarea.tostring(), '<textArea><tbreak /><tspan>line1</tspan><tbreak />'
+                         '<tbreak /><tspan>line2</tspan><tbreak /></textArea>')
+
+
+if __name__ == '__main__':
+    unittest.main()