def merge_otus(): '''Takes a "nexson" arg that should be a NexSON blob. Returns an object with a "data" property that will be the NexSON with otus merged into the first otu group. 1. merges trees elements 2 - # trees into the first trees element., 2. merges otus elements 2 - # otus into the first otus element. 3. if there is no ot:originalLabel field for any otu, it sets that field based on @label and deletes @label 4. merges an otu elements using the rule: A. treat (ottId, originalLabel) as a key B. If otu objects in subsequent trees match originalLabel and have a matching or absent ot:ottId, then they are merged into the same OTUs (however see C) C. No two leaves of a tree may share an otu (though otu should be shared across different trees). It is important that each leaf node be mapped to a distinct OTU. Otherwise there will be no way of separating them during OTU mapping. we do this indirectly by assuring to no two otu objects in the same otus object get merged with each other (or to a common object) 5. correct object references to deleted entities. This function is used to patch up NexSONs created by multiple imports, hence the substitution of '@label' for 'ot:originalLabel'. Ids are arbitrary for imports from non-nexml tools, so matching is done based on names. This should mimic the behavior of the analysis tools that produced the trees (for most/all such tools unique names constitute unique OTUs). ''' response.view = 'generic.json' # read NexSON from 'nexson' arg or (more likely) the request body nexson = extract_nexson_from_http_call(request, **request.vars) # web2py equivalent to **kwargs try: o = merge_otus_and_trees(nexson) return {'data': o, 'error': 0} except Exception, x: s = str(x) return {'error': 1, 'description': s}