Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix assets/ installation #121

Merged
merged 9 commits into from
Nov 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ ENV USE_MSSQL=${USE_MSSQL}
ARG USE_OTEL=false
ENV USE_OTEL=${USE_OTEL}
# Set default log config
ARG LOG_CONFIG=/code/assets/production_log_config.json
ARG LOG_CONFIG=assets/production_log_config.json
ENV LOG_CONFIG=${LOG_CONFIG}

# Updgrade system packages and install curl
Expand Down Expand Up @@ -53,7 +53,6 @@ RUN if [ "$USE_OTEL" = "true" ]; then \
# Copy over the rest of the code
COPY ./src /code/src
COPY ./docs /code/docs
COPY ./assets /code/assets
COPY README.md /code/README.md

EXPOSE ${PORT}
Expand Down
1 change: 0 additions & 1 deletion compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ services:
opentelemetry-instrument --service_name recordlinker
uvicorn recordlinker.main:app --app-dir src
--host 0 --port 8080
--log-config src/recordlinker/log_config.yml
depends_on:
db:
condition: service_healthy
Expand Down
3 changes: 3 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,9 @@ prod = [
[tool.setuptools]
package-dir = {"" = "src"}

[tool.setuptools.package-data]
recordlinker = ["assets/*"]

[tool.setuptools.packages.find]
where = ["src"]
namespaces = false
Expand Down
6 changes: 3 additions & 3 deletions src/recordlinker/config.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import json
import logging.config
import typing

import pydantic
import pydantic_settings

from recordlinker.utils import path as utils


class ConfigurationError(Exception):
"""
Expand Down Expand Up @@ -99,8 +100,7 @@ def configure_logging(self) -> None:
if self.log_config:
# Load logging config from the provided file
try:
with open(self.log_config, "r") as fobj:
config = json.loads(fobj.read())
config = utils.read_json(self.log_config)
except Exception as exc:
msg = f"Error loading log configuration: {self.log_config}"
raise ConfigurationError(msg) from exc
Expand Down
4 changes: 2 additions & 2 deletions src/recordlinker/models/algorithm.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@
from sqlalchemy import schema
from sqlalchemy import types as sqltypes

from recordlinker import utils
from recordlinker.config import ConfigurationError
from recordlinker.config import settings
from recordlinker.utils import functools as func_utils
from recordlinker.utils import path as path_utils

from .base import Base

Expand Down Expand Up @@ -143,7 +143,7 @@ def create_initial_algorithms(target, connection, **kw) -> typing.List[Algorithm
"""
if settings.initial_algorithms:
try:
data = utils.read_json(settings.initial_algorithms)
data = path_utils.read_json(settings.initial_algorithms)
except Exception as exc:
raise ConfigurationError("Error loading initial algorithms") from exc
if not any(algo.get("is_default") for algo in data):
Expand Down
27 changes: 0 additions & 27 deletions src/recordlinker/utils/__init__.py
Original file line number Diff line number Diff line change
@@ -1,27 +0,0 @@
import json
import pathlib


def project_root() -> pathlib.Path:
"""
Returns the path to the project root directory.
"""
cwd = pathlib.Path(__file__).resolve()
root = cwd

# FIXME: this only works when in the git project root and will fail if we install the
# package into the site-packages
while not (root / "pyproject.toml").exists():
if root.parent == root:
raise FileNotFoundError("Project root with 'pyproject.toml' not found.")
root = root.parent
return root


def read_json(*filepaths: str) -> dict:
"""
Loads a JSON file.
"""
filename = pathlib.Path(project_root(), *filepaths)
with open(filename, "r") as fobj:
return json.load(fobj)
25 changes: 25 additions & 0 deletions src/recordlinker/utils/path.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import json
import pathlib


def project_root() -> pathlib.Path:
"""
Returns the path to the project root directory.
"""
root = pathlib.Path(__file__).resolve()
while root.name != "recordlinker":
if root.parent == root:
raise FileNotFoundError("recordlinker project root not found.")
root = root.parent
return root


def read_json(path: str) -> dict:
"""
Loads a JSON file.
"""
if not pathlib.Path(path).is_absolute():
# if path is relative, append to the project root
path = str(pathlib.Path(project_root(), path))
with open(path, "r") as fobj:
return json.load(fobj)
1 change: 0 additions & 1 deletion tests/unit/assets/initial_algorithms.json

This file was deleted.

7 changes: 4 additions & 3 deletions tests/unit/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@
from recordlinker import database
from recordlinker import main
from recordlinker import models
from recordlinker.utils import path as utils


def load_json_asset(*paths: str) -> dict | list:
def load_test_json_asset(*paths: str) -> dict | list:
"""
Loads a JSON file from the testing 'assets' directory.
"""
Expand Down Expand Up @@ -45,14 +46,14 @@ def client():
@functools.lru_cache
@pytest.fixture
def basic_algorithm():
for algo in load_json_asset("initial_algorithms.json"):
for algo in utils.read_json("assets/initial_algorithms.json"):
if algo["label"] == "dibbs-basic":
return models.Algorithm.from_dict(**algo)


@functools.lru_cache
@pytest.fixture
def enhanced_algorithm():
for algo in load_json_asset("initial_algorithms.json"):
for algo in utils.read_json("assets/initial_algorithms.json"):
if algo["label"] == "dibbs-enhanced":
return models.Algorithm.from_dict(**algo)
132 changes: 59 additions & 73 deletions tests/unit/hl7/test_fhir.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

import copy

from conftest import load_json_asset
from conftest import load_test_json_asset

from recordlinker.hl7 import fhir

Expand All @@ -20,105 +20,91 @@ def test_fhir_record_to_pii_record():
{
"value": "1234567890",
"type": {
"coding": [{
"code": "MR",
"system": "http://terminology.hl7.org/CodeSystem/v2-0203",
"display": "Medical record number"
}]
"coding": [
{
"code": "MR",
"system": "http://terminology.hl7.org/CodeSystem/v2-0203",
"display": "Medical record number",
}
]
},
},
{
"system" : "http://hl7.org/fhir/sid/us-ssn",
"value" : "111223333",
"type" : {
"coding" : [{
"system" : "http://terminology.hl7.org/CodeSystem/v2-0203",
"code" : "SS"
}]
"system": "http://hl7.org/fhir/sid/us-ssn",
"value": "111223333",
"type": {
"coding": [
{"system": "http://terminology.hl7.org/CodeSystem/v2-0203", "code": "SS"}
]
},
},
{
{
"use": "official",
"type": {
"text": "Driver's License",
"coding": [
{
"system": "http://terminology.hl7.org/CodeSystem/v2-0203",
"code": "DL",
"display": "Driver's License"
"system": "http://terminology.hl7.org/CodeSystem/v2-0203",
"code": "DL",
"display": "Driver's License",
}
],
},
"system": "urn:oid:2.16.840.1.113883.3.19.3.1.8",
"value": "D1234567",
"assigner": {
"system": "urn:oid:2.16.840.1.113883.3.19.3.1.8",
"value": "D1234567",
"assigner": {
"display": "State DMV",
"identifier": {
"system": "urn:oid:2.16.840.1.113883.19.3.1.1",
"value": "CA"
}
}
}
],
"name": [
{
"family": "Shepard",
"given": [
"John"
],
"use": "official"
}
"identifier": {"system": "urn:oid:2.16.840.1.113883.19.3.1.1", "value": "CA"},
},
},
],
"name": [{"family": "Shepard", "given": ["John"], "use": "official"}],
"birthDate": "2053-11-07",
"gender": "male",
"address": [
{
"line": [
"1234 Silversun Strip"
],
"buildingNumber": "1234",
"city": "Boston",
"state": "Massachusetts",
"postalCode": "99999",
"district": "county",
"use": "home"
}
],
"telecom": [
{
"line": ["1234 Silversun Strip"],
"buildingNumber": "1234",
"city": "Boston",
"state": "Massachusetts",
"postalCode": "99999",
"district": "county",
"use": "home",
"system": "phone",
"value": "123-456-7890"
}
],
"extension" : [
"telecom": [{"use": "home", "system": "phone", "value": "123-456-7890"}],
"extension": [
{
"url" : "http://hl7.org/fhir/StructureDefinition/individual-genderIdentity",
"extension" : [{
"url" : "value",
"valueCodeableConcept" : {
"coding" : [{
"system" : "http://snomed.info/sct",
"code" : "446141000124107",
"display" : "Identifies as female gender (finding)"
}]
"url": "http://hl7.org/fhir/StructureDefinition/individual-genderIdentity",
"extension": [
{
"url": "value",
"valueCodeableConcept": {
"coding": [
{
"system": "http://snomed.info/sct",
"code": "446141000124107",
"display": "Identifies as female gender (finding)",
}
]
},
}
}]
],
},
{
"url" : "http://hl7.org/fhir/us/core/StructureDefinition/us-core-race",
"url": "http://hl7.org/fhir/us/core/StructureDefinition/us-core-race",
"extension": [
{
"url" : "ombCategory",
"valueCoding" : {
"system" : "urn:oid:2.16.840.1.113883.6.238",
"code" : "2106-3",
"display" : "White"
}
"url": "ombCategory",
"valueCoding": {
"system": "urn:oid:2.16.840.1.113883.6.238",
"code": "2106-3",
"display": "White",
},
}
]
}
]
],
},
],
}

pii_record = fhir.fhir_record_to_pii_record(fhir_record)
Expand All @@ -142,8 +128,9 @@ def test_fhir_record_to_pii_record():
assert pii_record.drivers_license.authority == "CA"
assert pii_record.drivers_license.value == "D1234567"


def test_add_person_resource():
bundle = load_json_asset("patient_bundle.json")
bundle = load_test_json_asset("patient_bundle.json")
raw_bundle = copy.deepcopy(bundle)
patient_id = "TEST_PATIENT_ID"
person_id = "TEST_PERSON_ID"
Expand All @@ -158,4 +145,3 @@ def test_add_person_resource():
# Assert the added element is the person_resource bundle
assert returned_bundle.get("entry")[-1].get("resource").get("resourceType") == "Person"
assert returned_bundle.get("entry")[-1].get("request").get("url") == "Person/TEST_PERSON_ID"

6 changes: 3 additions & 3 deletions tests/unit/linking/test_link.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import uuid

import pytest
from conftest import load_json_asset
from conftest import load_test_json_asset

from recordlinker import models
from recordlinker import schemas
Expand Down Expand Up @@ -105,7 +105,7 @@ class TestLinkRecordAgainstMpi:
# TODO: Add test case for last name O'Neil
@pytest.fixture
def patients(self):
bundle = load_json_asset("simple_patient_bundle_to_link_with_mpi.json")
bundle = load_test_json_asset("simple_patient_bundle_to_link_with_mpi.json")
patients = []
patients: list[schemas.PIIRecord] = []
for entry in bundle["entry"]:
Expand Down Expand Up @@ -170,4 +170,4 @@ def test_enhanced_match_three(self, session, enhanced_algorithm, patients: list[
# in second pass name blocks on different cluster and address matches it,
# finds greatest strength match and correctly assigns to larger cluster
assert matches == [False, True, False, True, False, False, True]
assert sorted(list(mapped_patients.values())) == [1, 1, 1, 4]
assert sorted(list(mapped_patients.values())) == [1, 1, 1, 4]
Loading
Loading