def show_slide(slideRef, sessionID=None): """Launch the default webbrowser and load a web-based viewer for the slide""" sessionID = _pma_session_id(sessionID) if (slideRef.startswith("/")): slideRef = slideRef[1:] if (os.name == "posix"): os_cmd = "open " else: os_cmd = "start " if (sessionID == _pma_pmacoreliteSessionID): url = "http://free.pathomation.com/pma-view-lite/?path=" + pma._pma_q( slideRef) else: url = _pma_url(sessionID) if url is None: raise Exception( "Unable to determine the PMA.core instance belonging to " + str(sessionID)) else: url += ("viewer/index.htm" + "?sessionID=" + pma._pma_q(sessionID) + "^&pathOrUid=" + pma._pma_q(slideRef)) # note the ^& to escape a regular & if (pma._pma_debug == True): print(url) os.system(os_cmd + url)
def get_slide_info(slideRef, sessionID=None): """ Return raw image information in the form of nested dictionaries """ sessionID = _pma_session_id(sessionID) if (slideRef.startswith("/")): slideRef = slideRef[1:] global _pma_slideinfos if (not (slideRef in _pma_slideinfos[sessionID])): url = _pma_api_url( sessionID, False) + "GetImageInfo?SessionID=" + pma._pma_q( sessionID) + "&pathOrUid=" + pma._pma_q(slideRef) r = requests.get(url) json = r.json() global _pma_amount_of_data_downloaded _pma_amount_of_data_downloaded[sessionID] += len(json) if ("Code" in json): raise Exception("ImageInfo to " + slideRef + " resulted in: " + json["Message"] + " (keep in mind that slideRef is case sensitive!)") elif ("d" in json): _pma_slideinfos[sessionID][slideRef] = json["d"] else: _pma_slideinfos[sessionID][slideRef] = json return _pma_slideinfos[sessionID][slideRef]
def get_annotations(slideRef, sessionID=None): """ Retrieve the annotations for slide slideRef """ sessionID = _pma_session_id(sessionID) if (slideRef.startswith("/")): slideRef = slideRef[1:] dir = os.path.split(slideRef)[0] url = _pma_api_url(sessionID, False) + "GetAnnotations?sessionID=" + pma._pma_q( sessionID) + "&pathOrUid=" + pma._pma_q(slideRef) r = requests.get(url) if ((not (r.text is None)) and (len(r.text) > 0)): json = r.json() global _pma_amount_of_data_downloaded _pma_amount_of_data_downloaded[sessionID] += len(json) if ("Code" in json): raise Exception("get_annotations() on " + slideRef + " resulted in: " + json["Message"] + " (keep in mind that slideRef is case sensitive!)") else: annotations = json else: annotations = "" return annotations
def get_files_for_slide(slideRef, sessionID=None): """Obtain all files actually associated with a specific slide This is most relevant with slides that are defined by multiple files, like MRXS or VSI""" sessionID = _pma_session_id(sessionID) if (slideRef.startswith("/")): slideRef = slideRef[1:] if (sessionID == _pma_pmacoreliteSessionID): url = _pma_api_url(sessionID) + "EnumerateAllFilesForSlide?sessionID=" + pma._pma_q( sessionID) + "&pathOrUid=" + pma._pma_q(slideRef) else: url = _pma_api_url(sessionID) + "getfilenames?sessionID=" + pma._pma_q(sessionID) + "&pathOrUid=" + pma._pma_q(slideRef) r = requests.get(url) json = r.json() global _pma_amount_of_data_downloaded _pma_amount_of_data_downloaded[sessionID] += len(json) if ("Code" in json): raise Exception("enumerate_files_for_slide on " + slideRef + " resulted in: " + json["Message"]) elif ("d" in json): files = json["d"] else: files = json retval = {} for file in files: if (sessionID == _pma_pmacoreliteSessionID): retval[file] = {"Size": 0, "LastModified": None} else: retval[file["Path"]] = {"Size": file["Size"], "LastModified": file["LastModified"]} return retval
def get_submitted_forms(slideRef, sessionID=None): """Find out what forms where submitted for a specific slide""" sessionID = _pma_session_id(sessionID) if (slideRef.startswith("/")): slideRef = slideRef[1:] url = _pma_api_url(sessionID, False) + "GetFormSubmissions?sessionID=" + pma._pma_q( sessionID) + "&pathOrUids=" + pma._pma_q(slideRef) all_forms = get_available_forms(slideRef, sessionID) print(url) r = requests.get(url) if ((not (r.text is None)) and (len(r.text) > 0)): json = r.json() global _pma_amount_of_data_downloaded _pma_amount_of_data_downloaded[sessionID] += len(json) if ("Code" in json): raise Exception("get_available_forms on " + slideRef + " resulted in: " + json["Message"] + " (keep in mind that slideRef is case sensitive!)") else: data = json forms = {} for entry in data: if (not (entry["FormID"] in forms)): forms[entry["FormID"]] = all_forms[entry["FormID"]] # should probably do some post-processing here, but unsure what that would actually be?? else: forms = "" return forms
def get_uid(slideRef, sessionID=None): """ Get the UID for a specific slide """ sessionID = _pma_session_id(sessionID) if (sessionID == _pma_pmacoreliteSessionID): if is_lite(): raise ValueError( "PMA.core.lite found running, but doesn't support UID generation.For advanced anonymization, please upgrade to PMA.core." ) else: raise ValueError( "PMA.core.lite not found, and besides; it doesn't support UID generation. For advanced anonymization, please upgrade to PMA.core." ) url = _pma_api_url(sessionID) + "GetUID?sessionID=" + pma._pma_q( sessionID) + "&path=" + pma._pma_q(slideRef) r = requests.get(url) json = r.json() global _pma_amount_of_data_downloaded _pma_amount_of_data_downloaded[sessionID] += len(json) if ("Code" in json): raise Exception("get_uid on " + slideRef + " resulted in: " + json["Message"]) else: fingerprint = json return fingerprint
def get_directories(startDir, sessionID=None, recursive=False): """ Return an array of sub-directories available to sessionID in the startDir directory """ sessionID = _pma_session_id(sessionID) url = _pma_api_url(sessionID) + "GetDirectories?sessionID=" + pma._pma_q( sessionID) + "&path=" + pma._pma_q(startDir) if pma._pma_debug is True: print(url) r = requests.get(url) json = r.json() global _pma_amount_of_data_downloaded _pma_amount_of_data_downloaded[sessionID] += len(json) if ("Code" in json): raise Exception("get_directories to " + startDir + " resulted in: " + json["Message"]) elif ("d" in json): dirs = json["d"] else: dirs = json # handle recursion, if so desired if (type(recursive) == bool and recursive is True) or (type(recursive) == int and recursive > 0): for dir in get_directories(startDir, sessionID): if type(recursive) == bool: dirs = dirs + get_directories(dir, sessionID, recursive) elif type(recursive) == int: dirs = dirs + get_directories(dir, sessionID, recursive - 1) return dirs
def search_slides(startDir, pattern, sessionID=None): sessionID = _pma_session_id(sessionID) if (sessionID == _pma_pmacoreliteSessionID): if is_lite(): raise ValueError("PMA.core.lite found running, but doesn't support searching.") else: raise ValueError("PMA.core.lite not found, and besides; it doesn't support searching.") if (startDir.startswith("/")): startDir = startDir[1:] url = _pma_query_url(sessionID) + "Filename?sessionID=" + pma._pma_q(sessionID) + "&path=" + pma._pma_q( startDir) + "&pattern=" + pma._pma_q(pattern) if pma._pma_debug == True: print("url =", url) r = requests.get(url) json = r.json() global _pma_amount_of_data_downloaded _pma_amount_of_data_downloaded[sessionID] += len(json) if ("Code" in json): raise Exception("search_slides on " + startDir + " resulted in: " + json["Message"]) elif ("d" in json): files = json["d"] else: files = json return files
def get_slides(startDir, sessionID=None, recursive=False): """ Return an array of slides available to sessionID in the startDir directory """ sessionID = _pma_session_id(sessionID) if (startDir.startswith("/")): startDir = startDir[1:] url = _pma_api_url(sessionID, False) + "GetFiles?sessionID=" + pma._pma_q( sessionID) + "&path=" + pma._pma_q(startDir) r = requests.get(url) json = r.json() global _pma_amount_of_data_downloaded _pma_amount_of_data_downloaded[sessionID] += len(json) if ("Code" in json): raise Exception("get_slides from " + startDir + " resulted in: " + json["Message"] + " (keep in mind that startDir is case sensitive!)") elif ("d" in json): slides = json["d"] else: slides = json # handle recursion, if so desired if (type(recursive) == bool and recursive == True) or (type(recursive) == int and recursive > 0): for dir in get_directories(startDir, sessionID): if type(recursive) == bool: slides = slides + get_slides(dir, sessionID, recursive) elif type(recursive) == int: slides = slides + get_slides(dir, sessionID, recursive - 1) return slides
def get_available_forms(slideRef=None, sessionID=None): """ See what forms are available to fill out, either system-wide (leave slideref to None), or for a particular slide """ sessionID = _pma_session_id(sessionID) if (slideRef is not None): if (slideRef.startswith("/")): slideRef = slideRef[1:] dir = os.path.split(slideRef)[0] url = _pma_api_url(sessionID) + "GetForms?sessionID=" + pma._pma_q(sessionID) + "&path=" + pma._pma_q(dir) else: url = _pma_api_url(sessionID) + "GetForms?sessionID=" + pma._pma_q(sessionID) r = requests.get(url) if ((not (r.text is None)) and (len(r.text) > 0)): json = r.json() global _pma_amount_of_data_downloaded _pma_amount_of_data_downloaded[sessionID] += len(json) if ("Code" in json): raise Exception("get_available_forms on " + slideRef + " resulted in: " + json["Message"]) else: forms_json = json forms = {} for entry in forms_json: forms[entry["Key"]] = entry["Value"] else: forms = "" return forms
def get_thumbnail_url(slideRef, sessionID=None): """Get the URL that points to the thumbnail for a slide""" sessionID = _pma_session_id(sessionID) if (slideRef.startswith("/")): slideRef = slideRef[1:] url = (_pma_url(sessionID) + "thumbnail" + "?SessionID=" + pma._pma_q(sessionID) + "&pathOrUid=" + pma._pma_q(slideRef)) return url
def get_barcode_url(slideRef, sessionID=None): """Get the URL that points to the barcode (alias for "label") for a slide""" sessionID = _pma_session_id(sessionID) if (slideRef.startswith("/")): slideRef = slideRef[1:] url = (_pma_url(sessionID) + "barcode" + "?SessionID=" + pma._pma_q(sessionID) + "&pathOrUid=" + pma._pma_q(slideRef)) return url
def connect(pmacoreURL=_pma_pmacoreliteURL, pmacoreUsername="", pmacorePassword=""): """ Attempt to connect to PMA.core instance; success results in a SessionID """ global _pma_sessions # so afterwards we can look up what username actually belongs to a sessions global _pma_usernames # so afterwards we can determine the PMA.core URL to connect to for a given SessionID global _pma_slideinfos # a caching mechanism for slide information; obsolete and should be improved global _pma_amount_of_data_downloaded # keep track of how much data was downloaded if (pmacoreURL == _pma_pmacoreliteURL): if is_lite(): # no point authenticating localhost / PMA.core.lite sessionID = _pma_pmacoreliteSessionID _pma_sessions[sessionID] = pmacoreURL if not (sessionID in _pma_slideinfos): _pma_slideinfos[sessionID] = {} _pma_amount_of_data_downloaded[sessionID] = 0 return sessionID else: return None # purposefully DON'T use helper function _pma_api_url() here: # why? Because_pma_api_url() takes session information into account (which we don't have yet) url = pma._pma_join(pmacoreURL, "api/json/authenticate?caller=SDK.Python") if (pmacoreUsername != ""): url += "&username="******""): url += "&password="******"Success"]).lower() != "true"): sessionID = None else: sessionID = loginresult["SessionId"] _pma_usernames[sessionID] = pmacoreUsername _pma_sessions[sessionID] = pmacoreURL if not (sessionID in _pma_slideinfos): _pma_slideinfos[sessionID] = {} _pma_amount_of_data_downloaded[sessionID] = len(loginresult) return sessionID
def user_exists(admSessionID, u): from pma_python import pma url = (_pma_admin_url(admSessionID) + "SearchUsers?source=Local" + "&SessionID=" + pma._pma_q(admSessionID) + "&query=" + pma._pma_q(u)) try: r = pma._pma_http_get(url, {'Accept': 'application/json'}) except Exception as e: print(e) return None results = r.json() for usr in results: if usr["Login"].lower() == u.lower(): return True return False
def prepare_form_dictionary(formID, sessionID=None): """Prepare a form-dictionary that can be used later on to submit new form data for a slide""" if (formID == None): return None sessionID = _pma_session_id(sessionID) url = _pma_api_url( sessionID, False) + "GetFormDefinitions?sessionID=" + pma._pma_q(sessionID) r = requests.get(url) if ((not (r.text is None)) and (len(r.text) > 0)): json = r.json() global _pma_amount_of_data_downloaded _pma_amount_of_data_downloaded[sessionID] += len(json) if ("Code" in json): raise Exception("get_available_forms on " + slideRef + " resulted in: " + json["Message"] + " (keep in mind that slideRef is case sensitive!)") else: forms_json = json form_def = {} for form in forms_json: if ((form["FormID"] == formID) or (form["FormName"] == formID)): for field in form["FormFields"]: form_def[field["Label"]] = None else: form_def = "" return form_def
def get_fingerprint(slideRef, sessionID=None): """ Get the fingerprint for a specific slide """ sessionID = _pma_session_id(sessionID) url = _pma_api_url(sessionID) + "GetFingerprint?sessionID=" + pma._pma_q( sessionID) + "&pathOrUid=" + pma._pma_q(slideRef) r = requests.get(url) json = r.json() global _pma_amount_of_data_downloaded _pma_amount_of_data_downloaded[sessionID] += len(json) if ("Code" in json): raise Exception("get_fingerprint on " + slideRef + " resulted in: " + json["Message"]) else: fingerprint = json return fingerprint
def get_barcode_text(slideRef, sessionID=None): """Get the text encoded by the barcode (if there IS a barcode on the slide to begin with)""" sessionID = _pma_session_id(sessionID) if (slideRef.startswith("/")): slideRef = slideRef[1:] url = _pma_api_url(sessionID) + "GetBarcodeText?sessionID=" + pma._pma_q( sessionID) + "&pathOrUid=" + pma._pma_q(slideRef) r = requests.get(url) if ((not (r.text is None)) and (len(r.text) > 0)): json = r.json() global _pma_amount_of_data_downloaded _pma_amount_of_data_downloaded[sessionID] += len(json) if ("Code" in json): raise Exception("get_barcode_text on " + slideRef + " resulted in: " + json["Message"]) else: barcode = json else: barcode = "" return barcode
def get_root_directories(sessionID=None): """ Return an array of root-directories available to sessionID """ sessionID = _pma_session_id(sessionID) url = _pma_api_url( sessionID) + "GetRootDirectories?sessionID=" + pma._pma_q((sessionID)) contents = urlopen(url).read() global _pma_amount_of_data_downloaded _pma_amount_of_data_downloaded[sessionID] += len(contents) dom = minidom.parseString(contents) return _pma_XmlToStringArray(dom.firstChild)
def get_root_directories(sessionID=None): """ Return an array of root-directories available to sessionID """ sessionID = _pma_session_id(sessionID) url = _pma_api_url(sessionID) + "GetRootDirectories?sessionID=" + pma._pma_q((sessionID)) r = requests.get(url) json = r.json() global _pma_amount_of_data_downloaded _pma_amount_of_data_downloaded[sessionID] += len(json) if ("Code" in json): raise Exception("get_root_directories failed with error " + json["Message"]) return json
def admin_connect(pmacoreURL, pmacoreAdmUsername, pmacoreAdmPassword): """ Attempt to connect to PMA.core instance; success results in a SessionID only success if the user has administrative status """ _pma_check_for_pma_start("admin_connect", pmacoreURL) # purposefully DON'T use helper function _pma_api_url() here: # why? Because_pma_api_url() takes session information into account (which we don't have yet) url = pma._pma_join(pmacoreURL, "admin/json/AdminAuthenticate?caller=SDK.Python") url += "&username="******"&password="******"Success"]).lower() != "true"): admSessionID = None else: admSessionID = loginresult["SessionId"] core._pma_sessions[admSessionID] = pmacoreURL core._pma_usernames[admSessionID] = pmacoreAdmUsername if not (admSessionID in core._pma_slideinfos): core._pma_slideinfos[admSessionID] = dict() core._pma_amount_of_data_downloaded[admSessionID] = len(loginresult) return (admSessionID)
def _pma_get_training_sessions(pmacontrolURL, pmacoreSessionID): """ Retrieve a list of currently defined training sessions in PMA.control. """ url = pma._pma_join( pmacontrolURL, "api/Sessions?sessionID=" + pma._pma_q(pmacoreSessionID)) try: headers = {'Accept': 'application/json'} r = pma._pma_http_get(url, headers) except Exception as e: print(e) return None return r.json()
def get_uid(slideRef, sessionID=None): """ Get the UID for a specific slide """ sessionID = _pma_session_id(sessionID) if (sessionID == _pma_pmacoreliteSessionID): if is_lite(): raise ValueError( "PMA.core.lite found running, but doesn't support UID generation. For advanced anonymization, please upgrade to PMA.core." ) else: raise ValueError( "PMA.core.lite not found, and besides; it doesn't support UID generation. For advanced anonymization, please upgrade to PMA.core." ) url = _pma_api_url(sessionID) + "GetUID?sessionID=" + pma._pma_q( sessionID) + "&path=" + pma._pma_q(slideRef) contents = urlopen(url).read() global _pma_amount_of_data_downloaded _pma_amount_of_data_downloaded[sessionID] += len(contents) dom = minidom.parseString(contents) return _pma_XmlToStringArray(dom)[0]
def get_submitted_form_data(slideRef, sessionID=None): """Get all submitted form data associated with a specific slide""" sessionID = _pma_session_id(sessionID) if (slideRef.startswith("/")): slideRef = slideRef[1:] url = _pma_api_url( sessionID) + "GetFormSubmissions?sessionID=" + pma._pma_q( sessionID) + "&pathOrUids=" + pma._pma_q(slideRef) print(url) r = requests.get(url) if ((not (r.text is None)) and (len(r.text) > 0)): json = r.json() global _pma_amount_of_data_downloaded _pma_amount_of_data_downloaded[sessionID] += len(json) if ("Code" in json): raise Exception("get_available_forms on " + slideRef + " resulted in: " + json["Message"]) else: data = json # should probably do some post-processing here, but unsure what that would actually be?? else: data = "" return data
def disconnect(sessionID=None): """ Attempt to disconnect from a PMA.core instance """ sessionID = _pma_session_id(sessionID) url = _pma_api_url(sessionID) + "DeAuthenticate?sessionID=" + pma._pma_q((sessionID)) contents = urlopen(url).read() global _pma_amount_of_data_downloaded _pma_amount_of_data_downloaded[sessionID] += len(contents) if (len(_pma_sessions.keys()) > 0): # yes we do! This means that when there's a PMA.core active session AND PMA.core.lite version running, # the PMA.core active will be selected and returned del _pma_sessions[sessionID] del _pma_slideinfos[sessionID] return True
def _pma_get_projects(pmacontrolURL, pmacoreSessionID): """ Retrieve all projects and their data in PMA.control (RAW JSON data; not suited for human consumption) """ global _pma_projects_json url = pma._pma_join( pmacontrolURL, "api/Projects?sessionID=" + pma._pma_q(pmacoreSessionID)) try: headers = {'Accept': 'application/json'} r = pma._pma_http_get(url, headers) return r.json() except Exception as e: return None
def _pma_get_case_collections(pmacontrolURL, pmacoreSessionID): """ Retrieve all the data for all the defined case collections in PMA.control (RAW JSON data; not suited for human consumption) """ global _pma_casecollections_json url = pma._pma_join( pmacontrolURL, "api/CaseCollections?sessionID=" + pma._pma_q(pmacoreSessionID)) try: headers = {'Accept': 'application/json'} r = pma._pma_http_get(url, headers) return r.json() except Exception as e: return None
def get_training_session_participants(pmacontrolURL, pmacontrolTrainingSessionID, pmacoreSessionID): """ Extract the participants in a particular session """ url = pma._pma_join( pmacontrolURL, "api/Sessions/" + str(pmacontrolTrainingSessionID) + "/Participants?sessionID=" + pma._pma_q(pmacoreSessionID)) try: headers = {'Accept': 'application/json'} r = pma._pma_http_get(url, headers) except Exception as e: print(e) return None parts = {} for part in r.json(): parts[part['User']] = part return parts
def reverse_uid(admSessionID, slideRefUid): """ lookup the reverse path of a UID for a specific slide """ if (admSessionID == core._pma_pmacoreliteSessionID): if is_lite(): raise ValueError( "PMA.core.lite found running, but doesn't support UIDs. For advanced anonymization, please upgrade to PMA.core." ) else: raise ValueError( "PMA.core.lite not found, and besides; it doesn't support UIDs. For advanced anonymization, please upgrade to PMA.core." ) url = _pma_admin_url(admSessionID) + "ReverseLookupUID?sessionID=" + pma._pma_q(admSessionID) + "&uid=" + pma._pma_q(slideRefUid) if (pma._pma_debug is True): print(url) r = requests.get(url) json = r.json() if ("Code" in json): raise Exception("reverse_uid on " + slideRefUid + " resulted in: " + json["Message"]) else: path = json return path
def reverse_root_directory(admSessionID, alias): """ lookup the reverse path of a root-directory """ if (admSessionID == core._pma_pmacoreliteSessionID): if is_lite(): raise ValueError( "PMA.core.lite found running, but doesn't support this method." ) else: raise ValueError( "PMA.core.lite not found, and besides; it doesn't support this method." ) url = _pma_admin_url(admSessionID) + "ReverseLookupRootDirectory?sessionID=" + pma._pma_q(admSessionID) + "&alias=" + pma._pma_q(alias) if (pma._pma_debug is True): print(url) r = requests.get(url) json = r.json() if ("Code" in json): raise Exception("reverse_root_directory on " + alias + " resulted in: " + json["Message"]) else: path = json return path
def get_tile(slideRef, x=0, y=0, zoomlevel=None, zstack=0, sessionID=None, format="jpg", quality=100): """ Get a single tile at position (x, y) Format can be 'jpg' or 'png' Quality is an integer value and varies from 0 (as much compression as possible; not recommended) to 100 (100%, no compression) """ sessionID = _pma_session_id(sessionID) if (slideRef.startswith("/")): slideRef = slideRef[1:] if (zoomlevel is None): zoomlevel = 0 # get_max_zoomlevel(slideRef, sessionID) url = _pma_url(sessionID) if url is None: raise Exception( "Unable to determine the PMA.core instance belonging to " + str(sessionID)) url += ("tile" + "?SessionID=" + pma._pma_q(sessionID) + "&channels=" + pma._pma_q("0") + "&timeframe=" + pma._pma_q("0") + "&layer=" + str(int(round(zstack))) + "&pathOrUid=" + pma._pma_q(slideRef) + "&x=" + str(int(round(x))) + "&y=" + str(int(round(y))) + "&z=" + str(int(round(zoomlevel))) + "&format=" + pma._pma_q(format) + "&quality=" + pma._pma_q(quality) + "&cache=" + str(_pma_usecachewhenretrievingtiles).lower()) r = requests.get(url) img = Image.open(BytesIO(r.content)) global _pma_amount_of_data_downloaded _pma_amount_of_data_downloaded[sessionID] += len(r.content) return img