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

Feature/additional resources templates #8

Merged
merged 28 commits into from
May 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
dfa87e4
Added some data validators
adamkells Apr 19, 2024
2acb769
Added data generator
adamkells Apr 22, 2024
f003719
adding pydantic fhir data classes
adamkells Apr 25, 2024
9f59a91
Working patient generator
adamkells Apr 29, 2024
860639b
merge branch
adamkells May 3, 2024
27e9393
modify generators
adamkells May 3, 2024
0d8da29
add refined fhir resources
adamkells May 3, 2024
5315735
commiting data generator
adamkells May 4, 2024
16aaad8
added practitioner
adamkells May 8, 2024
9cbe00f
refactor generators
adamkells May 9, 2024
25efdba
add resource tests
adamkells May 9, 2024
2b65a91
modified tests
adamkells May 11, 2024
e46880c
Merge branch 'main' into feature/data-generator
adamkells May 11, 2024
27e9bff
adding encounter
adamkells May 12, 2024
88e02ff
pre-commit tidying
adamkells May 12, 2024
61d3a78
removed pydantic generator
adamkells May 12, 2024
28562b5
fix errors
adamkells May 12, 2024
dff0e9f
modify generator registry object
adamkells May 14, 2024
8a66e2b
commit condition resource
adamkells May 14, 2024
15ba690
add further resources
adamkells May 14, 2024
8540b09
Add medication resources
adamkells May 15, 2024
1ec4c1d
refactor of base resources
adamkells May 16, 2024
361a49c
refactor base
adamkells May 16, 2024
52e0a08
add bundle
adamkells May 16, 2024
340f631
Merge branch 'main' into feature/additional-resources-templates
adamkells May 17, 2024
cc8f008
merge main
adamkells May 17, 2024
7499ca3
add annotation
adamkells May 17, 2024
6430c59
change case on generators
adamkells May 17, 2024
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
36 changes: 18 additions & 18 deletions healthchain/data_generator/base_generators.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import random
import string

from healthchain.fhir_resources.base_resources import (
from healthchain.fhir_resources.primitive_resources import (
booleanModel,
canonicalModel,
codeModel,
Expand Down Expand Up @@ -58,21 +58,21 @@ def generate():


@register_generator
class booleanGenerator(BaseGenerator):
class BooleanGenerator(BaseGenerator):
@staticmethod
def generate():
return booleanModel(random.choice(["true", "false"]))


@register_generator
class canonicalGenerator(BaseGenerator):
class CanonicalGenerator(BaseGenerator):
@staticmethod
def generate():
return canonicalModel(f"https://example/{faker.uri_path()}")


@register_generator
class codeGenerator(BaseGenerator):
class CodeGenerator(BaseGenerator):
# TODO: Codes can technically have whitespace but here I've left it out for simplicity
@staticmethod
def generate():
Expand All @@ -82,98 +82,98 @@ def generate():


@register_generator
class dateGenerator(BaseGenerator):
class DateGenerator(BaseGenerator):
@staticmethod
def generate():
return dateModel(faker.date())


@register_generator
class dateTimeGenerator(BaseGenerator):
class DateTimeGenerator(BaseGenerator):
@staticmethod
def generate():
return dateTimeModel(faker.date_time().isoformat())


@register_generator
class decimalGenerator(BaseGenerator):
class DecimalGenerator(BaseGenerator):
@staticmethod
def generate():
return decimalModel(faker.random_number())


@register_generator
class idGenerator(BaseGenerator):
class IdGenerator(BaseGenerator):
@staticmethod
def generate():
return idModel(faker.uuid4())


@register_generator
class instantGenerator(BaseGenerator):
class InstantGenerator(BaseGenerator):
@staticmethod
def generate():
return instantModel(faker.date_time().isoformat())


@register_generator
class integerGenerator(BaseGenerator):
class IntegerGenerator(BaseGenerator):
@staticmethod
def generate():
return integerModel(faker.random_int())


@register_generator
class markdownGenerator(BaseGenerator):
class MarkdownGenerator(BaseGenerator):
@staticmethod
def generate():
return markdownModel(faker.text())


@register_generator
class positiveIntGenerator(BaseGenerator):
class PositiveIntGenerator(BaseGenerator):
@staticmethod
def generate():
return positiveIntModel(faker.random_int(min=1))


@register_generator
class stringGenerator(BaseGenerator):
class StringGenerator(BaseGenerator):
@staticmethod
def generate():
return stringModel(faker.word())


@register_generator
class timeGenerator(BaseGenerator):
class TimeGenerator(BaseGenerator):
@staticmethod
def generate():
return timeModel(faker.time())


@register_generator
class unsignedIntGenerator(BaseGenerator):
class UnsignedIntGenerator(BaseGenerator):
@staticmethod
def generate():
return unsignedIntModel(faker.random_int(min=0))


@register_generator
class uriGenerator(BaseGenerator):
class UriGenerator(BaseGenerator):
@staticmethod
def generate():
return uriModel(f"https://example/{faker.uri_path()}")


@register_generator
class urlGenerator(BaseGenerator):
class UrlGenerator(BaseGenerator):
@staticmethod
def generate():
return urlModel(f"https://example/{faker.uri_path()}")


@register_generator
class uuidGenerator(BaseGenerator):
class UuidGenerator(BaseGenerator):
@staticmethod
def generate():
return uuidModel(faker.uuid4())
159 changes: 159 additions & 0 deletions healthchain/data_generator/condition_generators.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
from healthchain.data_generator.base_generators import (
BaseGenerator,
generator_registry,
register_generator,
)
from healthchain.fhir_resources.general_purpose_resources import (
CodeableConceptModel,
CodingModel,
ReferenceModel,
)
from healthchain.fhir_resources.condition_resources import (
ConditionModel,
Condition_StageModel,
Condition_ParticipantModel,
)
from typing import Optional
from faker import Faker


faker = Faker()


@register_generator
class ClinicalStatusGenerator(BaseGenerator):
@staticmethod
def generate():
return CodeableConceptModel(
coding=[
CodingModel(
system="http://terminology.hl7.org/CodeSystem/condition-clinical",
code=faker.random_element(
elements=("active", "recurrence", "inactive", "resolved")
),
)
]
)


@register_generator
class VerificationStatusGenerator(BaseGenerator):
@staticmethod
def generate():
return CodeableConceptModel(
coding=[
CodingModel(
system="http://terminology.hl7.org/CodeSystem/condition-ver-status",
code=faker.random_element(elements=("provisional", "confirmed")),
)
]
)


@register_generator
class CategoryGenerator(BaseGenerator):
@staticmethod
def generate():
return CodeableConceptModel(
coding=[
CodingModel(
system="http://snomed.info/sct",
code=faker.random_element(
elements=("55607006", "404684003")
), # Snomed Codes -> probably want to overwrite with template
)
]
)


@register_generator
class ConditionStageGenerator(BaseGenerator):
@staticmethod
def generate():
return Condition_StageModel(
summary=generator_registry.get("CodeableConceptGenerator").generate(),
assessment=generator_registry.get("ReferenceGenerator").generate(),
type=generator_registry.get("CodeableConceptGenerator").generate(),
)


@register_generator
class SeverityGenerator(BaseGenerator):
@staticmethod
def generate():
return CodeableConceptModel(
coding=[
CodingModel(
system="http://snomed.info/sct",
code=faker.random_element(
elements=("24484000", "6736007", "255604002")
),
# TODO: Add display values for the codes
)
]
)


@register_generator
class SnomedCodeGenerator(BaseGenerator):
@staticmethod
def generate():
return CodeableConceptModel(
coding=[
CodingModel(
system="http://snomed.info/sct",
code=faker.random_element(elements=("386661006")),
display=faker.random_element(elements=("Fever")),
)
]
)


@register_generator
class BodySiteGenerator(BaseGenerator):
@staticmethod
def generate():
return CodeableConceptModel(
coding=[
CodingModel(
system="http://snomed.info/sct",
code=faker.random_element(elements=("38266002")),
display=faker.random_element(elements=("Entire body as a whole")),
)
]
)


@register_generator
class ConditionParticipantGenerator(BaseGenerator):
@staticmethod
def generate():
return Condition_ParticipantModel(
type=generator_registry.get("CodeableConceptGenerator").generate(),
individual=generator_registry.get("ReferenceGenerator").generate(),
)


@register_generator
class ConditionModelGenerator(BaseGenerator):
@staticmethod
def generate(subject_reference: Optional[str], encounter_reference: Optional[str]):
subject_reference = subject_reference or "Patient/123"
encounter_reference = encounter_reference or "Encounter/123"
return ConditionModel(
id=generator_registry.get("IdGenerator").generate(),
clinicalStatus=generator_registry.get("ClinicalStatusGenerator").generate(),
verificationStatus=generator_registry.get(
"VerificationStatusGenerator"
).generate(),
category=[generator_registry.get("CategoryGenerator").generate()],
severity=generator_registry.get("SeverityGenerator").generate(),
code=generator_registry.get("SnomedCodeGenerator").generate(),
bodySite=[generator_registry.get("BodySiteGenerator").generate()],
subject=ReferenceModel(reference=subject_reference),
encounter=ReferenceModel(reference=encounter_reference),
onsetDateTime=generator_registry.get(
"DateGenerator"
).generate(), ## Are there more plausible dates to use?
recordedDate=generator_registry.get("DateGenerator").generate(),
)
7 changes: 5 additions & 2 deletions healthchain/data_generator/encounter_generator.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
from healthchain.fhir_resources.encounter_resources import EncounterModel
from healthchain.fhir_resources.base_resources import CodingModel, CodeableConceptModel
from healthchain.fhir_resources.general_purpose_resources import (
CodingModel,
CodeableConceptModel,
)
from healthchain.data_generator.base_generators import (
BaseGenerator,
generator_registry,
Expand Down Expand Up @@ -70,7 +73,7 @@ def generate(patient_reference: Optional[str]):
patient_reference = "Patient/123"
return EncounterModel(
resourceType="Encounter",
id=generator_registry.get("idGenerator").generate(),
id=generator_registry.get("IdGenerator").generate(),
text={
"status": "generated",
"div": '<div xmlns="http://www.w3.org/1999/xhtml">Encounter with patient @example</div>',
Expand Down
45 changes: 45 additions & 0 deletions healthchain/data_generator/medication_administration_generators.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
from healthchain.fhir_resources.medication_administration_resources import (
MedicationAdministrationModel,
MedicationAdministration_DosageModel,
)
from healthchain.fhir_resources.general_purpose_resources import ReferenceModel
from healthchain.data_generator.base_generators import (
BaseGenerator,
generator_registry,
register_generator,
)
from faker import Faker


faker = Faker()


@register_generator
class MedicationAdministrationDosageGenerator(BaseGenerator):
@staticmethod
def generate():
return MedicationAdministration_DosageModel(
text=faker.random_element(
elements=(
"Take 1 tablet by mouth once daily",
"Take 2 tablets by mouth once daily",
)
),
)


@register_generator
class MedicationAdministrationGenerator(BaseGenerator):
@staticmethod
def generate(subject_reference: str, encounter_reference: str):
return MedicationAdministrationModel(
id=generator_registry.get("IdGenerator").generate(),
status=generator_registry.get("EventStatusGenerator").generate(),
medication=generator_registry.get("MedicationGenerator").generate(),
subject=ReferenceModel(reference=subject_reference),
encounter=ReferenceModel(reference=encounter_reference),
authoredOn=generator_registry.get("DateGenerator").generate(),
dosage=generator_registry.get(
"MedicationAdministrationDosageGenerator"
).generate(),
)
Loading
Loading