summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLars Wirzenius <lars.wirzenius@codethink.co.uk>2013-01-29 13:50:46 +0000
committerLars Wirzenius <lars.wirzenius@codethink.co.uk>2013-01-29 14:32:49 +0000
commite06eafcbf0784271f51c0936852d1e97c0ccce8b (patch)
treee7e914cd82348e79b7662e6bd06851a0100e7751
parent63f608d7c05095c16d1a8863b13c55634c0cae8b (diff)
downloadmorph-e06eafcbf0784271f51c0936852d1e97c0ccce8b.tar.gz
Make yaml be an optional dependency
This can go away when we have made a release with yaml in it, and its staging filler.
-rwxr-xr-xcheck9
-rw-r--r--morphlib/__init__.py14
-rw-r--r--morphlib/morph2.py2
-rw-r--r--morphlib/morph2_tests.py34
-rw-r--r--morphlib/morphologyfactory.py3
-rw-r--r--morphlib/yamlparse.py185
-rw-r--r--morphlib/yamlparse_tests.py15
7 files changed, 151 insertions, 111 deletions
diff --git a/check b/check
index 7288e55f..3ee752a4 100755
--- a/check
+++ b/check
@@ -23,9 +23,16 @@ python setup.py clean check
cmdtest tests
cmdtest tests.branching
cmdtest tests.merging
-if [ $(whoami) = root ] && command -v mkfs.btrfs > /dev/null
+if [ $(whoami) = root ] && command -v mkfs.btrfs > /dev/null &&
+ python -c "
+import morphlib, sys
+if not morphlib.got_yaml:
+ sys.exit(1)
+" > /dev/null 2>&1
then
cmdtest tests.as-root
+else
+ echo "NOT RUNNING tests.as-root"
fi
if [ -d .git ];
diff --git a/morphlib/__init__.py b/morphlib/__init__.py
index aba7a4d6..0f60642c 100644
--- a/morphlib/__init__.py
+++ b/morphlib/__init__.py
@@ -17,6 +17,19 @@
'''Baserock library.'''
+# Import yaml if available. This can go away once Baserock has made a
+# release that includes yaml (also in its staging filler).
+try:
+ import yaml
+except ImportError:
+ got_yaml = False
+ class YAMLError(Exception):
+ pass
+else:
+ got_yaml = True
+ YAMLError = yaml.YAMLError
+
+
import cliapp
import gitversion
@@ -57,6 +70,7 @@ import stagingarea
import stopwatch
import tempdir
import util
+
import yamlparse
import app # this needs to be last
diff --git a/morphlib/morph2.py b/morphlib/morph2.py
index edf7bb31..3a3ad679 100644
--- a/morphlib/morph2.py
+++ b/morphlib/morph2.py
@@ -70,7 +70,7 @@ class Morphology(object):
try:
self._dict = self._load_json(text)
self._dumper = self._dump_json
- except Exception, e:
+ except Exception, e: # pragma: no cover
self._dict = morphlib.yamlparse.load(text)
self._dumper = morphlib.yamlparse.dump
self._set_defaults()
diff --git a/morphlib/morph2_tests.py b/morphlib/morph2_tests.py
index 34df4657..7a819556 100644
--- a/morphlib/morph2_tests.py
+++ b/morphlib/morph2_tests.py
@@ -17,6 +17,7 @@
import StringIO
import unittest
+import morphlib
from morphlib.morph2 import Morphology
@@ -41,22 +42,23 @@ class MorphologyTests(unittest.TestCase):
self.assertEqual(m['max-jobs'], None)
self.assertEqual(m['chunks'], [])
- def test_parses_simple_yaml_chunk(self):
- m = Morphology('''
- name: foo
- kind: chunk
- build-system: manual
- ''')
-
- self.assertEqual(m['name'], 'foo')
- self.assertEqual(m['kind'], 'chunk')
- self.assertEqual(m['build-system'], 'manual')
- self.assertEqual(m['configure-commands'], None)
- self.assertEqual(m['build-commands'], None)
- self.assertEqual(m['test-commands'], None)
- self.assertEqual(m['install-commands'], None)
- self.assertEqual(m['max-jobs'], None)
- self.assertEqual(m['chunks'], [])
+ if morphlib.got_yaml:
+ def test_parses_simple_yaml_chunk(self):
+ m = Morphology('''
+ name: foo
+ kind: chunk
+ build-system: manual
+ ''')
+
+ self.assertEqual(m['name'], 'foo')
+ self.assertEqual(m['kind'], 'chunk')
+ self.assertEqual(m['build-system'], 'manual')
+ self.assertEqual(m['configure-commands'], None)
+ self.assertEqual(m['build-commands'], None)
+ self.assertEqual(m['test-commands'], None)
+ self.assertEqual(m['install-commands'], None)
+ self.assertEqual(m['max-jobs'], None)
+ self.assertEqual(m['chunks'], [])
def test_sets_stratum_chunks_repo_and_morph_from_name(self):
m = Morphology('''
diff --git a/morphlib/morphologyfactory.py b/morphlib/morphologyfactory.py
index 261dc908..6625d375 100644
--- a/morphlib/morphologyfactory.py
+++ b/morphlib/morphologyfactory.py
@@ -13,7 +13,6 @@
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-import yaml
import morphlib
import cliapp
@@ -83,7 +82,7 @@ class MorphologyFactory(object):
try:
morphology = morphlib.morph2.Morphology(text)
- except yaml.YAMLError as e:
+ except morphlib.YAMLError as e: # pragma: no cover
raise morphlib.Error("Error parsing %s: %s" %
(filename, str(e)))
diff --git a/morphlib/yamlparse.py b/morphlib/yamlparse.py
index 7f8b00e5..a2832b89 100644
--- a/morphlib/yamlparse.py
+++ b/morphlib/yamlparse.py
@@ -13,13 +13,18 @@
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-import yaml
-import yaml.constructor
+import morphlib
from morphlib.util import OrderedDict
-class OrderedDictYAMLLoader(yaml.Loader):
- """A YAML loader that loads mappings into ordered dictionaries.
+if morphlib.got_yaml: # pragma: no cover
+ yaml = morphlib.yaml
+
+
+if morphlib.got_yaml: # pragma: no cover
+
+ class OrderedDictYAMLLoader(yaml.Loader):
+ """A YAML loader that loads mappings into ordered dictionaries.
When YAML is loaded with this Loader, it loads mappings as ordered
dictionaries, so the order the keys were written in is maintained.
@@ -27,47 +32,48 @@ class OrderedDictYAMLLoader(yaml.Loader):
When combined with the OrderedDictYAMLDumper, this allows yaml documents
to be written out in a similar format to they were read.
- """
-
- def __init__(self, *args, **kwargs):
- yaml.Loader.__init__(self, *args, **kwargs)
-
- # When YAML encounters a mapping (which YAML identifies with
- # the given tag), it will use construct_yaml_map to read it as
- # an OrderedDict.
- self.add_constructor(u'tag:yaml.org,2002:map',
- type(self).construct_yaml_map)
-
- def construct_yaml_map(self, node):
- data = OrderedDict()
- yield data
- value = self.construct_mapping(node)
- data.update(value)
-
- def construct_mapping(self, node, deep=False):
- if isinstance(node, yaml.MappingNode):
- self.flatten_mapping(node)
- else:
- raise yaml.constructor.ConstructorError(
- None, None,
- 'expected a mapping node, but found %s' % node.id,
- node.start_mark)
-
- mapping = OrderedDict()
- for key_node, value_node in node.value:
- key = self.construct_object(key_node, deep=deep)
- try:
- hash(key)
- except TypeError, exc:
- raise yaml.constructor.ConstructorError(
- 'while constructing a mapping', node.start_mark,
- 'found unacceptable key (%s)' % exc, key_node.start_mark)
- value = self.construct_object(value_node, deep=deep)
- mapping[key] = value
- return mapping
+ """
+
+ def __init__(self, *args, **kwargs):
+ yaml.Loader.__init__(self, *args, **kwargs)
-class OrderedDictYAMLDumper(yaml.Dumper):
- """A YAML dumper that will dump OrderedDicts as mappings.
+ # When YAML encounters a mapping (which YAML identifies with
+ # the given tag), it will use construct_yaml_map to read it as
+ # an OrderedDict.
+ self.add_constructor(u'tag:yaml.org,2002:map',
+ type(self).construct_yaml_map)
+
+ def construct_yaml_map(self, node):
+ data = OrderedDict()
+ yield data
+ value = self.construct_mapping(node)
+ data.update(value)
+
+ def construct_mapping(self, node, deep=False):
+ if isinstance(node, yaml.MappingNode):
+ self.flatten_mapping(node)
+ else:
+ raise yaml.constructor.ConstructorError(
+ None, None,
+ 'expected a mapping node, but found %s' % node.id,
+ node.start_mark)
+
+ mapping = OrderedDict()
+ for key_node, value_node in node.value:
+ key = self.construct_object(key_node, deep=deep)
+ try:
+ hash(key)
+ except TypeError, exc:
+ raise yaml.constructor.ConstructorError(
+ 'while constructing a mapping', node.start_mark,
+ 'found unacceptable key (%s)' % exc,
+ key_node.start_mark)
+ value = self.construct_object(value_node, deep=deep)
+ mapping[key] = value
+ return mapping
+
+ class OrderedDictYAMLDumper(yaml.Dumper):
+ """A YAML dumper that will dump OrderedDicts as mappings.
When YAML is dumped with this Dumper, it dumps OrderedDicts as
mappings, preserving the key order, so the order the keys were
@@ -76,44 +82,53 @@ class OrderedDictYAMLDumper(yaml.Dumper):
When combined with the OrderedDictYAMLDumper, this allows yaml documents
to be written out in a similar format to they were read.
- """
-
- def __init__(self, *args, **kwargs):
- yaml.Dumper.__init__(self, *args, **kwargs)
-
- # When YAML sees an OrderedDict, use represent_ordered_dict to dump it
- self.add_representer(OrderedDict,
- type(self).represent_ordered_dict)
-
- def represent_ordered_dict(self, odict):
- return self.represent_ordered_mapping(u'tag:yaml.org,2002:map', odict)
-
- def represent_ordered_mapping(self, tag, omap):
- value = []
- node = yaml.MappingNode(tag, value)
- if self.alias_key is not None:
- self.represented_objects[self.alias_key] = node
- best_style = True
- for item_key, item_value in omap.iteritems():
- node_key = self.represent_data(item_key)
- node_value = self.represent_data(item_value)
- if not (isinstance(node_key, yaml.ScalarNode) and
- not node_key.style):
- best_style = False # pragma: no cover
- if not (isinstance(node_value, yaml.ScalarNode) and
- not node_value.style):
- best_style = False # pragma: no cover
- value.append((node_key, node_value))
- if self.default_flow_style is not None:
- node.flow_style = self.default_flow_style
- else:
- node.flow_style = best_style # pragma: no cover
- return node
-
-def load(*args, **kwargs):
- return yaml.load(Loader=OrderedDictYAMLLoader, *args, **kwargs)
-
-def dump(*args, **kwargs):
- if 'default_flow_style' not in kwargs:
- kwargs['default_flow_style'] = False
- return yaml.dump(Dumper=OrderedDictYAMLDumper, *args, **kwargs)
+ """
+
+ def __init__(self, *args, **kwargs):
+ yaml.Dumper.__init__(self, *args, **kwargs)
+
+ # When YAML sees an OrderedDict, use represent_ordered_dict to
+ # dump it
+ self.add_representer(OrderedDict,
+ type(self).represent_ordered_dict)
+
+ def represent_ordered_dict(self, odict):
+ return self.represent_ordered_mapping(
+ u'tag:yaml.org,2002:map', odict)
+
+ def represent_ordered_mapping(self, tag, omap):
+ value = []
+ node = yaml.MappingNode(tag, value)
+ if self.alias_key is not None:
+ self.represented_objects[self.alias_key] = node
+ best_style = True
+ for item_key, item_value in omap.iteritems():
+ node_key = self.represent_data(item_key)
+ node_value = self.represent_data(item_value)
+ if not (isinstance(node_key, yaml.ScalarNode) and
+ not node_key.style):
+ best_style = False # pragma: no cover
+ if not (isinstance(node_value, yaml.ScalarNode) and
+ not node_value.style):
+ best_style = False # pragma: no cover
+ value.append((node_key, node_value))
+ if self.default_flow_style is not None:
+ node.flow_style = self.default_flow_style
+ else:
+ node.flow_style = best_style # pragma: no cover
+ return node
+
+ def load(*args, **kwargs):
+ return yaml.load(Loader=OrderedDictYAMLLoader, *args, **kwargs)
+
+ def dump(*args, **kwargs):
+ if 'default_flow_style' not in kwargs:
+ kwargs['default_flow_style'] = False
+ return yaml.dump(Dumper=OrderedDictYAMLDumper, *args, **kwargs)
+
+else: # pragma: no cover
+ def load(*args, **kwargs):
+ raise morphlib.Error('YAML not available')
+ def dump(*args, **kwargs):
+ raise morphlib.Error('YAML not available')
+
diff --git a/morphlib/yamlparse_tests.py b/morphlib/yamlparse_tests.py
index cb658e15..f5c2569b 100644
--- a/morphlib/yamlparse_tests.py
+++ b/morphlib/yamlparse_tests.py
@@ -15,17 +15,20 @@
import unittest
-try:
- from collections import OrderedDict
-except ImportError:
- from ordereddict import OrderedDict
-import yaml
-
+import morphlib
import morphlib.yamlparse as yamlparse
+from morphlib.util import OrderedDict
+
+if morphlib.got_yaml:
+ yaml = morphlib.yaml
class YAMLParseTests(unittest.TestCase):
+ def run(self, *args, **kwargs):
+ if morphlib.got_yaml:
+ return unittest.TestCase.run(self, *args, **kwargs)
+
example_text = '''\
name: foo
kind: chunk