def body_edge_table(): """ Extract rows for a particular body from the merge table. Useful for debugging, or for warming up the merge graph cache. """ global logger global MERGE_TABLE data = request.json user = data.get("user", "unknown") body_id = data["body-id"] server = data["server"] + ':' + str(data["port"]) uuid = data["uuid"] segmentation_instance = data["segmentation-instance"] find_missing_edges = data.get("find-missing-edges", True) body_logger = PrefixedLogger(logger, f"User {user}: Body {body_id}: ") instance_info = DvidInstanceInfo(server, uuid, segmentation_instance) body_logger.info("Recevied body-edge-table request") try: session = default_dvid_session(appname='cleave-server', user=user) _mutid, _supervoxels, edges, scores = MERGE_GRAPH.extract_edges(*instance_info, body_id, find_missing_edges, session=session, logger=body_logger) except requests.HTTPError as ex: status_name = str(HTTPStatus(ex.response.status_code)).split('.')[1] if ex.response.status_code == HTTPStatus.NOT_FOUND: msg = f"Body not found: {body_id}" else: msg = f"Received error from DVID: {status_name}" body_logger.error(msg) return msg, ex.response.status_code response = StringIO() table = pd.DataFrame(edges, columns=['id_a', 'id_b']) table['score'] = scores table.to_csv(response, index=False, header=True) return response.getvalue()
def session_id(_): time.sleep(0.01) return id(default_dvid_session())
def _run_cleave(data): """ Helper function that actually performs the cleave, and can be run in a separate process. Must not use any flask functions. """ global logger global MERGE_TABLE user = data.get("user", "unknown") method = data.get("method", DEFAULT_METHOD) body_id = data["body-id"] seeds = { int(k): v for k,v in data["seeds"].items() } server = data["server"] + ':' + str(data["port"]) uuid = data["uuid"] segmentation_instance = data["segmentation-instance"] find_missing_edges = data.get("find-missing-edges", True) body_logger = PrefixedLogger(logger, f"User {user}: Body {body_id}: ") instance_info = DvidInstanceInfo(server, uuid, segmentation_instance) # Remove empty seed classes (if any) for label in list(seeds.keys()): if len(seeds[label]) == 0: del seeds[label] cleave_response = copy.copy(data) cleave_response["seeds"] = dict(sorted((k, sorted(v)) for (k,v) in data["seeds"].items())) cleave_response["assignments"] = {} cleave_response["warnings"] = [] cleave_response["info"] = [] if not data["seeds"]: msg = "Request contained no seeds!" body_logger.error(msg) body_logger.info(f"Responding with error PRECONDITION_FAILED.") cleave_response.setdefault("errors", []).append(msg) return cleave_response, HTTPStatus.PRECONDITION_FAILED # code 412 # Extract this body's edges from the complete merge graph with Timer() as timer: try: session = default_dvid_session(appname='cleave-server', user=user) mutid, supervoxels, edges, scores = MERGE_GRAPH.extract_edges(*instance_info, body_id, find_missing_edges, session=session, logger=body_logger) except requests.HTTPError as ex: status_name = str(HTTPStatus(ex.response.status_code)).split('.')[1] if ex.response.status_code == HTTPStatus.NOT_FOUND: msg = f"Body not found: {body_id}" else: msg = f"Received error from DVID: {status_name}" body_logger.error(msg) body_logger.info(f"Responding with error {status_name}.") cleave_response.setdefault("errors", []).append(msg) return cleave_response, ex.response.status_code body_logger.info(f"Extracting body graph (mutid={mutid}) took {timer.timedelta}") unexpected_seeds = set(chain(*seeds.values())) - set(supervoxels) if unexpected_seeds: msg = f"Request contained seeds that do not belong to body: {sorted(unexpected_seeds)}" body_logger.error(msg) body_logger.info("Responding with error PRECONDITION_FAILED.") cleave_response.setdefault("errors", []).append(msg) return cleave_response, HTTPStatus.PRECONDITION_FAILED # code 412 try: # Perform the cleave computation with Timer() as timer: results = cleave(edges, scores, seeds, supervoxels, method=method) except InvalidCleaveMethodError as ex: body_logger.error(str(ex)) body_logger.info("Responding with error BAD_REQUEST.") cleave_response.setdefault("errors", []).append(str(ex)) return cleave_response, HTTPStatus.BAD_REQUEST # code 400 body_logger.info(f"Computing cleave took {timer.timedelta}") # Convert assignments to JSON df = pd.DataFrame({'node': supervoxels, 'label': results.output_labels}) df.sort_values('node', inplace=True) for label, group in df.groupby('label'): cleave_response["assignments"][str(label)] = group['node'].tolist() if results.disconnected_components: msg = (f"Cleave result contains non-contiguous objects for seeds: " f"{sorted(results.disconnected_components)}") body_logger.warning(msg) cleave_response["info"].append(msg) if results.contains_unlabeled_components: num_unlabeled = len(cleave_response["assignments"]["0"]) msg = f"Cleave result is not complete. {num_unlabeled} supervoxels remain unassigned." body_logger.error(msg) body_logger.warning(msg) cleave_response["warnings"].append(msg) body_logger.info("Sending cleave results") return ( cleave_response, HTTPStatus.OK )