Boost logo

Boost-Commit :

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.


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk