Skip to content

Commit

Permalink
Merge pull request #81 from pennsignals/flowsheet_kind
Browse files Browse the repository at this point in the history
Allow multiple flowsheet kinds from one predictions table and one flowsheet publisher
  • Loading branch information
mdbecker authored Nov 3, 2022
2 parents 08e028c + 0cbec30 commit 83b42db
Show file tree
Hide file tree
Showing 6 changed files with 108 additions and 27 deletions.
6 changes: 4 additions & 2 deletions local/configuration.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@
flowsheets: !flowsheets
client_id: ${EPIC_CLIENT_ID}
cookie: ${EPIC_COOKIE}
flowsheet_id: ${EPIC_FLOWSHEET_ID}
flowsheet_template_id: ${EPIC_FLOWSHEET_TEMPLATE_ID}
kinds:
score:
flowsheet_id: ${EPIC_FLOWSHEET_ID}
flowsheet_template_id: ${EPIC_FLOWSHEET_TEMPLATE_ID}
password: ${EPIC_PASSWORD}
url: ${EPIC_URL}api/epic/2011/clinical/patient/addflowsheetvalue/flowsheetvalue
username: ${EPIC_USERNAME}
Expand Down
6 changes: 4 additions & 2 deletions local/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ gold: ./predict/gold/gold.pkl
flowsheets: !flowsheets
client_id: ${EPIC_CLIENT_ID}
cookie: ${EPIC_COOKIE}
flowsheet_id: ${EPIC_FLOWSHEET_ID}
flowsheet_template_id: ${EPIC_FLOWSHEET_TEMPLATE_ID}
kinds:
score:
flowsheet_id: ${EPIC_FLOWSHEET_ID}
flowsheet_template_id: ${EPIC_FLOWSHEET_TEMPLATE_ID}
password: ${EPIC_PASSWORD}
url: ${EPIC_URL}api/epic/2011/clinical/patient/addflowsheetvalue/flowsheetvalue
username: ${EPIC_USERNAME}
Expand Down
5 changes: 3 additions & 2 deletions postgres/sql/patchdb.d/005.public.sql
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ begin
id int primary key generated always as identity,
run_id int not null,
subject_id int not null,
kind varchar not null default "score",
score double precision not null,
constraint predictions_require_a_run
foreign key (run_id) references runs (id)
Expand All @@ -94,8 +95,8 @@ begin
-- document your assumptions about how many predictions are made per subject
-- per visit?
-- per run?
constraint only_one_prediction_per_subject_and_run
unique (run_id, subject_id),
constraint only_one_prediction_per_subject_kind_and_run
unique (run_id, subject_id, kind),
-- pick one of the following two constaints
constraint prediction_score_must_be_a_normal
check (0.0 <= score and score <= 1.0),
Expand Down
60 changes: 41 additions & 19 deletions src/dsdk/flowsheet.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from datetime import datetime
from json import JSONDecodeError, dumps
from time import sleep as default_sleep
from typing import TYPE_CHECKING, Any, Generator
from typing import TYPE_CHECKING, Any, Generator, Mapping
from urllib.parse import urlencode

from cfgenvy import YamlMapping
Expand Down Expand Up @@ -56,6 +56,33 @@ def __str__(self):
return str(self.__dict__)


class Kind(YamlMapping):
"""Kind."""

def __init__(
self,
*,
flowsheet_id: str,
flowsheet_template_id: str,
flowsheet_id_type: str = "external",
flowsheet_template_id_type: str = "external",
):
"""__init__."""
self.flowsheet_id = flowsheet_id
self.flowsheet_id_type = flowsheet_id_type
self.flowsheet_template_id = flowsheet_template_id
self.flowsheet_template_id_type = flowsheet_template_id_type

def as_yaml(self) -> dict[str, Any]:
"""As yaml."""
return {
"flowsheet_id": self.flowsheet_id,
"flowsheet_id_type": self.flowsheet_id_type,
"flowsheet_template_id": self.flowsheet_template_id,
"flowsheet_template_id_type": self.flowsheet_template_id_type,
}


class Flowsheet(YamlMapping): # pylint: disable=too-many-instance-attributes
"""Flowsheet."""

Expand Down Expand Up @@ -90,14 +117,11 @@ def __init__( # pylint: disable=too-many-locals
*,
client_id: str,
cookie: str,
flowsheet_id: str,
flowsheet_template_id: str,
kinds: Mapping[str, Mapping[str, str]],
password: str,
url: str,
username: str,
contact_id_type: str = "CSN",
flowsheet_id_type: str = "external",
flowsheet_template_id_type: str = "external",
operation_timeout: int = 5,
patient_id_type: str = "UID",
user_id: str = "PENNSIGNALS",
Expand All @@ -110,10 +134,7 @@ def __init__( # pylint: disable=too-many-locals
self.client_id = client_id
self.contact_id_type = contact_id_type
self.cookie = cookie
self.flowsheet_id = flowsheet_id
self.flowsheet_id_type = flowsheet_id_type
self.flowsheet_template_id = flowsheet_template_id
self.flowsheet_template_id_type = flowsheet_template_id_type
self.kinds = {key: Kind(**values) for key, values in kinds.items()}
self.operation_timeout = operation_timeout
self.password = password
self.patient_id_type = patient_id_type
Expand All @@ -128,11 +149,9 @@ def as_yaml(self) -> dict[str, Any]:
"client_id": self.client_id,
"contact_id_type": self.contact_id_type,
"cookie": self.cookie,
"flowsheet_id": self.flowsheet_id,
"flowsheet_id_type": self.flowsheet_id_type,
"flowsheet_template_id": self.flowsheet_template_id,
"flowsheet_template_id_type": self.flowsheet_template_id_type,
"operation_timeout": self.operation_timeout,
"kinds": {
key: value.as_yaml() for key, value in self.kinds.items()
},
"password": self.password,
"patient_id_type": self.patient_id_type,
"url": self.url,
Expand Down Expand Up @@ -203,14 +222,15 @@ def rest(
session: Session,
) -> Result:
"""Rest."""
kind = self.kinds[missing["kind"]]
query = {
"Comment": missing["id"],
"ContactID": missing["csn"],
"ContactIDType": self.contact_id_type,
"FlowsheetID": self.flowsheet_id,
"FlowsheetIDType": self.flowsheet_id_type,
"FlowsheetTemplateID": self.flowsheet_template_id,
"FlowsheetTemplateIDType": self.flowsheet_template_id_type,
"FlowsheetID": kind.flowsheet_id,
"FlowsheetIDType": kind.flowsheet_id_type,
"FlowsheetTemplateID": kind.flowsheet_template_id,
"FlowsheetTemplateIDType": kind.flowsheet_template_id_type,
"InstantValueTaken": missing["as_of"].strftime(DATETIME_FORMAT),
"PatientID": missing["empi"],
"PatientIDType": self.patient_id_type,
Expand Down Expand Up @@ -299,14 +319,15 @@ def on_rest(
"Should not get here with raise_for_status and a status of 400."
)

def test(
def test( # pylint: disable=too-many-arguments
self,
# csn=278820881,
csn=218202909, # inpatient admission date is 2019-02-06 at PAH
# csn="BAD202909",
empi="8330651951",
# empi="BAD2345678",
id=0, # pylint: disable=redefined-builtin
kind="score",
score="0.5",
):
"""Test epic API."""
Expand All @@ -315,6 +336,7 @@ def test(
"csn": csn,
"empi": empi,
"id": id,
"kind": kind,
"score": score,
}
with self.session() as session:
Expand Down
54 changes: 52 additions & 2 deletions test/test_dsdk.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
from dsdk import (
Asset,
Batch,
Flowsheet,
FlowsheetMixin,
Model,
ModelMixin,
Mssql,
Expand Down Expand Up @@ -58,7 +60,9 @@ def __call__(self, batch: Batch, service: Service) -> None:
assert batch.evidence["test"] is df


class MockService(ModelMixin, MssqlMixin, PostgresMixin, Service):
class MockService( # pylint: disable=too-many-ancestors
FlowsheetMixin, ModelMixin, MssqlMixin, PostgresMixin, Service
):
"""MockService."""

YAML = "!test"
Expand All @@ -78,6 +82,16 @@ def __init__(self, **kwargs) -> None:

CONFIGS = """
!test
flowsheets: !flowsheets
client_id: 00000000-0000-0000-0000-000000000000
cookie: ASP.NET_SessionId=000000000000000000000000
kinds:
score:
flowsheet_id: '0000000000'
flowsheet_template_id: '0000000000'
password: ${EPIC_PASSWORD}
url: https://interconnectbgprod.uphs.upenn.edu/interconnect-prd-web/
username: epic
model: !model ./test/0.0.1.pkl
mssql: !mssql
database: test
Expand All @@ -99,6 +113,7 @@ def __init__(self, **kwargs) -> None:
""".strip()

ENVS = """
EPIC_PASSWORD=password
MSSQL_PASSWORD=password
POSTGRES_PASSWORD=password
""".strip()
Expand All @@ -107,6 +122,22 @@ def __init__(self, **kwargs) -> None:
!test
as_of: null
duration: null
flowsheets: !flowsheets
client_id: 00000000-0000-0000-0000-000000000000
contact_id_type: CSN
cookie: ASP.NET_SessionId=000000000000000000000000
kinds:
score:
flowsheet_id: '0000000000'
flowsheet_id_type: external
flowsheet_template_id: '0000000000'
flowsheet_template_id_type: external
password: password
patient_id_type: UID
url: https://interconnectbgprod.uphs.upenn.edu/interconnect-prd-web/
user_id: PENNSIGNALS
user_id_type: external
username: epic
gold: null
model: !model ./test/0.0.1.pkl
mssql: !mssql
Expand All @@ -119,6 +150,7 @@ def __init__(self, **kwargs) -> None:
ext: .sql
path: ./assets/mssql
username: mssql
poll_interval: 60
postgres: !postgres
database: test
host: 0.0.0.0
Expand All @@ -139,6 +171,19 @@ def build(
) -> tuple[Callable, dict[str, Any], str]:
"""Build from parameters."""
cls.yaml_types()
flowsheets = Flowsheet(
client_id="00000000-0000-0000-0000-000000000000",
cookie="ASP.NET_SessionId=000000000000000000000000",
kinds={
"score": {
"flowsheet_id": "0000000000",
"flowsheet_template_id": "0000000000",
},
},
password="password",
url="https://interconnectbgprod.uphs.upenn.edu/interconnect-prd-web/",
username="epic",
)
model = Model(name="test", path="./test/0.0.1.pkl", version="0.0.1")
mssql = Mssql(
database="test",
Expand All @@ -158,6 +203,7 @@ def build(
return (
cls,
{
"flowsheets": flowsheets,
"model": model,
"mssql": mssql,
"postgres": postgres,
Expand All @@ -176,7 +222,11 @@ def deserialize(
pickle_file = "./test/0.0.1.pkl"
dump_pickle_file({"name": "test", "version": "0.0.1"}, pickle_file)

env = {"POSTGRES_PASSWORD": "oops!", "MSSQL_PASSWORD": "oops!"}
env = {
"EPIC_PASSWORD": "oops!",
"MSSQL_PASSWORD": "oops!",
"POSTGRES_PASSWORD": "oops!",
}
return (
cls.loads,
{
Expand Down
4 changes: 4 additions & 0 deletions test/test_flowsheets.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ def test_valid(mock_flowsheets_service):
"csn": 218202909,
"empi": "8330651951",
"id": 0,
"kind": "score",
"run_id": 0,
"score": 0.5,
}
Expand All @@ -51,6 +52,7 @@ def test_invalid_csn(mock_flowsheets_service):
"csn": 999999999,
"empi": "8330651951",
"id": 0,
"kind": "score",
"run_id": 0,
"score": 0.5,
}
Expand Down Expand Up @@ -81,6 +83,7 @@ def test_invalid_empi(mock_flowsheets_service):
"csn": 218202909,
"empi": "9999999999",
"id": 0,
"kind": "score",
"run_id": 0,
"score": 0.5,
}
Expand Down Expand Up @@ -120,6 +123,7 @@ def outer(*args, **kwargs):
"csn": 133713371,
"empi": "1337133713",
"id": 0,
"kind": "score",
"run_id": 0,
"score": 0.5,
}
Expand Down

0 comments on commit 83b42db

Please sign in to comment.