#!/usr/bin/env python3 import re import datetime import util import autoproc import logging logger = logging.getLogger(__name__) local_tzinfo = datetime.datetime.now(datetime.timezone.utc).astimezone().tzinfo def parse(text): data = { 'body': text.rstrip() } if match := re.search(r'\bProvider: \b(?P.*?)\r\n', text): data.update(match.groupdict()) if match := re.search(r'\bSpecimen: \b(?P.*?)\r\n', text): data.update(match.groupdict()) if match := re.search(r'\bAccession \[UID\]: \b(?P.*?) \[(?P.*?)\]\r\n', text): data.update(match.groupdict()) if match := re.search(r'\bReport Released: \b(?P.*?)\r\n', text): value = match.group(1) data['time_released'] = datetime.datetime.strptime(value, '%b %d, %Y@%H:%M').replace(tzinfo=local_tzinfo) if '@' in value else datetime.datetime.strptime(value, '%b %d, %Y').replace(tzinfo=local_tzinfo) if match := re.search(r'\bSpecimen Collection Date: \b(?P.*?)\r\n', text): value = match.group(1) data['time_collected'] = datetime.datetime.strptime(value, '%b %d, %Y@%H:%M').replace(tzinfo=local_tzinfo) if '@' in value else datetime.datetime.strptime(value, '%b %d, %Y').replace(tzinfo=local_tzinfo) if match := re.match(r'\s+----(.*?)----\s+page \d+\r\n', text): data['title'] = match.group(1) if match := re.search(r'\bAccession \[UID\]: (?P.*?) \[(?P.*?)\]\s+Received: (?P.*?)\r\n', text): data.update(match.groupdict()) data['time_received'] = datetime.datetime.strptime(data['time_received'], '%b %d, %Y@%H:%M').replace(tzinfo=local_tzinfo) if '@' in data['time_received'] else datetime.datetime.strptime(data['time_received'], '%b %d, %Y').replace(tzinfo=local_tzinfo) if match := re.search(r'\bReport Completed: \b(?P.*?)\r\n', text): value = match.group(1) data['time_completed'] = datetime.datetime.strptime(value, '%b %d, %Y@%H:%M').replace(tzinfo=local_tzinfo) if '@' in value else datetime.datetime.strptime(value, '%b %d, %Y').replace(tzinfo=local_tzinfo) if match := re.search(r'\bCollection sample: (?P.*?)\s+Collection date: (?P.*?)\r\n', text): data.update(match.groupdict()) data['time_collected'] = datetime.datetime.strptime(data['time_collected'], '%b %d, %Y %H:%M').replace(tzinfo=local_tzinfo) if ':' in data['time_collected'] else datetime.datetime.strptime(data['time_collected'], '%b %d, %Y').replace(tzinfo=local_tzinfo) return data async def cmd_reports(proc, mrn, alpha, omega): """Fetch lab reports""" async with proc.sendline, autoproc.expect_async(proc) as expect: proc.sendline('^Laboratory Menu') async for prompt, response in expect.promptmatches( ('Select HOSPITAL LOCATION NAME: ', None), ('Select Laboratory Menu Option: ', '13'), # Interim report ('Select Patient Name: ', mrn), ( ('Do you wish to continue with this patient [Yes/No]? ', 'Yes'), ('Date to START with: TODAY//', util.vista_strftime(omega), True), ), ('Date to END with: T-7//', util.vista_strftime(alpha)), ('Print address page? NO// ', None), # default NO ( ('Do you want to start each note on a new page? NO// ', None), # default NO ('DEVICE: HOME// ', 'HOME;90;1023', True), ), throw=True): proc.sendline(response) assert await expect.earliest(' HOME(CRT)\r\n') pages = [] async for prompt, response in expect.promptmatches(( (re.compile(r' PRESS \'\^\' TO STOP $'), None), (re.compile(r' \'\^\' TO STOP$'), None), ('Select Patient Name: ', None), ('Select Laboratory Menu Option: ', None, True), ), throw=True): proc.sendline(response) match prompt: case autoproc.ExpectMatch(index=(0|1), before=before): if left := re.match(r'(?:\x1b\[H\x1b\[J\x1b\[2J\x1b\[H\r\n\r\n.+?[ ]{2,}Report date: .+?\r\n Pat ID: \d{3}-\d{2}-\d{4}[ ]{2,}SEX: \w[ ]{2,}DOB: .+?[ ]{2,}LOC: .+?\r\n)|(?:\r\n\x1b\[H\x1b\[J\x1b\[2J\x1b\[H\r\n.+?[ ]{2,}\d{3}-\d{2}-\d{4}[ ]{2,}AGE: \d+[^\r\n]*?\r\n)|(?:\r[ ]+\r\r\n.+?[ ]{2,}\d{3}-\d{2}-\d{4}[ ]{2,}AGE: \d+[ ]{2,}.+?\r\n)', before): pages.append(before[len(left.group(0)):]) elif re.match(r'(?:\r\n)+.+?[ ]{2,}\d{3}-\d{2}-\d{4}[ ]{2,}.+?[ ]+$', before) or re.match(r'^(?:\r\n)+$', before): pass else: print(repr(before)) assert False assert await expect.endswith('\r\nSelect Patient Information and OE/RR Option: ', '\r\nSelect Patient Information and OE/RR Option: ') expect.clear() text = re.sub(r'\r\n\s+>> CONTINUATION OF .+? <<(?:(?:\r\n)|(?:\s+page \d+))', '', '\r\n'.join(pages)) positions = [m.start() for m in re.finditer(r'(?:(?:[ ]+----MICROBIOLOGY----[ ]+page \d+\r\n\r\n)|(?:[ ]+))Reporting Lab:', text)] positions.append(len(text)) for i in range(len(positions) - 1): yield parse(text[positions[i]:positions[i + 1]])