$include_dir="/home/hyper-archives/boost-commit/include"; include("$include_dir/msg-header.inc") ?>
From: ghost_at_[hidden]
Date: 2007-10-19 18:44:31
Author: vladimir_prus
Date: 2007-10-19 18:44:30 EDT (Fri, 19 Oct 2007)
New Revision: 40201
URL: http://svn.boost.org/trac/boost/changeset/40201
Log:
Revise feature.py.
Text files modified: 
   branches/build/python_port/python/boost/build/build/feature.py |   609 ++++++++++++++++++++++----------------- 
   1 files changed, 335 insertions(+), 274 deletions(-)
Modified: branches/build/python_port/python/boost/build/build/feature.py
==============================================================================
--- branches/build/python_port/python/boost/build/build/feature.py	(original)
+++ branches/build/python_port/python/boost/build/build/feature.py	2007-10-19 18:44:30 EDT (Fri, 19 Oct 2007)
@@ -1,7 +1,11 @@
-#  (C) Copyright David Abrahams 2001. Permission to copy, use, modify, sell and
-#  distribute this software is granted provided this copyright notice appears in
-#  all copies. This software is provided "as is" without express or implied
-#  warranty, and with no claim as to its suitability for any purpose.
+# Status: mostly ported.
+# TODO: carry over tests.
+#
+# Copyright 2001, 2002, 2003 Dave Abrahams 
+# Copyright 2002, 2006 Rene Rivera 
+# Copyright 2002, 2003, 2004, 2005, 2006 Vladimir Prus 
+# Distributed under the Boost Software License, Version 1.0. 
+# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) 
 
 # TODO: stop using grists to identify the name of features?
 #       create a class for Features and Properties?
@@ -73,6 +77,8 @@
     """
     return __all_features.iteritems ()
 
+# FIXME: prepare-test/finish-test?
+
 def feature (name, values, attributes = []):
     """ Declares a new feature with the given name, values, and attributes.
         name: the feature name
@@ -83,71 +89,30 @@
 
     __validate_feature_attributes (name, attributes)
 
-    empty_feature = { 
+    feature = { 
         'values': [],
-        'attributes': [],
+        'attributes': attributes,
         'subfeatures': [],
         'default': None
         }
+    __all_features [name] = feature
     
-    feature = __all_features.get (name, empty_feature)
-    
-    # TODO: do we allow overriding a feature's attributes
     feature ['attributes'] = attributes
     
     for attribute in attributes:
         __features_with_attributes [attribute].append (name)
-
-    __all_features [name] = feature
-    
-    if not 'subfeature' in attributes:
-        __all_top_features.append (name)
+        
+    if 'subfeature' in attributes:
+        __all_subfeatures.append(name)
+    else:
+        __all_top_features.append(name)
 
     extend_feature (name, values)
 
+    # FIXME: why his is needed.
     if 'free' in attributes:
         __free_features.append (name)
 
-# TODO: Porting note:
-# rule extend was defined as below:
-    # Can be called three ways:
-    #
-    #    1. extend feature : values *
-    #    2. extend <feature> subfeature : values *
-    #    3. extend <feature>value-string subfeature : values *
-    #
-    # * Form 1 adds the given values to the given feature
-    # * Forms 2 and 3 add subfeature values to the given feature
-    # * Form 3 adds the subfeature values as specific to the given
-    #   property value-string.
-    #
-    #rule extend ( feature-or-property subfeature ? : values * )
-#
-# Now, the specific rule must be called, depending on the desired operation:
-#   extend_feature
-#   extend_subfeature
-
-def extend_feature (name, values):
-    """ Adds the given values to the given feature.
-    """
-    name = add_grist (name)
-    __validate_feature (name)
-    feature = __all_features [name]
-    
-    if 'implicit' in feature ['attributes']:
-        for v in values:
-            if __implicit_features.has_key (v):
-                raise BaseException ("'%s' is already associated with the feature '%s'" % (v, __implicit_features [v]))
-
-            __implicit_features [v] = name
-
-    if len (feature ['values']) == 0 and len (values) > 0:
-        # This is the first value specified for this feature,
-        # take it as default value
-        feature ['default'] = values [0]
-
-    feature ['values'].extend (values)
-
 def set_default (feature, value):
     """ Sets the default value of the given feature, overriding any previous default.
         feature: the name of the feature
@@ -160,24 +125,91 @@
 
     f ['default'] = value
 
+def defaults (features):
+    """ Returns the default property values for the given features.
+    """
+    result = []
+    for f in features:
+        attributes = __all_features [f]['attributes']
+        if not 'free' in attributes and not 'optional' in attributes:
+            defaults = __all_features [f]['default']
+            if defaults:
+                result.append (replace_grist (defaults, f))
 
-def compose (composite_property, component_properties):
-    """ Sets the components of the given composite property.
+    return result
+
+def valid (names):
+    """ Returns true iff all elements of names are valid features.
     """
-    component_properties = to_seq (component_properties)
+    def valid_one (name): return __all_features.has_key (name)
+        
+    if isinstance (names, str):
+        return valid_one (names)
+    else:
+        return [ valid_one (name) for name in names ]
 
-    feature = get_grist (composite_property)
-    if not 'composite' in attributes (feature):
-        raise BaseException ("'%s' is not a composite feature" % feature)
+def attributes (feature):
+    """ Returns the attributes of the given feature.
+    """
+    return __all_features [feature]['attributes']
+        
+def values (feature):
+    """ Return the values of the given feature.
+    """
+    validate_feature (feature)
+    return __all_features [feature]['values']
 
-    if __composite_properties.has_key (composite_property):
-        raise BaseException ('components of "%s" already set: %s' % (composite_property, str (__composite_properties [composite_property]['components'])))
+def is_implicit_value (value_string):
+    """ Returns true iff 'value_string' is a value_string
+    of an implicit feature.
+    """
+    v = value_string.split('-')
+    
+    if not __implicit_features.has_key(v[0]):
+        return False
 
-    if composite_property in component_properties:
-        raise BaseException ('composite property "%s" cannot have itself as a component' % composite_property)
+    feature = __implicit_features[v[0]]
+    
+    for subvalue in (v[1:]):
+        if not __find_implied_subfeature(feature, subvalue, v[0]):
+            return False
+            
+    return True
 
-    entry = { 'components': component_properties }
-    __composite_properties [composite_property] = entry
+def implied_feature (implicit_value):
+    """ Returns the implicit feature associated with the given implicit value.
+    """
+    components = implicit_value.split('-')
+    
+    if not __implicit_features.has_key(components[0]):
+        raise InvalidValue ("'%s' is not a value of an implicit feature" % implicit_value)
+        
+    return __implicit_features[components[0]]
+
+def __find_implied_subfeature (feature, subvalue, value_string):
+    feature = add_grist (feature)
+    if value_string == None: value_string = ''
+
+    if not __subfeature_value_to_name.has_key (feature) \
+        or not __subfeature_value_to_name [feature].has_key (value_string) \
+        or not __subfeature_value_to_name [feature][value_string].has_key (subvalue):
+        return None
+        
+    return __subfeature_value_to_name[feature][value_string][subvalue]
+
+# Given a feature and a value of one of its subfeatures, find the name
+# of the subfeature. If value-string is supplied, looks for implied
+# subfeatures that are specific to that value of feature
+#  feature             # The main feature name
+#  subvalue            # The value of one of its subfeatures
+#  value-string        # The value of the main feature
+
+def implied_subfeature (feature, subvalue, value_string):
+    result = __find_implied_subfeature (feature, subvalue, value_string)
+    if not result:
+        raise InvalidValue ("'%s' is not a known subfeature value of '%s%s'" % (subvalue, feature, value_string))
+
+    return result
 
 def validate_feature (name):
     """ Checks if all name is a valid feature. Otherwise, raises an exception.
@@ -196,48 +228,146 @@
     else:
         return [ valid_one (name) for name in names ]
 
-def attributes (feature):
-    """ Returns the attributes of the given feature.
+def __expand_subfeatures_aux (feature, value, dont_validate = False):
+    """ Helper for expand_subfeatures.
+        Given a feature and value, or just a value corresponding to an
+        implicit feature, returns a property set consisting of all component
+        subfeatures and their values. For example:
+        
+          expand_subfeatures <toolset>gcc-2.95.2-linux-x86
+              -> <toolset>gcc <toolset-version>2.95.2 <toolset-os>linux <toolset-cpu>x86
+          equivalent to:
+              expand_subfeatures gcc-2.95.2-linux-x86
+
+        feature:        The name of the feature, or empty if value corresponds to an implicit property
+        value:          The value of the feature.
+        dont_validate:  If True, no validation of value string will be done.
     """
-    validate_feature (feature)
-    return __all_features [feature]['attributes']
+    if not feature:
+        feature = implied_feature(value)
+    else:
+        validate_feature(feature)
 
-def defaults (features):
-    """ Returns the default property values for the given features.
+    if not dont_validate:
+        validate_value_string(feature, value)
+    
+    components = value.split ("-")
+    
+    # get the top-level feature's value
+    value = replace_grist(components[0], '')
+
+    result = [ replace_grist(components[0], feature) ]
+    
+    subvalues = components[1:]
+
+    while len(subvalues) > 0:
+        subvalue = subvalues [0]    # pop the head off of subvalues
+        subvalues = subvalues [1:]
+        
+        subfeature = __find_implied_subfeature (feature, subvalue, value)
+        
+        # If no subfeature was found, reconstitute the value string and use that
+        if not subfeature:
+            result = '-'.join(components)
+            result = replace_grist (result, feature)
+            return [result]
+            
+        f = ungrist (feature)
+        # FIXME: why grist includes '<>'?
+        result.append (replace_grist (subvalue, '<' + f + '-' + subfeature + '>'))
+    
+    return result
+
+def expand_subfeatures (properties, dont_validate = False):
+    """
+    Make all elements of properties corresponding to implicit features
+    explicit, and express all subfeature values as separate properties
+    in their own right. For example, the property
+    
+       gcc-2.95.2-linux-x86
+    
+    might expand to
+    
+      <toolset>gcc <toolset-version>2.95.2 <toolset-os>linux <toolset-cpu>x86
+
+    properties:     A sequence with elements of the form
+                    <feature>value-string or just value-string in the
+                    case of implicit features.
+  : dont_validate:  If True, no validation of value string will be done.
     """
     result = []
-    for f in features:
-        validate_feature (f)
-        attributes = __all_features [f]['attributes']
-        if not 'free' in attributes and not 'optional' in attributes:
-            defaults = __all_features [f]['default']
-            if defaults:
-                result.append (replace_grist (defaults, f))
+    for p in properties:
+        p_grist = get_grist (p)
+        # Don't expand subfeatures in subfeatures
+        if ':' in p_grist:
+            result.append (p)
+        else:
+            result.extend (__expand_subfeatures_aux (p_grist, replace_grist (p, ''), dont_validate))
 
     return result
 
-def values (feature):
-    """ Return the values of the given feature.
-    """
-    validate_feature (feature)
-    return __all_features [feature]['values']
 
 
-def is_implicit_value (value_string):
-    """ Returns true iff 'value_string' is a value_string of an implicit feature.
+# rule extend was defined as below:
+    # Can be called three ways:
+    #
+    #    1. extend feature : values *
+    #    2. extend <feature> subfeature : values *
+    #    3. extend <feature>value-string subfeature : values *
+    #
+    # * Form 1 adds the given values to the given feature
+    # * Forms 2 and 3 add subfeature values to the given feature
+    # * Form 3 adds the subfeature values as specific to the given
+    #   property value-string.
+    #
+    #rule extend ( feature-or-property subfeature ? : values * )
+#
+# Now, the specific rule must be called, depending on the desired operation:
+#   extend_feature
+#   extend_subfeature
+
+def extend_feature (name, values):
+    """ Adds the given values to the given feature.
     """
-    v = value_string.split ('-')
+    name = add_grist (name)
+    __validate_feature (name)
+    feature = __all_features [name]
     
-    if not __implicit_features.has_key (v [0]):
-        return False
+    if 'implicit' in feature ['attributes']:
+        for v in values:
+            if __implicit_features.has_key (v):
+                raise BaseException ("'%s' is already associated with the feature '%s'" % (v, __implicit_features [v]))
+
+            __implicit_features[v] = name
+
+    if len (feature ['values']) == 0 and len (values) > 0:
+        # This is the first value specified for this feature,
+        # take it as default value
+        feature ['default'] = values[0]
+
+    feature['values'].extend (values)
+
+def validate_value_string (feature, value_string):
+    """ Checks that value-string is a valid value-string for the given feature.
+    """
+    f = __all_features [feature]
+    if 'free' in f ['attributes'] or value_string in f ['values']:
+        return
+
+    values = [value_string]
+
+    if f['subfeatures']:
+        values = value_string.split('-')
+
+    # An empty value is allowed for optional features
+    if not values[0] in f['values'] and \
+           (values[0] or not 'optional' in f['attributes']):
+        raise InvalidValue ("'%s' is not a known value of feature '%s'\nlegal values: '%s'" % (values [0], feature, f ['values']))
+
+    for v in values [1:]:
+        # this will validate any subfeature values in value-string
+        implied_subfeature(feature, v, values[0])
 
-    feature = __implicit_features [v [0]]
-    
-    for subvalue in (v [1:]):
-        if not __find_implied_subfeature (feature, subvalue, v [0]):
-            return False
-            
-    return True
 
 """ Extends the given subfeature with the subvalues.  If the optional
     value-string is provided, the subvalues are only valid for the given
@@ -300,57 +430,83 @@
     # Now make sure the subfeature values are known.
     extend_subfeature (feature_name, value_string, subfeature, subvalues)
 
-
-def implied_feature (implicit_value):
-    """ Returns the implicit feature associated with the given implicit value.
+def compose (composite_property, component_properties):
+    """ Sets the components of the given composite property.
     """
-    components = implicit_value.split ('-')
-    
-    if not __implicit_features.has_key (components [0]):
-        raise InvalidValue ("'%s' is not a value of an implicit feature" % implicit_value)
-        
-    return __implicit_features [components [0]]
+    component_properties = to_seq (component_properties)
 
-def implied_subfeature (feature, subvalue, value_string):
-    result = __find_implied_subfeature (feature, subvalue, value_string)
-    if not result:
-        raise InvalidValue ("'%s' is not a known subfeature value of '%s%s'" % (subvalue, feature, value_string))
+    feature = get_grist (composite_property)
+    if not 'composite' in attributes (feature):
+        raise BaseException ("'%s' is not a composite feature" % feature)
+
+    if __composite_properties.has_key (composite_property):
+        raise BaseException ('components of "%s" already set: %s' % (composite_property, str (__composite_properties [composite_property]['components'])))
+
+    if composite_property in component_properties:
+        raise BaseException ('composite property "%s" cannot have itself as a component' % composite_property)
 
+    entry = { 'components': component_properties }
+    __composite_properties [composite_property] = entry
+
+
+def expand_composite (property):
+    result = [ property ]
+    if __composite_properties.has_key (property):
+        for p in __composite_properties [property]['components']:
+            result.extend (expand_composite (p))
     return result
 
-def expand_subfeatures (properties, dont_validate = False):
-    """
-    Make all elements of properties corresponding to implicit features
-    explicit, and express all subfeature values as separate properties
-    in their own right. For example, the property
-    
-       gcc-2.95.2-linux-x86
-    
-    might expand to
-    
-      <toolset>gcc <toolset-version>2.95.2 <toolset-os>linux <toolset-cpu>x86
 
-    properties:     A sequence with elements of the form
-                    <feature>value-string or just value-string in the
-                    case of implicit features.
-  : dont_validate:  If True, no validation of value string will be done.
+def get_values (feature, properties):
+    """ Returns all values of the given feature specified by the given property set.
     """
     result = []
     for p in properties:
-        p_grist = get_grist (p)
-        # Don't expand subfeatures in subfeatures
-        if ':' in p_grist:
-            result.append (p)
-        else:
-            result.extend (__expand_subfeatures_aux (p_grist, replace_grist (p, ''), dont_validate))
-
+        if get_grist (p) == feature:
+            result.append (replace_grist (p, ''))
+    
     return result
 
 def free_features ():
     """ Returns all free features.
     """
     return __free_features
-    
+
+def expand_composites (properties):
+    """ Expand all composite properties in the set so that all components
+        are explicitly expressed.
+    """
+    explicit_features = get_grist (properties)
+
+    result = []
+
+    # now expand composite features
+    for p in properties:
+        expanded = expand_composite (p)
+
+        for x in expanded:
+            if not x in result:
+                f = get_grist (x)
+
+                if f in __free_features:
+                    result.append (x)
+                elif not x in properties:  # x is the result of expansion
+                    if not f in explicit_features:  # not explicitly-specified
+                        if f in get_grist (result):
+                            raise FeatureConflict ("error expansions of composite features result in "
+                            "conflicting values for '%s'\nvalues: '%s'\none contributing composite property was '%s'" % (f, 
+                            get_values (f, result) + [replace_grist (x, '')], p))
+                        else:
+                            result.append (x)
+                elif f in get_grist (result):
+                    raise FeatureConflict ("error explicitly-specified values of non-free feature '%s' conflict\n"
+                    "existing values: '%s'\nvalue from expanding '%s': '%s'" % (f, 
+                    get_values (f, properties), p, replace_grist (x, '')))
+                else:
+                    result.append (x)
+
+    return result
+
 def is_subfeature_of (parent_property, f):
     """ Return true iff f is an ordinary subfeature of the parent_property's
         feature, or if f is a subfeature of the parent_property's feature
@@ -365,7 +521,7 @@
         # The feature has the form
         # <topfeature-topvalue:subfeature>,
         # e.g. <toolset-msvc:version>
-        feature_value = split_top_feature (specific_subfeature.group (1))
+        feature_value = split_top_feature(specific_subfeature.group(1))
         if replace_grist (feature_value [1], '<' + feature_value [0] + '>') == parent_property:
             return True
     else:
@@ -378,6 +534,46 @@
 
     return False
 
+def __is_subproperty_of (parent_property, p):
+    """ As is_subfeature_of, for subproperties.
+    """
+    return is_subfeature_of (parent_property, get_grist (p))
+
+    
+# Returns true iff the subvalue is valid for the feature.  When the
+# optional value-string is provided, returns true iff the subvalues
+# are valid for the given value of the feature.
+def is_subvalue(feature, value_string, subfeature, subvalue):
+
+    if not value_string:
+        value_string = ''
+
+    if not __subfeature_value_to_name.has_key(feature):
+        return False
+        
+    if not __subfeature_value_to_name[feature].has_key(value_string):
+        return False
+        
+    if not __subfeature_value_to_name[feature][value_string].has_key(subvalue):
+        return False
+
+    if __subfeature_value_to_name[feature][value_string][subvalue]\
+           != subfeature:
+        return False
+
+    return True
+
+
+
+
+def implied_subfeature (feature, subvalue, value_string):
+    result = __find_implied_subfeature (feature, subvalue, value_string)
+    if not result:
+        raise InvalidValue ("'%s' is not a known subfeature value of '%s%s'" % (subvalue, feature, value_string))
+
+    return result
+
+
 def expand (properties):
     """ Given a property set which may consist of composite and implicit
         properties and combined subfeature values, returns an expanded,
@@ -391,48 +587,7 @@
     """
     expanded = expand_subfeatures (properties)
     return expand_composites (expanded)
-
-def expand_composite (property):
-    result = [ property ]
-    if __composite_properties.has_key (property):
-        for p in __composite_properties [property]['components']:
-            result.extend (expand_composite (p))
-    return result
     
-def expand_composites (properties):
-    """ Expand all composite properties in the set so that all components
-        are explicitly expressed.
-    """
-    explicit_features = get_grist (properties)
-
-    result = []
-
-    # now expand composite features
-    for p in properties:
-        expanded = expand_composite (p)
-
-        for x in expanded:
-            if not x in result:
-                f = get_grist (x)
-
-                if f in __free_features:
-                    result.append (x)
-                elif not x in properties:  # x is the result of expansion
-                    if not f in explicit_features:  # not explicitly-specified
-                        if f in get_grist (result):
-                            raise FeatureConflict ("error expansions of composite features result in "
-                            "conflicting values for '%s'\nvalues: '%s'\none contributing composite property was '%s'" % (f, 
-                            get_values (f, result) + [replace_grist (x, '')], p))
-                        else:
-                            result.append (x)
-                elif f in get_grist (result):
-                    raise FeatureConflict ("error explicitly-specified values of non-free feature '%s' conflict\n"
-                    "existing values: '%s'\nvalue from expanding '%s': '%s'" % (f, 
-                    get_values (f, properties), p, replace_grist (x, '')))
-                else:
-                    result.append (x)
-
-    return result
 
 def split_top_feature (feature_plus):
     """ Given an ungristed string, finds the longest prefix which is a
@@ -518,8 +673,8 @@
         Implicit properties will be expressed without feature
         grist, and sub-property values will be expressed as elements joined
         to the corresponding main property.
-    """
-# TODO: the code below was in the original feature.jam file, however 'p' is not defined.
+    """    
+# FXIME: the code below was in the original feature.jam file, however 'p' is not defined.
 #       # Precondition checking
 #       local implicits = [ set.intersection $(p:G=) : $(p:G) ] ;
 #       if $(implicits)
@@ -570,41 +725,14 @@
             # have been eliminated, any remaining property whose
             # feature is the same as a component of a composite in the
             # set must have a non-redundant value.
-            if [fullp] != defaults ([f]) or 'symmetric' in attributes (f) or get_grist (fullp) in get_grist (components):
+            if [fullp] != defaults ([f]) or 'symmetric' in attributes (f)\
+                   or get_grist (fullp) in get_grist (components):
                 result.append (p)
 
             x = x [1:]
 
     return result
 
-def validate_value_string (feature, value_string):
-    """ Checks that value-string is a valid value-string for the given feature.
-    """
-    f = __all_features [feature]
-    if 'free' in f ['attributes'] or value_string in f ['values']:
-        return
-
-    values = [ value_string ]
-
-    if len (f ['subfeatures']) > 0:
-        values = value_string.split ('-')
-
-    if not values [0] in f ['values']:
-        raise InvalidValue ("'%s' is not a known value of feature '%s'\nlegal values: '%s'" % (values [0], feature, f ['values']))
-
-    for v in values [1:]:
-        # this will validate any subfeature values in value-string
-        implied_subfeature (feature, v, values [0])
-
-def get_values (feature, properties):
-    """ Returns all values of the given feature specified by the given property set.
-    """
-    result = []
-    for p in properties:
-        if get_grist (p) == feature:
-            result.append (replace_grist (p, ''))
-    
-    return result
 
 def split (properties):
     """ Given a property-set of the form
@@ -724,66 +852,6 @@
     if not __all_features.has_key (feature):
         raise BaseException ('unknown feature "%s"' % feature)
 
-def __find_implied_subfeature (feature, subvalue, value_string):
-    feature = add_grist (feature)
-    if value_string == None: value_string = ''
-
-    if not __subfeature_value_to_name.has_key (feature) \
-        or not __subfeature_value_to_name [feature].has_key (value_string) \
-        or not __subfeature_value_to_name [feature][value_string].has_key (subvalue):
-        return None
-        
-    return __subfeature_value_to_name [feature][value_string][subvalue]
-
-def __expand_subfeatures_aux (feature, value, dont_validate = False):
-    """ Helper for expand_subfeatures.
-        Given a feature and value, or just a value corresponding to an
-        implicit feature, returns a property set consisting of all component
-        subfeatures and their values. For example:
-        
-          expand_subfeatures <toolset>gcc-2.95.2-linux-x86
-              -> <toolset>gcc <toolset-version>2.95.2 <toolset-os>linux <toolset-cpu>x86
-          equivalent to:
-              expand_subfeatures gcc-2.95.2-linux-x86
-
-        feature:        The name of the feature, or empty if value corresponds to an implicit property
-        value:          The value of the feature.
-        dont_validate:  If True, no validation of value string will be done.
-    """
-    if not feature:
-        feature = implied_feature (value)
-    else:
-        validate_feature (feature)
-
-    if not dont_validate:
-        validate_value_string (feature, value)
-    
-    components = value.split ("-")
-    
-    # get the top-level feature's value
-    value = replace_grist (components [0], '')
-
-    result = [ replace_grist (components [0], feature) ]
-    
-    subvalues = components [1:]
-
-    while len (subvalues) > 0:
-        subvalue = subvalues [0]    # pop the head off of subvalues
-        subvalues = subvalues [1:]
-        
-        subfeature = __find_implied_subfeature (feature, subvalue, value)
-        
-        # If no subfeature was found, reconstitute the value string and use that
-        if not subfeature:
-            result = '-'.join (components)
-            result = replace_grist (result, feature)
-            return [result]
-            
-        f = ungrist (feature)
-        result.append (replace_grist (subvalue, '<' + f + '-' + subfeature + '>'))
-    
-    return result
-
 def __add_to_subfeature_value_to_name_map (feature, value_string, subfeature_name, subvalues):
     # provide a way to get from the given feature or property and
     # subfeature value to the subfeature name.
@@ -798,10 +866,6 @@
     for subvalue in subvalues:
         __subfeature_value_to_name [feature][value_string][subvalue] = subfeature_name
     
-def __is_subproperty_of (parent_property, p):
-    """ As is_subfeature_of, for subproperties.
-    """
-    return is_subfeature_of (parent_property, get_grist (p))
 
 def __select_subfeatures (parent_property, features):
     """ Given a property, return the subset of features consisting of all
@@ -809,9 +873,6 @@
         subfeatures of the property's feature which are conditional on the
         property's value.
     """
-    result = []
-    for f in features:
-        if is_subfeature_of (parent_property, f):
-            result.append (f)
-    return result
+    return [f for f in features if is_subfeature_of (parent_property, f)]
   
+# FIXME: copy over tests.