parameters: (property_sets, seen_features)
docstring: Returns non-conflicting combinations of property sets.
  
      property_sets is a list of PropertySet instances. seen_features is a set of Property
      instances.
  
      Returns a tuple of:
      - list of lists of Property instances, such that within each list, no two Property instance
      have the same feature, and no Property is for feature in seen_features.
      - set of features we saw in property_sets
docstring_summary: Returns non-conflicting combinations of property sets.
docstring_tokens: Returns non - conflicting combinations of property sets .
function: def __x_product_aux (property_sets, seen_features):
      """Returns non-conflicting combinations of property sets.
  
      property_sets is a list of PropertySet instances. seen_features is a set of Property
      instances.
  
      Returns a tuple of:
      - list of lists of Property instances, such that within each list, no two Property instance
      have the same feature, and no Property is for feature in seen_features.
      - set of features we saw in property_sets      
      """
      if not property_sets:
          return ([], set())
  
      properties = property_sets[0].all()
  
      these_features = set()
      for p in property_sets[0].non_free():
          these_features.add(p.feature())
  
      # Note: the algorithm as implemented here, as in original Jam code, appears to
      # detect conflicts based on features, not properties. For example, if command
      # line build request say:
      #
      # <a>1/<b>1 c<1>/<b>1
      #
      # It will decide that those two property sets conflict, because they both specify
      # a value for 'b' and will not try building "<a>1 <c1> <b1>", but rather two
      # different property sets. This is a topic for future fixing, maybe.
      if these_features & seen_features:
  
          (inner_result, inner_seen) = __x_product_aux(property_sets[1:], seen_features)
          return (inner_result, inner_seen | these_features)
  
      else:
  
          result = []
          (inner_result, inner_seen) = __x_product_aux(property_sets[1:], seen_features | these_features)
          if inner_result:
              for inner in inner_result:
                  result.append(properties + inner)
          else:
              result.append(properties)
          
          if inner_seen & these_features:
              # Some of elements in property_sets[1:] conflict with elements of property_sets[0],
              # Try again, this time omitting elements of property_sets[0]
              (inner_result2, inner_seen2) = __x_product_aux(property_sets[1:], seen_features)
              result.extend(inner_result2)
  
          return (result, inner_seen | these_features)
function_tokens: def __x_product_aux ( property_sets , seen_features ) : if not property_sets : return ( [ ] , set ( ) ) properties = property_sets [ 0 ] . all ( ) these_features = set ( ) for p in property_sets [ 0 ] . non_free ( ) : these_features . add ( p . feature ( ) ) # Note: the algorithm as implemented here, as in original Jam code, appears to # detect conflicts based on features, not properties. For example, if command # line build request say: # # <a>1/<b>1 c<1>/<b>1 # # It will decide that those two property sets conflict, because they both specify # a value for 'b' and will not try building "<a>1 <c1> <b1>", but rather two # different property sets. This is a topic for future fixing, maybe. if these_features & seen_features : ( inner_result , inner_seen ) = __x_product_aux ( property_sets [ 1 : ] , seen_features ) return ( inner_result , inner_seen | these_features ) else : result = [ ] ( inner_result , inner_seen ) = __x_product_aux ( property_sets [ 1 : ] , seen_features | these_features ) if inner_result : for inner in inner_result : result . append ( properties + inner ) else : result . append ( properties ) if inner_seen & these_features : # Some of elements in property_sets[1:] conflict with elements of property_sets[0], # Try again, this time omitting elements of property_sets[0] ( inner_result2 , inner_seen2 ) = __x_product_aux ( property_sets [ 1 : ] , seen_features ) result . extend ( inner_result2 ) return ( result , inner_seen | these_features )