Ready for the initial release.
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..050ced2
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2006 Kirill Simonov
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/README b/README
new file mode 100644
index 0000000..4c8431d
--- /dev/null
+++ b/README
@@ -0,0 +1,11 @@
+PyYAML3000 - The next generation YAML parser for Python.
+
+To install, type 'python setup.py install'.
+
+For more information, check 'http://trac.xitology.org/pysyck/wiki/PyYAML3000'.
+
+Post your questions and opinions to the YAML-Core mailing list:
+'http://lists.sourceforge.net/lists/listinfo/yaml-core'.
+
+PyYAML3000 is written by Kirill Simonov <xi@resolvent.net>. It is released
+under the MIT license. See the file LICENSE for more details.
diff --git a/lib/yaml/constructor.py b/lib/yaml/constructor.py
index 1e7fea0..0660f54 100644
--- a/lib/yaml/constructor.py
+++ b/lib/yaml/constructor.py
@@ -92,23 +92,23 @@
                 if merge is not None:
                     raise ConstructorError("while constructing a mapping", node.start_marker,
                             "found duplicate merge key", key_node.start_marker)
-                    value_node = node.value[key_node]
-                    if isinstance(value_node, MappingNode):
-                        merge = [self.construct_mapping(value_node)]
-                    elif isinstance(value_node, SequenceNode):
-                        merge = []
-                        for subnode in value_node.value:
-                            if not isinstance(subnode, MappingNode):
-                                raise ConstructorError("while constructing a mapping",
-                                        node.start_marker,
-                                        "expected a mapping for merging, but found %s"
-                                        % subnode.id, subnode.start_marker)
-                            merge.append(self.construct_mapping(subnode))
-                        merge.reverse()
-                    else:
-                        raise ConstructorError("while constructing a mapping", node.start_marker,
-                                "expected a mapping or list of mappings for merging, but found %s"
-                                % value_node.id, value_node.start_marker)
+                value_node = node.value[key_node]
+                if isinstance(value_node, MappingNode):
+                    merge = [self.construct_mapping(value_node)]
+                elif isinstance(value_node, SequenceNode):
+                    merge = []
+                    for subnode in value_node.value:
+                        if not isinstance(subnode, MappingNode):
+                            raise ConstructorError("while constructing a mapping",
+                                    node.start_marker,
+                                    "expected a mapping for merging, but found %s"
+                                    % subnode.id, subnode.start_marker)
+                        merge.append(self.construct_mapping(subnode))
+                    merge.reverse()
+                else:
+                    raise ConstructorError("while constructing a mapping", node.start_marker,
+                            "expected a mapping or list of mappings for merging, but found %s"
+                            % value_node.id, value_node.start_marker)
             elif key_node.tag == u'tag:yaml.org,2002:value':
                 if '=' in mapping:
                     raise ConstructorError("while construction a mapping", node.start_marker,
@@ -211,7 +211,7 @@
         value = value.replace('_', '')
         sign = +1
         if value[0] == '-':
-            value = -1
+            sign = -1
         if value[0] in '+-':
             value = value[1:]
         if value.lower() == '.inf':
@@ -236,23 +236,23 @@
             return str(value).decode('base64')
         except (binascii.Error, UnicodeEncodeError), exc:
             raise ConstructorError(None, None,
-                    "failed to decode base64 data: %s" % exc, node.start_mark) 
+                    "failed to decode base64 data: %s" % exc, node.start_marker) 
 
     timestamp_regexp = re.compile(
             ur'''^(?P<year>[0-9][0-9][0-9][0-9])
                 -(?P<month>[0-9][0-9]?)
                 -(?P<day>[0-9][0-9]?)
-                (?:[Tt]|[ \t]+)
+                (?:(?:[Tt]|[ \t]+)
                 (?P<hour>[0-9][0-9]?)
                 :(?P<minute>[0-9][0-9])
                 :(?P<second>[0-9][0-9])
                 (?:\.(?P<fraction>[0-9]*))?
                 (?:[ \t]*(?:Z|(?P<tz_hour>[-+][0-9][0-9]?)
-                (?::(?P<tz_minute>[0-9][0-9])?)))?$''', re.X),
+                (?::(?P<tz_minute>[0-9][0-9])?)?))?)?$''', re.X)
 
     def construct_yaml_timestamp(self, node):
         value = self.construct_scalar(node)
-        match = self.timestamp_expr.match(node.value)
+        match = self.timestamp_regexp.match(node.value)
         values = match.groupdict()
         for key in values:
             if values[key]:
@@ -260,7 +260,7 @@
             else:
                 values[key] = 0
         fraction = values['fraction']
-        if micro:
+        if fraction:
             while 10*fraction < 1000000:
                 fraction *= 10
             values['fraction'] = fraction
@@ -281,34 +281,36 @@
                 raise ConstructorError("while constructing an ordered map", node.start_marker,
                         "expected a mapping of length 1, but found %s" % subnode.id,
                         subnode.start_marker)
-                if len(subnode.value) != 1:
-                    raise ConstructorError("while constructing an ordered map", node.start_marker,
-                            "expected a single mapping item, but found %d items" % len(subnode.value),
-                            subnode.start_marker)
-                key_node = subnode.value.keys()[0]
-                key = self.construct_object(key_node)
-                value = self.construct_object(subnode.value[key_node])
-                omap.append((key, value))
+            if len(subnode.value) != 1:
+                raise ConstructorError("while constructing an ordered map", node.start_marker,
+                        "expected a single mapping item, but found %d items" % len(subnode.value),
+                        subnode.start_marker)
+            key_node = subnode.value.keys()[0]
+            key = self.construct_object(key_node)
+            value = self.construct_object(subnode.value[key_node])
+            omap.append((key, value))
+        return omap
 
     def construct_yaml_pairs(self, node):
         # Note: the same code as `construct_yaml_omap`.
         if not isinstance(node, SequenceNode):
             raise ConstructorError("while constructing pairs", node.start_marker,
                     "expected a sequence, but found %s" % node.id, node.start_marker)
-        omap = []
+        pairs = []
         for subnode in node.value:
             if not isinstance(subnode, MappingNode):
                 raise ConstructorError("while constructing pairs", node.start_marker,
                         "expected a mapping of length 1, but found %s" % subnode.id,
                         subnode.start_marker)
-                if len(subnode.value) != 1:
-                    raise ConstructorError("while constructing pairs", node.start_marker,
-                            "expected a single mapping item, but found %d items" % len(subnode.value),
-                            subnode.start_marker)
-                key_node = subnode.value.keys()[0]
-                key = self.construct_object(key_node)
-                value = self.construct_object(subnode.value[key_node])
-                omap.append((key, value))
+            if len(subnode.value) != 1:
+                raise ConstructorError("while constructing pairs", node.start_marker,
+                        "expected a single mapping item, but found %d items" % len(subnode.value),
+                        subnode.start_marker)
+            key_node = subnode.value.keys()[0]
+            key = self.construct_object(key_node)
+            value = self.construct_object(subnode.value[key_node])
+            pairs.append((key, value))
+        return pairs
 
     def construct_yaml_set(self, node):
         value = self.construct_mapping(node)
@@ -349,8 +351,13 @@
         Constructor.construct_yaml_float)
 
 Constructor.add_constructor(
-        u'tag:yaml.org,2002:timestamp',
-        Constructor.construct_yaml_timestamp)
+        u'tag:yaml.org,2002:binary',
+        Constructor.construct_yaml_binary)
+
+if datetime_available:
+    Constructor.add_constructor(
+            u'tag:yaml.org,2002:timestamp',
+            Constructor.construct_yaml_timestamp)
 
 Constructor.add_constructor(
         u'tag:yaml.org,2002:omap',
@@ -384,13 +391,13 @@
     def __init__(cls, name, bases, kwds):
         super(YAMLObjectMetaclass, cls).__init__(name, bases, kwds)
         if 'yaml_tag' in kwds and kwds['yaml_tag'] is not None:
-            cls.yaml_constructor_class.add_constructor(cls.yaml_tag, cls.from_yaml)
+            cls.yaml_constructor.add_constructor(cls.yaml_tag, cls.from_yaml)
 
 class YAMLObject(object):
 
     __metaclass__ = YAMLObjectMetaclass
 
-    yaml_constructor_class = Constructor
+    yaml_constructor = Constructor
 
     yaml_tag = None
 
diff --git a/tests/data/construct-binary.code b/tests/data/construct-binary.code
new file mode 100644
index 0000000..67ac0d5
--- /dev/null
+++ b/tests/data/construct-binary.code
@@ -0,0 +1,7 @@
+{
+    "canonical":
+        "GIF89a\x0c\x00\x0c\x00\x84\x00\x00\xff\xff\xf7\xf5\xf5\xee\xe9\xe9\xe5fff\x00\x00\x00\xe7\xe7\xe7^^^\xf3\xf3\xed\x8e\x8e\x8e\xe0\xe0\xe0\x9f\x9f\x9f\x93\x93\x93\xa7\xa7\xa7\x9e\x9e\x9eiiiccc\xa3\xa3\xa3\x84\x84\x84\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9!\xfe\x0eMade with GIMP\x00,\x00\x00\x00\x00\x0c\x00\x0c\x00\x00\x05,  \x8e\x810\x9e\xe3@\x14\xe8i\x10\xc4\xd1\x8a\x08\x1c\xcf\x80M$z\xef\xff0\x85p\xb8\xb01f\r\x1b\xce\x01\xc3\x01\x1e\x10' \x82\n\x01\x00;",
+    "generic":
+        "GIF89a\x0c\x00\x0c\x00\x84\x00\x00\xff\xff\xf7\xf5\xf5\xee\xe9\xe9\xe5fff\x00\x00\x00\xe7\xe7\xe7^^^\xf3\xf3\xed\x8e\x8e\x8e\xe0\xe0\xe0\x9f\x9f\x9f\x93\x93\x93\xa7\xa7\xa7\x9e\x9e\x9eiiiccc\xa3\xa3\xa3\x84\x84\x84\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9!\xfe\x0eMade with GIMP\x00,\x00\x00\x00\x00\x0c\x00\x0c\x00\x00\x05,  \x8e\x810\x9e\xe3@\x14\xe8i\x10\xc4\xd1\x8a\x08\x1c\xcf\x80M$z\xef\xff0\x85p\xb8\xb01f\r\x1b\xce\x01\xc3\x01\x1e\x10' \x82\n\x01\x00;",
+    "description": "The binary value above is a tiny arrow encoded as a gif image.",
+}
diff --git a/tests/data/construct-binary.data b/tests/data/construct-binary.data
new file mode 100644
index 0000000..dcdb16f
--- /dev/null
+++ b/tests/data/construct-binary.data
@@ -0,0 +1,12 @@
+canonical: !!binary "\
+ R0lGODlhDAAMAIQAAP//9/X17unp5WZmZgAAAOfn515eXvPz7Y6OjuDg4J+fn5\
+ OTk6enp56enmlpaWNjY6Ojo4SEhP/++f/++f/++f/++f/++f/++f/++f/++f/+\
+ +f/++f/++f/++f/++f/++SH+Dk1hZGUgd2l0aCBHSU1QACwAAAAADAAMAAAFLC\
+ AgjoEwnuNAFOhpEMTRiggcz4BNJHrv/zCFcLiwMWYNG84BwwEeECcgggoBADs="
+generic: !!binary |
+ R0lGODlhDAAMAIQAAP//9/X17unp5WZmZgAAAOfn515eXvPz7Y6OjuDg4J+fn5
+ OTk6enp56enmlpaWNjY6Ojo4SEhP/++f/++f/++f/++f/++f/++f/++f/++f/+
+ +f/++f/++f/++f/++f/++SH+Dk1hZGUgd2l0aCBHSU1QACwAAAAADAAMAAAFLC
+ AgjoEwnuNAFOhpEMTRiggcz4BNJHrv/zCFcLiwMWYNG84BwwEeECcgggoBADs=
+description:
+ The binary value above is a tiny arrow encoded as a gif image.
diff --git a/tests/data/construct-bool.code b/tests/data/construct-bool.code
new file mode 100644
index 0000000..389d2c0
--- /dev/null
+++ b/tests/data/construct-bool.code
@@ -0,0 +1,6 @@
+{
+    "canonical": True,
+    "answer": False,
+    "logical": True,
+    "option": True,
+}
diff --git a/tests/data/construct-bool.data b/tests/data/construct-bool.data
new file mode 100644
index 0000000..2a8f2e6
--- /dev/null
+++ b/tests/data/construct-bool.data
@@ -0,0 +1,4 @@
+canonical: y
+answer: NO
+logical: True
+option: on
diff --git a/tests/data/construct-custom.code b/tests/data/construct-custom.code
new file mode 100644
index 0000000..bcc283f
--- /dev/null
+++ b/tests/data/construct-custom.code
@@ -0,0 +1,9 @@
+[
+    MyTestClass1(x=1),
+    MyTestClass1(x=1, y=2, z=3),
+    MyTestClass2(x=10),
+    MyTestClass2(x=10, y=20, z=30),
+    MyTestClass3(x=1),
+    MyTestClass3(x=1, y=2, z=3),
+    MyTestClass3(x=1, y=2, z=3),
+]
diff --git a/tests/data/construct-custom.data b/tests/data/construct-custom.data
new file mode 100644
index 0000000..053d028
--- /dev/null
+++ b/tests/data/construct-custom.data
@@ -0,0 +1,23 @@
+---
+- !tag1
+  x: 1
+- !tag1
+  x: 1
+  'y': 2
+  z: 3
+- !tag2
+  10
+- !tag2
+  =: 10
+  'y': 20
+  z: 30
+- !tag3
+  x: 1
+- !tag3
+  x: 1
+  'y': 2
+  z: 3
+- !tag3
+  =: 1
+  'y': 2
+  z: 3
diff --git a/tests/data/construct-float.code b/tests/data/construct-float.code
new file mode 100644
index 0000000..8493bf2
--- /dev/null
+++ b/tests/data/construct-float.code
@@ -0,0 +1,8 @@
+{
+    "canonical": 685230.15,
+    "exponential": 685230.15,
+    "fixed": 685230.15,
+    "sexagesimal": 685230.15,
+    "negative infinity": -1e300000,
+    "not a number": 1e300000/1e300000,
+}
diff --git a/tests/data/construct-float.data b/tests/data/construct-float.data
new file mode 100644
index 0000000..b662c62
--- /dev/null
+++ b/tests/data/construct-float.data
@@ -0,0 +1,6 @@
+canonical: 6.8523015e+5
+exponential: 685.230_15e+03
+fixed: 685_230.15
+sexagesimal: 190:20:30.15
+negative infinity: -.inf
+not a number: .NaN
diff --git a/tests/data/construct-int.code b/tests/data/construct-int.code
new file mode 100644
index 0000000..1058f7b
--- /dev/null
+++ b/tests/data/construct-int.code
@@ -0,0 +1,8 @@
+{
+    "canonical": 685230,
+    "decimal": 685230,
+    "octal": 685230,
+    "hexadecimal": 685230,
+    "binary": 685230,
+    "sexagesimal": 685230,
+}
diff --git a/tests/data/construct-int.data b/tests/data/construct-int.data
new file mode 100644
index 0000000..852c314
--- /dev/null
+++ b/tests/data/construct-int.data
@@ -0,0 +1,6 @@
+canonical: 685230
+decimal: +685_230
+octal: 02472256
+hexadecimal: 0x_0A_74_AE
+binary: 0b1010_0111_0100_1010_1110
+sexagesimal: 190:20:30
diff --git a/tests/data/construct-map.code b/tests/data/construct-map.code
new file mode 100644
index 0000000..736ba48
--- /dev/null
+++ b/tests/data/construct-map.code
@@ -0,0 +1,6 @@
+{
+    "Block style":
+        { "Clark" : "Evans", "Brian" : "Ingerson", "Oren" : "Ben-Kiki" },
+    "Flow style":
+        { "Clark" : "Evans", "Brian" : "Ingerson", "Oren" : "Ben-Kiki" },
+}
diff --git a/tests/data/construct-map.data b/tests/data/construct-map.data
new file mode 100644
index 0000000..022446d
--- /dev/null
+++ b/tests/data/construct-map.data
@@ -0,0 +1,6 @@
+# Unordered set of key: value pairs.
+Block style: !!map
+  Clark : Evans
+  Brian : Ingerson
+  Oren  : Ben-Kiki
+Flow style: !!map { Clark: Evans, Brian: Ingerson, Oren: Ben-Kiki }
diff --git a/tests/data/construct-merge.code b/tests/data/construct-merge.code
new file mode 100644
index 0000000..6cd419d
--- /dev/null
+++ b/tests/data/construct-merge.code
@@ -0,0 +1,10 @@
+[
+    { "x": 1, "y": 2 },
+    { "x": 0, "y": 2 },
+    { "r": 10 },
+    { "r": 1 },
+    { "x": 1, "y": 2, "r": 10, "label": "center/big" },
+    { "x": 1, "y": 2, "r": 10, "label": "center/big" },
+    { "x": 1, "y": 2, "r": 10, "label": "center/big" },
+    { "x": 1, "y": 2, "r": 10, "label": "center/big" },
+]
diff --git a/tests/data/construct-merge.data b/tests/data/construct-merge.data
new file mode 100644
index 0000000..3fdb2e2
--- /dev/null
+++ b/tests/data/construct-merge.data
@@ -0,0 +1,27 @@
+---
+- &CENTER { x: 1, 'y': 2 }
+- &LEFT { x: 0, 'y': 2 }
+- &BIG { r: 10 }
+- &SMALL { r: 1 }
+
+# All the following maps are equal:
+
+- # Explicit keys
+  x: 1
+  'y': 2
+  r: 10
+  label: center/big
+
+- # Merge one map
+  << : *CENTER
+  r: 10
+  label: center/big
+
+- # Merge multiple maps
+  << : [ *CENTER, *BIG ]
+  label: center/big
+
+- # Override
+  << : [ *BIG, *LEFT, *SMALL ]
+  x: 1
+  label: center/big
diff --git a/tests/data/construct-null.code b/tests/data/construct-null.code
new file mode 100644
index 0000000..a895eaa
--- /dev/null
+++ b/tests/data/construct-null.code
@@ -0,0 +1,13 @@
+[
+    None,
+    { "empty": None, "canonical": None, "english": None, None: "null key" },
+    {
+        "sparse": [
+            None,
+            "2nd entry",
+            None,
+            "4th entry",
+            None,
+        ],
+    },
+]
diff --git a/tests/data/construct-null.data b/tests/data/construct-null.data
new file mode 100644
index 0000000..9ad0344
--- /dev/null
+++ b/tests/data/construct-null.data
@@ -0,0 +1,18 @@
+# A document may be null.
+---
+---
+# This mapping has four keys,
+# one has a value.
+empty:
+canonical: ~
+english: null
+~: null key
+---
+# This sequence has five
+# entries, two have values.
+sparse:
+  - ~
+  - 2nd entry
+  -
+  - 4th entry
+  - Null
diff --git a/tests/data/construct-omap.code b/tests/data/construct-omap.code
new file mode 100644
index 0000000..f4cf1b8
--- /dev/null
+++ b/tests/data/construct-omap.code
@@ -0,0 +1,8 @@
+{
+    "Bestiary": [
+        ("aardvark", "African pig-like ant eater. Ugly."),
+        ("anteater", "South-American ant eater. Two species."),
+        ("anaconda", "South-American constrictor snake. Scaly."),
+    ],
+    "Numbers": [ ("one", 1), ("two", 2), ("three", 3) ],
+}
diff --git a/tests/data/construct-omap.data b/tests/data/construct-omap.data
new file mode 100644
index 0000000..4fa0f45
--- /dev/null
+++ b/tests/data/construct-omap.data
@@ -0,0 +1,8 @@
+# Explicitly typed ordered map (dictionary).
+Bestiary: !!omap
+  - aardvark: African pig-like ant eater. Ugly.
+  - anteater: South-American ant eater. Two species.
+  - anaconda: South-American constrictor snake. Scaly.
+  # Etc.
+# Flow style
+Numbers: !!omap [ one: 1, two: 2, three : 3 ]
diff --git a/tests/data/construct-pairs.code b/tests/data/construct-pairs.code
new file mode 100644
index 0000000..64f86ee
--- /dev/null
+++ b/tests/data/construct-pairs.code
@@ -0,0 +1,9 @@
+{
+    "Block tasks": [
+        ("meeting", "with team."),
+        ("meeting", "with boss."),
+        ("break", "lunch."),
+        ("meeting", "with client."),
+    ],
+    "Flow tasks": [ ("meeting", "with team"), ("meeting", "with boss") ],
+}
diff --git a/tests/data/construct-pairs.data b/tests/data/construct-pairs.data
new file mode 100644
index 0000000..05f55b9
--- /dev/null
+++ b/tests/data/construct-pairs.data
@@ -0,0 +1,7 @@
+# Explicitly typed pairs.
+Block tasks: !!pairs
+  - meeting: with team.
+  - meeting: with boss.
+  - break: lunch.
+  - meeting: with client.
+Flow tasks: !!pairs [ meeting: with team, meeting: with boss ]
diff --git a/tests/data/construct-seq.code b/tests/data/construct-seq.code
new file mode 100644
index 0000000..0c90c05
--- /dev/null
+++ b/tests/data/construct-seq.code
@@ -0,0 +1,4 @@
+{
+    "Block style": ["Mercury", "Venus", "Earth", "Mars", "Jupiter", "Saturn", "Uranus", "Neptune", "Pluto"],
+    "Flow style": ["Mercury", "Venus", "Earth", "Mars", "Jupiter", "Saturn", "Uranus", "Neptune", "Pluto"],
+}
diff --git a/tests/data/construct-seq.data b/tests/data/construct-seq.data
new file mode 100644
index 0000000..bb92fd1
--- /dev/null
+++ b/tests/data/construct-seq.data
@@ -0,0 +1,15 @@
+# Ordered sequence of nodes
+Block style: !!seq
+- Mercury   # Rotates - no light/dark sides.
+- Venus     # Deadliest. Aptly named.
+- Earth     # Mostly dirt.
+- Mars      # Seems empty.
+- Jupiter   # The king.
+- Saturn    # Pretty.
+- Uranus    # Where the sun hardly shines.
+- Neptune   # Boring. No rings.
+- Pluto     # You call this a planet?
+Flow style: !!seq [ Mercury, Venus, Earth, Mars,      # Rocks
+                    Jupiter, Saturn, Uranus, Neptune, # Gas
+                    Pluto ]                           # Overrated
+
diff --git a/tests/data/construct-set.code b/tests/data/construct-set.code
new file mode 100644
index 0000000..aa090e8
--- /dev/null
+++ b/tests/data/construct-set.code
@@ -0,0 +1,4 @@
+{
+    "baseball players": set(["Mark McGwire", "Sammy Sosa", "Ken Griffey"]),
+    "baseball teams": set(["Boston Red Sox", "Detroit Tigers", "New York Yankees"]),
+}
diff --git a/tests/data/construct-set.data b/tests/data/construct-set.data
new file mode 100644
index 0000000..e05dc88
--- /dev/null
+++ b/tests/data/construct-set.data
@@ -0,0 +1,7 @@
+# Explicitly typed set.
+baseball players: !!set
+  ? Mark McGwire
+  ? Sammy Sosa
+  ? Ken Griffey
+# Flow style
+baseball teams: !!set { Boston Red Sox, Detroit Tigers, New York Yankees }
diff --git a/tests/data/construct-str.code b/tests/data/construct-str.code
new file mode 100644
index 0000000..8d57214
--- /dev/null
+++ b/tests/data/construct-str.code
@@ -0,0 +1 @@
+{ "string": "abcd" }
diff --git a/tests/data/construct-str.data b/tests/data/construct-str.data
new file mode 100644
index 0000000..606ac6b
--- /dev/null
+++ b/tests/data/construct-str.data
@@ -0,0 +1 @@
+string: abcd
diff --git a/tests/data/construct-timestamp.code b/tests/data/construct-timestamp.code
new file mode 100644
index 0000000..288022e
--- /dev/null
+++ b/tests/data/construct-timestamp.code
@@ -0,0 +1,7 @@
+{
+    "canonical": datetime.datetime(2001, 12, 15, 2, 59, 43, 100000),
+    "valid iso8601": datetime.datetime(2001, 12, 15, 2, 59, 43, 100000),
+    "space separated": datetime.datetime(2001, 12, 15, 2, 59, 43, 100000),
+    "no time zone (Z)": datetime.datetime(2001, 12, 15, 2, 59, 43, 100000),
+    "date (00:00:00Z)": datetime.datetime(2002, 12, 14),
+}
diff --git a/tests/data/construct-timestamp.data b/tests/data/construct-timestamp.data
new file mode 100644
index 0000000..c5f3840
--- /dev/null
+++ b/tests/data/construct-timestamp.data
@@ -0,0 +1,5 @@
+canonical:        2001-12-15T02:59:43.1Z
+valid iso8601:    2001-12-14t21:59:43.10-05:00
+space separated:  2001-12-14 21:59:43.10 -5
+no time zone (Z): 2001-12-15 2:59:43.10
+date (00:00:00Z): 2002-12-14
diff --git a/tests/data/construct-value.code b/tests/data/construct-value.code
new file mode 100644
index 0000000..f1f015e
--- /dev/null
+++ b/tests/data/construct-value.code
@@ -0,0 +1,9 @@
+[
+    { "link with": [ "library1.dll", "library2.dll" ] },
+    {
+        "link with": [
+            { "=": "library1.dll", "version": 1.2 },
+            { "=": "library2.dll", "version": 2.3 },
+        ],
+    },
+]
diff --git a/tests/data/construct-value.data b/tests/data/construct-value.data
new file mode 100644
index 0000000..3eb7919
--- /dev/null
+++ b/tests/data/construct-value.data
@@ -0,0 +1,10 @@
+---     # Old schema
+link with:
+  - library1.dll
+  - library2.dll
+---     # New schema
+link with:
+  - = : library1.dll
+    version: 1.2
+  - = : library2.dll
+    version: 2.3
diff --git a/tests/data/duplicate-key.error-message b/tests/data/duplicate-key.error-message
new file mode 100644
index 0000000..84deb8f
--- /dev/null
+++ b/tests/data/duplicate-key.error-message
@@ -0,0 +1,3 @@
+---
+foo: bar
+foo: baz
diff --git a/tests/data/duplicate-merge-key.error-message b/tests/data/duplicate-merge-key.error-message
new file mode 100644
index 0000000..cebc3a1
--- /dev/null
+++ b/tests/data/duplicate-merge-key.error-message
@@ -0,0 +1,4 @@
+---
+<<: {x: 1, y: 2}
+foo: bar
+<<: {z: 3, t: 4}
diff --git a/tests/data/duplicate-value-key.error-message b/tests/data/duplicate-value-key.error-message
new file mode 100644
index 0000000..b34a1d6
--- /dev/null
+++ b/tests/data/duplicate-value-key.error-message
@@ -0,0 +1,4 @@
+---
+=: 1
+foo: bar
+=: 2
diff --git a/tests/data/expected-mapping.error-message b/tests/data/expected-mapping.error-message
new file mode 100644
index 0000000..82aed98
--- /dev/null
+++ b/tests/data/expected-mapping.error-message
@@ -0,0 +1 @@
+--- !!map [not, a, map]
diff --git a/tests/data/expected-scalar.error-message b/tests/data/expected-scalar.error-message
new file mode 100644
index 0000000..7b3171e
--- /dev/null
+++ b/tests/data/expected-scalar.error-message
@@ -0,0 +1 @@
+--- !!str [not a scalar]
diff --git a/tests/data/expected-sequence.error-message b/tests/data/expected-sequence.error-message
new file mode 100644
index 0000000..08074ea
--- /dev/null
+++ b/tests/data/expected-sequence.error-message
@@ -0,0 +1 @@
+--- !!seq {foo, bar, baz}
diff --git a/tests/data/invalid-base64-data.error-message b/tests/data/invalid-base64-data.error-message
new file mode 100644
index 0000000..798abba
--- /dev/null
+++ b/tests/data/invalid-base64-data.error-message
@@ -0,0 +1,2 @@
+--- !!binary
+    binary data encoded in base64 should be here.
diff --git a/tests/data/invalid-merge-1.error-message b/tests/data/invalid-merge-1.error-message
new file mode 100644
index 0000000..fc3c284
--- /dev/null
+++ b/tests/data/invalid-merge-1.error-message
@@ -0,0 +1,2 @@
+foo: bar
+<<: baz
diff --git a/tests/data/invalid-merge-2.error-message b/tests/data/invalid-merge-2.error-message
new file mode 100644
index 0000000..8e88615
--- /dev/null
+++ b/tests/data/invalid-merge-2.error-message
@@ -0,0 +1,2 @@
+foo: bar
+<<: [x: 1, y: 2, z, t: 4]
diff --git a/tests/data/invalid-omap-1.error-message b/tests/data/invalid-omap-1.error-message
new file mode 100644
index 0000000..2863392
--- /dev/null
+++ b/tests/data/invalid-omap-1.error-message
@@ -0,0 +1,3 @@
+--- !!omap
+foo: bar
+baz: bat
diff --git a/tests/data/invalid-omap-2.error-message b/tests/data/invalid-omap-2.error-message
new file mode 100644
index 0000000..c377dfb
--- /dev/null
+++ b/tests/data/invalid-omap-2.error-message
@@ -0,0 +1,3 @@
+--- !!omap
+- foo: bar
+- baz
diff --git a/tests/data/invalid-omap-3.error-message b/tests/data/invalid-omap-3.error-message
new file mode 100644
index 0000000..2a4f50d
--- /dev/null
+++ b/tests/data/invalid-omap-3.error-message
@@ -0,0 +1,4 @@
+--- !!omap
+- foo: bar
+- baz: bar
+  bar: bar
diff --git a/tests/data/invalid-pairs-1.error-message b/tests/data/invalid-pairs-1.error-message
new file mode 100644
index 0000000..42d19ae
--- /dev/null
+++ b/tests/data/invalid-pairs-1.error-message
@@ -0,0 +1,3 @@
+--- !!pairs
+foo: bar
+baz: bat
diff --git a/tests/data/invalid-pairs-2.error-message b/tests/data/invalid-pairs-2.error-message
new file mode 100644
index 0000000..31389ea
--- /dev/null
+++ b/tests/data/invalid-pairs-2.error-message
@@ -0,0 +1,3 @@
+--- !!pairs
+- foo: bar
+- baz
diff --git a/tests/data/invalid-pairs-3.error-message b/tests/data/invalid-pairs-3.error-message
new file mode 100644
index 0000000..f8d7704
--- /dev/null
+++ b/tests/data/invalid-pairs-3.error-message
@@ -0,0 +1,4 @@
+--- !!pairs
+- foo: bar
+- baz: bar
+  bar: bar
diff --git a/tests/data/unacceptable-key.error-message b/tests/data/unacceptable-key.error-message
new file mode 100644
index 0000000..d748e37
--- /dev/null
+++ b/tests/data/unacceptable-key.error-message
@@ -0,0 +1,4 @@
+---
+? - foo
+  - bar
+: baz
diff --git a/tests/data/undefined-constructor.error-message b/tests/data/undefined-constructor.error-message
new file mode 100644
index 0000000..9a37ccc
--- /dev/null
+++ b/tests/data/undefined-constructor.error-message
@@ -0,0 +1 @@
+--- !foo bar
diff --git a/tests/test_constructor.py b/tests/test_constructor.py
new file mode 100644
index 0000000..e3895fa
--- /dev/null
+++ b/tests/test_constructor.py
@@ -0,0 +1,86 @@
+
+import test_appliance
+try:
+    import datetime
+except ImportError:
+    pass
+
+from yaml import *
+
+class MyConstructor(Constructor):
+    pass
+
+class MyTestClass1:
+
+    def __init__(self, x, y=0, z=0):
+        self.x = x
+        self.y = y
+        self.z = z
+
+    def __eq__(self, other):
+        return self.__class__, self.__dict__ == other.__class__, other.__dict__
+
+def construct1(constructor, node):
+    mapping = constructor.construct_mapping(node)
+    return MyTestClass1(**mapping)
+
+MyConstructor.add_constructor("!tag1", construct1)
+
+class MyTestClass2(MyTestClass1, YAMLObject):
+
+    yaml_constructor = MyConstructor
+    yaml_tag = "!tag2"
+
+    def from_yaml(cls, constructor, node):
+        x = constructor.construct_yaml_int(node)
+        return cls(x=x)
+    from_yaml = classmethod(from_yaml)
+
+class MyTestClass3(MyTestClass2):
+
+    yaml_tag = "!tag3"
+
+    def from_yaml(cls, constructor, node):
+        mapping = constructor.construct_mapping(node)
+        if '=' in mapping:
+            x = mapping['=']
+            del mapping['=']
+            mapping['x'] = x
+        return cls(**mapping)
+    from_yaml = classmethod(from_yaml)
+
+class TestTypes(test_appliance.TestAppliance):
+
+    def _testTypes(self, test_name, data_filename, code_filename):
+        natives1 = None
+        natives2 = None
+        try:
+            constructor1 = MyConstructor(Resolver(Composer(Parser(Scanner(Reader(file(data_filename, 'rb')))))))
+            natives1 = list(iter(constructor1))
+            if len(natives1) == 1:
+                natives1 = natives1[0]
+            natives2 = eval(file(code_filename, 'rb').read())
+            try:
+                self.failUnlessEqual(natives1, natives2)
+            except AssertionError:
+                if isinstance(natives1, dict):
+                    natives1 = natives1.items()
+                    natives1.sort()
+                    natives1 = repr(natives1)
+                    natives2 = natives2.items()
+                    natives2.sort()
+                    natives2 = repr(natives2)
+                if natives1 != natives2:
+                    raise
+        except:
+            print
+            print "DATA:"
+            print file(data_filename, 'rb').read()
+            print "CODE:"
+            print file(code_filename, 'rb').read()
+            print "NATIVES1:", natives1
+            print "NATIVES2:", natives2
+            raise
+
+TestTypes.add_tests('testTypes', '.data', '.code')
+
diff --git a/tests/test_errors.py b/tests/test_errors.py
index 43834cb..74ba9f2 100644
--- a/tests/test_errors.py
+++ b/tests/test_errors.py
@@ -1,12 +1,7 @@
 
 import test_appliance
 
-from yaml.error import YAMLError
-from yaml.reader import *
-from yaml.scanner import *
-from yaml.parser import *
-from yaml.composer import *
-from yaml.resolver import *
+from yaml import *
 
 class TestErrors(test_appliance.TestAppliance):
 
@@ -25,7 +20,8 @@
             parser = Parser(scanner)
             composer = Composer(parser)
             resolver = Resolver(composer)
-            return list(composer)
+            constructor = Constructor(resolver)
+            return list(constructor)
         except YAMLError, exc:
         #except ScannerError, exc:
         #except ParserError, exc:
@@ -41,14 +37,16 @@
             parser = Parser(scanner)
             composer = Composer(parser)
             resolver = Resolver(composer)
-            return list(composer)
-        except YAMLError, exc:
+            constructor = Constructor(resolver)
+            return list(constructor)
+        #except YAMLError, exc:
         #except ScannerError, exc:
         #except ParserError, exc:
         #except ComposerError, exc:
-            #print '.'*70
-            #print "%s:" % filename
-            #print "%s:" % exc.__class__.__name__, exc
+        except ConstructorError, exc:
+            print '.'*70
+            print "%s:" % filename
+            print "%s:" % exc.__class__.__name__, exc
             raise
 
 TestErrors.add_tests('testErrors', '.error-message')
diff --git a/tests/test_yaml.py b/tests/test_yaml.py
index ccdd8d5..cfd4e79 100644
--- a/tests/test_yaml.py
+++ b/tests/test_yaml.py
@@ -8,6 +8,7 @@
 from test_structure import *
 from test_errors import *
 from test_detector import *
+from test_constructor import *
 from test_syck import *
 
 def main(module='__main__'):