From 6fbefa902c6e6b663fbd8d719c4a9d76e2759aca Mon Sep 17 00:00:00 2001 From: Aleksandr Penskoi Date: Fri, 24 Jul 2026 15:44:18 +0400 Subject: [PATCH 01/16] feat(py): validate prohibited choice variants in profile validate() validate() now emits validate_choice_prohibited(...) from the choice declaration's prohibited list, covering variants that are never materialized as instance fields. Replaces the per-instance validate_excluded emission, mirroring the TypeScript writer. --- .../python/profile_helpers.py | 11 ++++++++ .../python/profile-validation.ts | 28 ++++++------------- 2 files changed, 19 insertions(+), 20 deletions(-) diff --git a/assets/api/writer-generator/python/profile_helpers.py b/assets/api/writer-generator/python/profile_helpers.py index 0cc130a2..a9d8db86 100644 --- a/assets/api/writer-generator/python/profile_helpers.py +++ b/assets/api/writer-generator/python/profile_helpers.py @@ -451,6 +451,17 @@ def validate_choice_required(res: object, profile_name: str, choices: Sequence[s return [f"{profile_name}: at least one of {', '.join(choices)} is required"] +def validate_choice_prohibited(res: object, profile_name: str, prohibited: Sequence[str]) -> list[str]: + """Checks that none of the listed prohibited choice-type variants is present. + E.g. a profile narrowing ``value[x]`` to ``value_quantity`` prohibits every + other variant.""" + return [ + f"{profile_name}: field '{c}' must not be present" + for c in prohibited + if _get_field(res, c) is not None + ] + + def validate_enum(res: object, profile_name: str, field: str, allowed: Sequence[str]) -> list[str]: """Checks that the value of ``field`` has a code within ``allowed``. Handles plain strings, Coding, and CodeableConcept.""" diff --git a/src/api/writer-generator/python/profile-validation.ts b/src/api/writer-generator/python/profile-validation.ts index 6e4b8004..681a70c0 100644 --- a/src/api/writer-generator/python/profile-validation.ts +++ b/src/api/writer-generator/python/profile-validation.ts @@ -1,6 +1,5 @@ import { type ChoiceFieldInstance, - type Field, isChoiceDeclarationField, isChoiceInstanceField, isNotChoiceDeclarationField, @@ -27,10 +26,7 @@ export const collectValidateBody = ( const fields = flatProfile.fields; for (const [name, field] of Object.entries(fields)) { const pyName = pyFieldName(name, formatName); - if (isChoiceInstanceField(field)) { - collectProhibitedChoiceValidation(fields, name, pyName, helpers, errorLines); - continue; - } + if (isChoiceInstanceField(field)) continue; if (isChoiceDeclarationField(field)) { if (field.required) { helpers.add("validate_choice_required"); @@ -39,6 +35,13 @@ export const collectValidateBody = ( `errors.extend(validate_choice_required(self._resource, profile_name, ${JSON.stringify(pyChoices)}))`, ); } + if (field.prohibited?.length) { + helpers.add("validate_choice_prohibited"); + const pyProhibited = field.prohibited.map((c) => pyFieldName(c, formatName)); + errorLines.push( + `errors.extend(validate_choice_prohibited(self._resource, profile_name, ${JSON.stringify(pyProhibited)}))`, + ); + } continue; } if (field.excluded) { @@ -91,21 +94,6 @@ export const collectValidateBody = ( return helpers; }; -const collectProhibitedChoiceValidation = ( - fields: Record, - name: string, - pyName: string, - helpers: Set, - errorLines: string[], -): void => { - const field = fields[name]; - if (!field || !isChoiceInstanceField(field)) return; - const decl = fields[field.choiceOf]; - if (!decl || !isChoiceDeclarationField(decl) || !decl.prohibited?.includes(name)) return; - helpers.add("validate_excluded"); - errorLines.push(`errors.extend(validate_excluded(self._resource, profile_name, ${JSON.stringify(pyName)}))`); -}; - const collectSliceCardinalityValidation = ( field: RegularField | ChoiceFieldInstance, name: string, From 089730ad4e9e853368dfad1397844ef3570c2263 Mon Sep 17 00:00:00 2001 From: Aleksandr Penskoi Date: Fri, 24 Jul 2026 15:44:18 +0400 Subject: [PATCH 02/16] test(py): update profile snapshots for prohibited choice validation --- .../__snapshots__/python.test.ts.snap | 35 +++++++++---------- 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/test/api/write-generator/__snapshots__/python.test.ts.snap b/test/api/write-generator/__snapshots__/python.test.ts.snap index 895f7062..e72f63fa 100644 --- a/test/api/write-generator/__snapshots__/python.test.ts.snap +++ b/test/api/write-generator/__snapshots__/python.test.ts.snap @@ -423,8 +423,8 @@ from fhir_types.hl7_fhir_r4_core.observation import Observation from fhir_types.hl7_fhir_r4_core.base import CodeableConcept, Period, Quantity, Reference from fhir_types.profile_helpers import ( apply_slice_match, build_resource, ensure_profile, ensure_slice_defaults, get_array_slice, matches_value, \\ - set_array_slice, strip_match_keys, validate_choice_required, validate_enum, validate_fixed_value, validate_must_support, \\ - validate_reference, validate_required, validate_slice_cardinality + set_array_slice, strip_match_keys, validate_choice_prohibited, validate_choice_required, validate_enum, \\ + validate_fixed_value, validate_must_support, validate_reference, validate_required, validate_slice_cardinality ) @@ -564,8 +564,10 @@ class ObservationBodyweightProfile: errors.extend(validate_required(self._resource, profile_name, "subject")) errors.extend(validate_reference(self._resource, profile_name, "subject", ["Patient"])) errors.extend(validate_choice_required(self._resource, profile_name, ["effectiveDateTime","effectivePeriod"])) + errors.extend(validate_choice_prohibited(self._resource, profile_name, ["effectiveTiming","effectiveInstant"])) errors.extend(validate_reference(self._resource, profile_name, "hasMember", ["MolecularSequence","QuestionnaireResponse","Observation"])) errors.extend(validate_reference(self._resource, profile_name, "derivedFrom", ["DocumentReference","ImagingStudy","Media","MolecularSequence","QuestionnaireResponse","Observation"])) + errors.extend(validate_choice_prohibited(self._resource, profile_name, ["valueCodeableConcept","valueString","valueBoolean","valueInteger","valueRange","valueRatio","valueSampledData","valueTime","valueDateTime","valuePeriod"])) warnings.extend(validate_enum(self._resource, profile_name, "category", ["social-history","vital-signs","imaging","laboratory","procedure","survey","exam","therapy","activity"])) warnings.extend(validate_enum(self._resource, profile_name, "code", ["85353-1","9279-1","8867-4","2708-6","8310-5","8302-2","9843-4","29463-7","39156-5","85354-9","8480-6","8462-4","8478-0"])) warnings.extend(validate_enum(self._resource, profile_name, "dataAbsentReason", ["unknown","asked-unknown","temp-unknown","not-asked","asked-declined","masked","not-applicable","unsupported","as-text","error","not-a-number","negative-infinity","positive-infinity","not-performed","not-permitted"])) @@ -591,8 +593,9 @@ from fhir_types.hl7_fhir_r4_core.base import ( from fhir_types.hl7_fhir_r4_core.observation import ObservationComponent from fhir_types.profile_helpers import ( apply_slice_match, build_resource, ensure_profile, ensure_slice_defaults, get_array_slice, matches_value, \\ - set_array_slice, strip_match_keys, unwrap_slice_choice, validate_choice_required, validate_enum, validate_fixed_value, \\ - validate_must_support, validate_reference, validate_required, validate_slice_cardinality, wrap_slice_choice + set_array_slice, strip_match_keys, unwrap_slice_choice, validate_choice_prohibited, validate_choice_required, \\ + validate_enum, validate_fixed_value, validate_must_support, validate_reference, validate_required, validate_slice_cardinality, \\ + wrap_slice_choice ) @@ -791,10 +794,12 @@ class ObservationBpProfile: errors.extend(validate_required(self._resource, profile_name, "subject")) errors.extend(validate_reference(self._resource, profile_name, "subject", ["Patient"])) errors.extend(validate_choice_required(self._resource, profile_name, ["effectiveDateTime","effectivePeriod"])) + errors.extend(validate_choice_prohibited(self._resource, profile_name, ["effectiveTiming","effectiveInstant"])) errors.extend(validate_reference(self._resource, profile_name, "hasMember", ["MolecularSequence","QuestionnaireResponse","Observation"])) errors.extend(validate_reference(self._resource, profile_name, "derivedFrom", ["DocumentReference","ImagingStudy","Media","MolecularSequence","QuestionnaireResponse","Observation"])) errors.extend(validate_slice_cardinality(self._resource, profile_name, "component", {"code":{"coding":[{"code":"8480-6","system":"http://loinc.org"}]}}, "SystolicBP", 1, 1)) errors.extend(validate_slice_cardinality(self._resource, profile_name, "component", {"code":{"coding":[{"code":"8462-4","system":"http://loinc.org"}]}}, "DiastolicBP", 1, 1)) + errors.extend(validate_choice_prohibited(self._resource, profile_name, ["valueCodeableConcept","valueString","valueBoolean","valueInteger","valueRange","valueRatio","valueSampledData","valueTime","valueDateTime","valuePeriod"])) warnings.extend(validate_enum(self._resource, profile_name, "category", ["social-history","vital-signs","imaging","laboratory","procedure","survey","exam","therapy","activity"])) warnings.extend(validate_enum(self._resource, profile_name, "code", ["85353-1","9279-1","8867-4","2708-6","8310-5","8302-2","9843-4","29463-7","39156-5","85354-9","8480-6","8462-4","8478-0"])) warnings.extend(validate_enum(self._resource, profile_name, "dataAbsentReason", ["unknown","asked-unknown","temp-unknown","not-asked","asked-declined","masked","not-applicable","unsupported","as-text","error","not-a-number","negative-infinity","positive-infinity","not-performed","not-permitted"])) @@ -1087,8 +1092,9 @@ from fhir_types.hl7_fhir_r4_core.base import ( from fhir_types.hl7_fhir_r4_core.observation import ObservationComponent from fhir_types.profile_helpers import ( apply_slice_match, build_resource, ensure_profile, ensure_slice_defaults, get_array_slice, matches_value, \\ - set_array_slice, strip_match_keys, unwrap_slice_choice, validate_choice_required, validate_enum, validate_fixed_value, \\ - validate_must_support, validate_reference, validate_required, validate_slice_cardinality, wrap_slice_choice + set_array_slice, strip_match_keys, unwrap_slice_choice, validate_choice_prohibited, validate_choice_required, \\ + validate_enum, validate_fixed_value, validate_must_support, validate_reference, validate_required, validate_slice_cardinality, \\ + wrap_slice_choice ) @@ -1467,6 +1473,7 @@ class UscoreBloodPressureProfile: errors.extend(validate_required(self._resource, profile_name, "subject")) errors.extend(validate_reference(self._resource, profile_name, "subject", ["Patient"])) errors.extend(validate_choice_required(self._resource, profile_name, ["effectiveDateTime","effectivePeriod"])) + errors.extend(validate_choice_prohibited(self._resource, profile_name, ["effectiveTiming","effectiveInstant"])) errors.extend(validate_reference(self._resource, profile_name, "hasMember", ["MolecularSequence","QuestionnaireResponse","Observation"])) errors.extend(validate_reference(self._resource, profile_name, "derivedFrom", ["DocumentReference","ImagingStudy","Media","MolecularSequence","QuestionnaireResponse","Observation"])) errors.extend(validate_slice_cardinality(self._resource, profile_name, "component", {"code":{"coding":[{"system":"http://loinc.org","code":"8480-6"}]}}, "systolic", 1, 1)) @@ -1497,8 +1504,8 @@ from fhir_types.hl7_fhir_r4_core.base import ( ) from fhir_types.profile_helpers import ( apply_slice_match, build_resource, ensure_profile, ensure_slice_defaults, get_array_slice, matches_value, \\ - set_array_slice, strip_match_keys, validate_choice_required, validate_enum, validate_excluded, validate_fixed_value, \\ - validate_must_support, validate_reference, validate_required, validate_slice_cardinality + set_array_slice, strip_match_keys, validate_choice_prohibited, validate_choice_required, validate_enum, \\ + validate_fixed_value, validate_must_support, validate_reference, validate_required, validate_slice_cardinality ) @@ -1708,19 +1715,11 @@ class UscoreBodyWeightProfile: errors.extend(validate_required(self._resource, profile_name, "subject")) errors.extend(validate_reference(self._resource, profile_name, "subject", ["Patient"])) errors.extend(validate_choice_required(self._resource, profile_name, ["effectiveDateTime","effectivePeriod"])) + errors.extend(validate_choice_prohibited(self._resource, profile_name, ["effectiveTiming","effectiveInstant"])) errors.extend(validate_reference(self._resource, profile_name, "hasMember", ["MolecularSequence","QuestionnaireResponse","Observation"])) errors.extend(validate_reference(self._resource, profile_name, "derivedFrom", ["DocumentReference","ImagingStudy","Media","MolecularSequence","QuestionnaireResponse","Observation"])) errors.extend(validate_reference(self._resource, profile_name, "performer", ["PractitionerRole","CareTeam","Organization","Patient","Practitioner","RelatedPerson"])) - errors.extend(validate_excluded(self._resource, profile_name, "valueCodeableConcept")) - errors.extend(validate_excluded(self._resource, profile_name, "valueString")) - errors.extend(validate_excluded(self._resource, profile_name, "valueBoolean")) - errors.extend(validate_excluded(self._resource, profile_name, "valueInteger")) - errors.extend(validate_excluded(self._resource, profile_name, "valueRange")) - errors.extend(validate_excluded(self._resource, profile_name, "valueRatio")) - errors.extend(validate_excluded(self._resource, profile_name, "valueSampledData")) - errors.extend(validate_excluded(self._resource, profile_name, "valueTime")) - errors.extend(validate_excluded(self._resource, profile_name, "valueDateTime")) - errors.extend(validate_excluded(self._resource, profile_name, "valuePeriod")) + errors.extend(validate_choice_prohibited(self._resource, profile_name, ["valueCodeableConcept","valueString","valueBoolean","valueInteger","valueRange","valueRatio","valueSampledData","valueTime","valueDateTime","valuePeriod"])) warnings.extend(validate_enum(self._resource, profile_name, "category", ["social-history","vital-signs","imaging","laboratory","procedure","survey","exam","therapy","activity"])) warnings.extend(validate_enum(self._resource, profile_name, "code", ["2708-6","29463-7","3140-1","3150-0","3151-8","39156-5","59408-5","59575-1","59576-9","77606-2","8287-5","8289-1","8302-2","8306-3","8310-5","8462-4","8478-0","8480-6","8867-4","9279-1","9843-4"])) warnings.extend(validate_enum(self._resource, profile_name, "dataAbsentReason", ["unknown","asked-unknown","temp-unknown","not-asked","asked-declined","masked","not-applicable","unsupported","as-text","error","not-a-number","negative-infinity","positive-infinity","not-performed","not-permitted"])) From 2c39b590c58617d22a6ae4a6bc2ffb7078b18d85 Mon Sep 17 00:00:00 2001 From: Aleksandr Penskoi Date: Fri, 24 Jul 2026 15:51:15 +0400 Subject: [PATCH 03/16] feat(py): validate required fields inside slice elements Port validateSliceFields from the TypeScript writer: for each array item matching a slice discriminator, check the slice's required fields and the single variant of a constrained choice (e.g. BP component value[x] narrowed to valueQuantity). --- .../python/profile_helpers.py | 23 +++++++++++ .../python/profile-validation.ts | 41 ++++++++++++++----- src/api/writer-generator/python/profile.ts | 8 +--- 3 files changed, 55 insertions(+), 17 deletions(-) diff --git a/assets/api/writer-generator/python/profile_helpers.py b/assets/api/writer-generator/python/profile_helpers.py index a9d8db86..f3146147 100644 --- a/assets/api/writer-generator/python/profile_helpers.py +++ b/assets/api/writer-generator/python/profile_helpers.py @@ -444,6 +444,29 @@ def validate_slice_cardinality( return errors +def validate_slice_fields( + res: object, + profile_name: str, + field: str, + match: Mapping[str, Any], + slice_name: str, + required_fields: Sequence[str], +) -> list[str]: + """Validates required fields within matched slice elements. For each array + item matching the discriminator, checks that the listed fields are present.""" + items = _get_field(res, field) or [] + if not isinstance(items, Iterable): + items = [] + errors: list[str] = [] + for item in items: + if not matches_value(item, match): + continue + for rf in required_fields: + if _get_field(item, rf) is None: + errors.append(f"{profile_name}.{field}[{slice_name}].{rf} is required") + return errors + + def validate_choice_required(res: object, profile_name: str, choices: Sequence[str]) -> list[str]: """Checks that at least one of the listed choice-type variants is present.""" if any(_get_field(res, c) is not None for c in choices): diff --git a/src/api/writer-generator/python/profile-validation.ts b/src/api/writer-generator/python/profile-validation.ts index 681a70c0..147d6b85 100644 --- a/src/api/writer-generator/python/profile-validation.ts +++ b/src/api/writer-generator/python/profile-validation.ts @@ -17,12 +17,13 @@ import { pyFieldName } from "./profile-naming"; * set of helper function names referenced. Pure: no writer side effects. */ export const collectValidateBody = ( flatProfile: SnapshotProfileTypeSchema, - resolveRef: TypeSchemaIndex["findLastSpecializationByIdentifier"], + tsIndex: TypeSchemaIndex, errorLines: string[], warningLines: string[], formatName: (s: string) => string, ): Set => { const helpers = new Set(); + const resolveRef = tsIndex.findLastSpecializationByIdentifier; const fields = flatProfile.fields; for (const [name, field] of Object.entries(fields)) { const pyName = pyFieldName(name, formatName); @@ -87,29 +88,49 @@ export const collectValidateBody = ( ); } if (field.slicing?.slices) { - collectSliceCardinalityValidation(field, pyName, helpers, errorLines); + collectSliceValidation(field, pyName, helpers, errorLines, tsIndex, formatName); } } } return helpers; }; -const collectSliceCardinalityValidation = ( +const collectSliceValidation = ( field: RegularField | ChoiceFieldInstance, name: string, helpers: Set, errorLines: string[], + tsIndex: TypeSchemaIndex, + formatName: (s: string) => string, ): void => { if (!field.slicing?.slices) return; for (const [sliceName, slice] of Object.entries(field.slicing.slices)) { - if (slice.min === undefined && slice.max === undefined) continue; const match = slice.match ?? {}; if (Object.keys(match).length === 0) continue; - const min = slice.min ?? 0; - const max = slice.max ?? 0; - helpers.add("validate_slice_cardinality"); - errorLines.push( - `errors.extend(validate_slice_cardinality(self._resource, profile_name, ${JSON.stringify(name)}, ${JSON.stringify(match)}, ${JSON.stringify(sliceName)}, ${min}, ${max}))`, - ); + if (slice.min !== undefined || slice.max !== undefined) { + const min = slice.min ?? 0; + const max = slice.max ?? 0; + helpers.add("validate_slice_cardinality"); + errorLines.push( + `errors.extend(validate_slice_cardinality(self._resource, profile_name, ${JSON.stringify(name)}, ${JSON.stringify(match)}, ${JSON.stringify(sliceName)}, ${min}, ${max}))`, + ); + } + // Collect required fields within the slice element + const sliceRequiredFields: string[] = []; + const matchKeys = new Set(Object.keys(match)); + for (const rf of slice.required ?? []) { + if (!matchKeys.has(rf)) sliceRequiredFields.push(pyFieldName(rf, formatName)); + } + // Constrained choice: the single variant is required + if (field.type && slice.elements) { + const cc = tsIndex.constrainedChoice(field.type.package, field.type, slice.elements); + if (cc) sliceRequiredFields.push(pyFieldName(cc.variant, formatName)); + } + if (sliceRequiredFields.length > 0) { + helpers.add("validate_slice_fields"); + errorLines.push( + `errors.extend(validate_slice_fields(self._resource, profile_name, ${JSON.stringify(name)}, ${JSON.stringify(match)}, ${JSON.stringify(sliceName)}, ${JSON.stringify(sliceRequiredFields)}))`, + ); + } } }; diff --git a/src/api/writer-generator/python/profile.ts b/src/api/writer-generator/python/profile.ts index 8b4b943f..11054591 100644 --- a/src/api/writer-generator/python/profile.ts +++ b/src/api/writer-generator/python/profile.ts @@ -403,13 +403,7 @@ const generateProfileModule = (w: Python, tsIndex: TypeSchemaIndex, flatProfile: const resolvedNames = resolveProfileMethodBaseNames(extensions, sliceDefs); const errorLines: string[] = []; const warningLines: string[] = []; - const validationHelpers = collectValidateBody( - flatProfile, - tsIndex.findLastSpecializationByIdentifier, - errorLines, - warningLines, - w.nameFormatFunction, - ); + const validationHelpers = collectValidateBody(flatProfile, tsIndex, errorLines, warningLines, w.nameFormatFunction); const helperImports = collectHelperImports(isResourceBase, factoryInfo, sliceDefs, extensions, validationHelpers); const typeImports = collectTypeImports( From 99a302246c1b2cffa24d1db840a1fa60fa733bd9 Mon Sep 17 00:00:00 2001 From: Aleksandr Penskoi Date: Fri, 24 Jul 2026 15:51:16 +0400 Subject: [PATCH 04/16] test(py): update profile snapshots for slice field validation --- .../__snapshots__/python.test.ts.snap | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/test/api/write-generator/__snapshots__/python.test.ts.snap b/test/api/write-generator/__snapshots__/python.test.ts.snap index e72f63fa..bc617f0a 100644 --- a/test/api/write-generator/__snapshots__/python.test.ts.snap +++ b/test/api/write-generator/__snapshots__/python.test.ts.snap @@ -595,7 +595,7 @@ from fhir_types.profile_helpers import ( apply_slice_match, build_resource, ensure_profile, ensure_slice_defaults, get_array_slice, matches_value, \\ set_array_slice, strip_match_keys, unwrap_slice_choice, validate_choice_prohibited, validate_choice_required, \\ validate_enum, validate_fixed_value, validate_must_support, validate_reference, validate_required, validate_slice_cardinality, \\ - wrap_slice_choice + validate_slice_fields, wrap_slice_choice ) @@ -798,7 +798,9 @@ class ObservationBpProfile: errors.extend(validate_reference(self._resource, profile_name, "hasMember", ["MolecularSequence","QuestionnaireResponse","Observation"])) errors.extend(validate_reference(self._resource, profile_name, "derivedFrom", ["DocumentReference","ImagingStudy","Media","MolecularSequence","QuestionnaireResponse","Observation"])) errors.extend(validate_slice_cardinality(self._resource, profile_name, "component", {"code":{"coding":[{"code":"8480-6","system":"http://loinc.org"}]}}, "SystolicBP", 1, 1)) + errors.extend(validate_slice_fields(self._resource, profile_name, "component", {"code":{"coding":[{"code":"8480-6","system":"http://loinc.org"}]}}, "SystolicBP", ["valueQuantity"])) errors.extend(validate_slice_cardinality(self._resource, profile_name, "component", {"code":{"coding":[{"code":"8462-4","system":"http://loinc.org"}]}}, "DiastolicBP", 1, 1)) + errors.extend(validate_slice_fields(self._resource, profile_name, "component", {"code":{"coding":[{"code":"8462-4","system":"http://loinc.org"}]}}, "DiastolicBP", ["valueQuantity"])) errors.extend(validate_choice_prohibited(self._resource, profile_name, ["valueCodeableConcept","valueString","valueBoolean","valueInteger","valueRange","valueRatio","valueSampledData","valueTime","valueDateTime","valuePeriod"])) warnings.extend(validate_enum(self._resource, profile_name, "category", ["social-history","vital-signs","imaging","laboratory","procedure","survey","exam","therapy","activity"])) warnings.extend(validate_enum(self._resource, profile_name, "code", ["85353-1","9279-1","8867-4","2708-6","8310-5","8302-2","9843-4","29463-7","39156-5","85354-9","8480-6","8462-4","8478-0"])) @@ -1094,7 +1096,7 @@ from fhir_types.profile_helpers import ( apply_slice_match, build_resource, ensure_profile, ensure_slice_defaults, get_array_slice, matches_value, \\ set_array_slice, strip_match_keys, unwrap_slice_choice, validate_choice_prohibited, validate_choice_required, \\ validate_enum, validate_fixed_value, validate_must_support, validate_reference, validate_required, validate_slice_cardinality, \\ - wrap_slice_choice + validate_slice_fields, wrap_slice_choice ) @@ -1477,7 +1479,9 @@ class UscoreBloodPressureProfile: errors.extend(validate_reference(self._resource, profile_name, "hasMember", ["MolecularSequence","QuestionnaireResponse","Observation"])) errors.extend(validate_reference(self._resource, profile_name, "derivedFrom", ["DocumentReference","ImagingStudy","Media","MolecularSequence","QuestionnaireResponse","Observation"])) errors.extend(validate_slice_cardinality(self._resource, profile_name, "component", {"code":{"coding":[{"system":"http://loinc.org","code":"8480-6"}]}}, "systolic", 1, 1)) + errors.extend(validate_slice_fields(self._resource, profile_name, "component", {"code":{"coding":[{"system":"http://loinc.org","code":"8480-6"}]}}, "systolic", ["valueQuantity"])) errors.extend(validate_slice_cardinality(self._resource, profile_name, "component", {"code":{"coding":[{"system":"http://loinc.org","code":"8462-4"}]}}, "diastolic", 1, 1)) + errors.extend(validate_slice_fields(self._resource, profile_name, "component", {"code":{"coding":[{"system":"http://loinc.org","code":"8462-4"}]}}, "diastolic", ["valueQuantity"])) errors.extend(validate_reference(self._resource, profile_name, "performer", ["PractitionerRole","CareTeam","Organization","Patient","Practitioner","RelatedPerson"])) warnings.extend(validate_enum(self._resource, profile_name, "category", ["social-history","vital-signs","imaging","laboratory","procedure","survey","exam","therapy","activity"])) warnings.extend(validate_enum(self._resource, profile_name, "code", ["2708-6","29463-7","3140-1","3150-0","3151-8","39156-5","59408-5","59575-1","59576-9","77606-2","8287-5","8289-1","8302-2","8306-3","8310-5","8462-4","8478-0","8480-6","8867-4","9279-1","9843-4"])) @@ -1744,7 +1748,7 @@ from fhir_types.hl7_fhir_r4_core.base import Extension from fhir_types.profile_helpers import ( _get_key, apply_slice_match, build_resource, ensure_slice_defaults, get_array_slice, get_extension_value, \\ is_extension, is_record, matches_value, push_extension, set_array_slice, strip_match_keys, unwrap_slice_choice, \\ - validate_fixed_value, validate_required, validate_slice_cardinality, wrap_slice_choice + validate_fixed_value, validate_required, validate_slice_cardinality, validate_slice_fields, wrap_slice_choice ) @@ -1951,7 +1955,10 @@ class UscoreRaceExtension: warnings: list[str] = [] errors.extend(validate_required(self._resource, profile_name, "extension")) errors.extend(validate_slice_cardinality(self._resource, profile_name, "extension", {"url":"ombCategory"}, "ombCategory", 0, 6)) + errors.extend(validate_slice_fields(self._resource, profile_name, "extension", {"url":"ombCategory"}, "ombCategory", ["value","valueCoding"])) + errors.extend(validate_slice_fields(self._resource, profile_name, "extension", {"url":"detailed"}, "detailed", ["value","valueCoding"])) errors.extend(validate_slice_cardinality(self._resource, profile_name, "extension", {"url":"text"}, "text", 1, 1)) + errors.extend(validate_slice_fields(self._resource, profile_name, "extension", {"url":"text"}, "text", ["value","valueString"])) errors.extend(validate_required(self._resource, profile_name, "url")) errors.extend(validate_fixed_value(self._resource, profile_name, "url", "http://hl7.org/fhir/us/core/StructureDefinition/us-core-race")) return {"errors": errors, "warnings": warnings} From 904bb69c8046bfe3c71f7aa04ab67b91e2d57945 Mon Sep 17 00:00:00 2001 From: Aleksandr Penskoi Date: Fri, 24 Jul 2026 16:06:04 +0400 Subject: [PATCH 05/16] feat(py): emit validate_required for inherited base-required fields Base-resource required fields the profile chain does not re-state live in snapshot.inheritedRequiredFields, outside the fields map. Port the TypeScript writer's emission so the generated validate() covers them. Also extract collectRegularFieldValidation to mirror the TypeScript writer's structure (and keep collectValidateBody under the complexity lint threshold). --- .../python/profile-validation.ts | 97 +++++++++++-------- 1 file changed, 57 insertions(+), 40 deletions(-) diff --git a/src/api/writer-generator/python/profile-validation.ts b/src/api/writer-generator/python/profile-validation.ts index 147d6b85..b3ac1087 100644 --- a/src/api/writer-generator/python/profile-validation.ts +++ b/src/api/writer-generator/python/profile-validation.ts @@ -23,7 +23,6 @@ export const collectValidateBody = ( formatName: (s: string) => string, ): Set => { const helpers = new Set(); - const resolveRef = tsIndex.findLastSpecializationByIdentifier; const fields = flatProfile.fields; for (const [name, field] of Object.entries(fields)) { const pyName = pyFieldName(name, formatName); @@ -45,54 +44,72 @@ export const collectValidateBody = ( } continue; } - if (field.excluded) { - helpers.add("validate_excluded"); - errorLines.push( - `errors.extend(validate_excluded(self._resource, profile_name, ${JSON.stringify(pyName)}))`, + collectRegularFieldValidation(field, pyName, helpers, errorLines, warningLines, tsIndex, formatName); + } + // Base-resource required fields the profile chain did not re-state. + // Emitted here (not via the regular field loop) because they intentionally + // live outside `fields` to avoid pulling unrelated base metadata into the + // profile's getter/setter surface. + for (const inheritedName of flatProfile.inheritedRequiredFields ?? []) { + helpers.add("validate_required"); + errorLines.push( + `errors.extend(validate_required(self._resource, profile_name, ${JSON.stringify(pyFieldName(inheritedName, formatName))}))`, + ); + } + return helpers; +}; + +const collectRegularFieldValidation = ( + field: RegularField | ChoiceFieldInstance, + pyName: string, + helpers: Set, + errorLines: string[], + warningLines: string[], + tsIndex: TypeSchemaIndex, + formatName: (s: string) => string, +): void => { + if (field.excluded) { + helpers.add("validate_excluded"); + errorLines.push(`errors.extend(validate_excluded(self._resource, profile_name, ${JSON.stringify(pyName)}))`); + return; + } + if (field.required) { + helpers.add("validate_required"); + errorLines.push(`errors.extend(validate_required(self._resource, profile_name, ${JSON.stringify(pyName)}))`); + } + if (field.valueConstraint) { + helpers.add("validate_fixed_value"); + const value = JSON.stringify(field.valueConstraint.value); + errorLines.push( + `errors.extend(validate_fixed_value(self._resource, profile_name, ${JSON.stringify(pyName)}, ${value}))`, + ); + } + if (isNotChoiceDeclarationField(field)) { + if (field.enum) { + helpers.add("validate_enum"); + const target = field.enum.isOpen ? warningLines : errorLines; + const listName = field.enum.isOpen ? "warnings" : "errors"; + target.push( + `${listName}.extend(validate_enum(self._resource, profile_name, ${JSON.stringify(pyName)}, ${JSON.stringify(field.enum.values)}))`, ); - continue; } - if (field.required) { - helpers.add("validate_required"); - errorLines.push( - `errors.extend(validate_required(self._resource, profile_name, ${JSON.stringify(pyName)}))`, + if (field.mustSupport && !field.required) { + helpers.add("validate_must_support"); + warningLines.push( + `warnings.extend(validate_must_support(self._resource, profile_name, ${JSON.stringify(pyName)}))`, ); } - if (field.valueConstraint) { - helpers.add("validate_fixed_value"); - const value = JSON.stringify(field.valueConstraint.value); + if (field.reference && field.reference.resource.length > 0) { + helpers.add("validate_reference"); + const allowed = field.reference.resource.map((ref) => tsIndex.findLastSpecializationByIdentifier(ref).name); errorLines.push( - `errors.extend(validate_fixed_value(self._resource, profile_name, ${JSON.stringify(pyName)}, ${value}))`, + `errors.extend(validate_reference(self._resource, profile_name, ${JSON.stringify(pyName)}, ${JSON.stringify(allowed)}))`, ); } - if (isNotChoiceDeclarationField(field)) { - if (field.enum) { - helpers.add("validate_enum"); - const target = field.enum.isOpen ? warningLines : errorLines; - const listName = field.enum.isOpen ? "warnings" : "errors"; - target.push( - `${listName}.extend(validate_enum(self._resource, profile_name, ${JSON.stringify(pyName)}, ${JSON.stringify(field.enum.values)}))`, - ); - } - if (field.mustSupport && !field.required) { - helpers.add("validate_must_support"); - warningLines.push( - `warnings.extend(validate_must_support(self._resource, profile_name, ${JSON.stringify(pyName)}))`, - ); - } - if (field.reference && field.reference.resource.length > 0) { - helpers.add("validate_reference"); - const allowed = field.reference.resource.map((ref) => resolveRef(ref).name); - errorLines.push( - `errors.extend(validate_reference(self._resource, profile_name, ${JSON.stringify(pyName)}, ${JSON.stringify(allowed)}))`, - ); - } - if (field.slicing?.slices) { - collectSliceValidation(field, pyName, helpers, errorLines, tsIndex, formatName); - } + if (field.slicing?.slices) { + collectSliceValidation(field, pyName, helpers, errorLines, tsIndex, formatName); } } - return helpers; }; const collectSliceValidation = ( From 3abce28e433c342668562ce102047dc54cc9c5a3 Mon Sep 17 00:00:00 2001 From: Aleksandr Penskoi Date: Fri, 24 Jul 2026 16:06:04 +0400 Subject: [PATCH 06/16] test(py): cover inherited base-required fields in the Python writer --- .../profile-inherited-required.test.ts | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/test/api/write-generator/profile-inherited-required.test.ts b/test/api/write-generator/profile-inherited-required.test.ts index 4f1674e7..ce4cbf24 100644 --- a/test/api/write-generator/profile-inherited-required.test.ts +++ b/test/api/write-generator/profile-inherited-required.test.ts @@ -72,3 +72,41 @@ describe("Profile inherited base-required fields (codegen-8iw)", async () => { expect(file).toMatch(/import\s*\{[^}]*\bvalidateRequired\b/); }); }); + +describe("Profile inherited base-required fields, Python writer (codegen-8iw)", async () => { + const result = await new APIBuilder({ logger: mkSilentLogger() }) + .localStructureDefinitions({ + package: { name: "cognovis.test.praxis", version: "0.0.1" }, + path: FIXTURE_PATH, + dependencies: [{ name: "hl7.fhir.r4.core", version: "4.0.1" }], + }) + .python({ inMemoryOnly: true, generateProfile: true, client: "none" }) + .generate(); + + const profileKey = Object.keys(result.filesGenerated.python ?? {}).find((k) => + k.includes("provenance_praxis_proposal_provenance"), + ); + const profileFile = () => (profileKey ? result.filesGenerated.python![profileKey] : undefined); + + it("should succeed", () => { + expect(result.success).toBeTrue(); + }); + + it("generates the Provenance profile class", () => { + expect(profileKey).toBeDefined(); + }); + + it("emits validate_required() for the differential-stated required fields", () => { + const file = profileFile(); + expect(file).toBeDefined(); + expect(file).toContain('validate_required(self._resource, profile_name, "activity")'); + expect(file).toContain('validate_required(self._resource, profile_name, "agent")'); + }); + + it("emits validate_required() for base-R4 required fields the profile inherits", () => { + const file = profileFile(); + expect(file).toBeDefined(); + expect(file).toContain('validate_required(self._resource, profile_name, "target")'); + expect(file).toContain('validate_required(self._resource, profile_name, "recorded")'); + }); +}); From 08200b6017c1941563cf74e2626535dc4a74addf Mon Sep 17 00:00:00 2001 From: Aleksandr Penskoi Date: Fri, 24 Jul 2026 16:12:28 +0400 Subject: [PATCH 07/16] chore(examples): regenerate python-r4-us-core profiles with ported validations Fresh BP profiles now also report the systolic/diastolic stub components' missing valueQuantity, matching the TypeScript example. --- .../profiles/bundle_example_typed_bundle.py | 3 +- .../profiles/extension_birth_place.py | 3 +- .../profiles/extension_birth_time.py | 3 +- .../profiles/extension_own_prefix.py | 3 +- .../observation_observation_bodyweight.py | 6 ++-- .../observation_observation_vitalsigns.py | 5 +-- .../extension_uscore_ethnicity_extension.py | 5 ++- ...tension_uscore_individual_sex_extension.py | 3 +- ...ion_uscore_interpreter_needed_extension.py | 3 +- .../extension_uscore_race_extension.py | 5 ++- ...ion_uscore_tribal_affiliation_extension.py | 4 ++- ...servation_uscore_blood_pressure_profile.py | 8 +++-- .../observation_uscore_body_weight_profile.py | 16 +++------ .../observation_uscore_vital_signs_profile.py | 5 +-- .../fhir_types/profile_helpers.py | 34 +++++++++++++++++++ examples/python-r4-us-core/test_profile_bp.py | 2 ++ 16 files changed, 79 insertions(+), 29 deletions(-) diff --git a/examples/python-r4-us-core/fhir_types/example_folder_structures/profiles/bundle_example_typed_bundle.py b/examples/python-r4-us-core/fhir_types/example_folder_structures/profiles/bundle_example_typed_bundle.py index 8455acf8..b22bb1e6 100644 --- a/examples/python-r4-us-core/fhir_types/example_folder_structures/profiles/bundle_example_typed_bundle.py +++ b/examples/python-r4-us-core/fhir_types/example_folder_structures/profiles/bundle_example_typed_bundle.py @@ -13,7 +13,7 @@ from fhir_types.hl7_fhir_r4_core.resource import Resource from fhir_types.profile_helpers import ( build_resource, ensure_profile, get_array_slice, get_array_slices, set_array_slice, set_array_slices, \ - validate_slice_cardinality + validate_required, validate_slice_cardinality ) @@ -99,5 +99,6 @@ def validate(self) -> dict[str, list[str]]: errors: list[str] = [] warnings: list[str] = [] errors.extend(validate_slice_cardinality(self._resource, profile_name, "entry", {"resource":{"resourceType":"Patient"}}, "PatientEntry", 1, 1)) + errors.extend(validate_required(self._resource, profile_name, "type")) return {"errors": errors, "warnings": warnings} diff --git a/examples/python-r4-us-core/fhir_types/hl7_fhir_r4_core/profiles/extension_birth_place.py b/examples/python-r4-us-core/fhir_types/hl7_fhir_r4_core/profiles/extension_birth_place.py index 5d7fd9e2..4a1d2a74 100644 --- a/examples/python-r4-us-core/fhir_types/hl7_fhir_r4_core/profiles/extension_birth_place.py +++ b/examples/python-r4-us-core/fhir_types/hl7_fhir_r4_core/profiles/extension_birth_place.py @@ -9,7 +9,7 @@ from fhir_types.hl7_fhir_r4_core.base import Extension from fhir_types.hl7_fhir_r4_core.base import Address from fhir_types.profile_helpers import ( - build_resource, validate_choice_required, validate_fixed_value, validate_required + build_resource, validate_choice_prohibited, validate_choice_required, validate_fixed_value, validate_required ) @@ -68,5 +68,6 @@ def validate(self) -> dict[str, list[str]]: errors.extend(validate_required(self._resource, profile_name, "url")) errors.extend(validate_fixed_value(self._resource, profile_name, "url", "http://hl7.org/fhir/StructureDefinition/patient-birthPlace")) errors.extend(validate_choice_required(self._resource, profile_name, ["valueAddress"])) + errors.extend(validate_choice_prohibited(self._resource, profile_name, ["valueBase64binary","valueBoolean","valueCanonical","valueCode","valueDate","valueDateTime","valueDecimal","valueId","valueInstant","valueInteger","valueMarkdown","valueOid","valuePositiveInt","valueString","valueTime","valueUnsignedInt","valueUri","valueUrl","valueUuid","valueAge","valueAnnotation","valueAttachment","valueCodeableConcept","valueCoding","valueContactPoint","valueCount","valueDistance","valueDuration","valueHumanName","valueIdentifier","valueMoney","valuePeriod","valueQuantity","valueRange","valueRatio","valueReference","valueSampledData","valueSignature","valueTiming","valueContactDetail","valueContributor","valueDataRequirement","valueExpression","valueParameterDefinition","valueRelatedArtifact","valueTriggerDefinition","valueUsageContext","valueDosage","valueMeta"])) return {"errors": errors, "warnings": warnings} diff --git a/examples/python-r4-us-core/fhir_types/hl7_fhir_r4_core/profiles/extension_birth_time.py b/examples/python-r4-us-core/fhir_types/hl7_fhir_r4_core/profiles/extension_birth_time.py index 6c6e0ee2..3734087b 100644 --- a/examples/python-r4-us-core/fhir_types/hl7_fhir_r4_core/profiles/extension_birth_time.py +++ b/examples/python-r4-us-core/fhir_types/hl7_fhir_r4_core/profiles/extension_birth_time.py @@ -8,7 +8,7 @@ from fhir_types.hl7_fhir_r4_core.base import Extension from fhir_types.profile_helpers import ( - build_resource, validate_choice_required, validate_fixed_value, validate_required + build_resource, validate_choice_prohibited, validate_choice_required, validate_fixed_value, validate_required ) @@ -67,5 +67,6 @@ def validate(self) -> dict[str, list[str]]: errors.extend(validate_required(self._resource, profile_name, "url")) errors.extend(validate_fixed_value(self._resource, profile_name, "url", "http://hl7.org/fhir/StructureDefinition/patient-birthTime")) errors.extend(validate_choice_required(self._resource, profile_name, ["valueDateTime"])) + errors.extend(validate_choice_prohibited(self._resource, profile_name, ["valueBase64binary","valueBoolean","valueCanonical","valueCode","valueDate","valueDecimal","valueId","valueInstant","valueInteger","valueMarkdown","valueOid","valuePositiveInt","valueString","valueTime","valueUnsignedInt","valueUri","valueUrl","valueUuid","valueAddress","valueAge","valueAnnotation","valueAttachment","valueCodeableConcept","valueCoding","valueContactPoint","valueCount","valueDistance","valueDuration","valueHumanName","valueIdentifier","valueMoney","valuePeriod","valueQuantity","valueRange","valueRatio","valueReference","valueSampledData","valueSignature","valueTiming","valueContactDetail","valueContributor","valueDataRequirement","valueExpression","valueParameterDefinition","valueRelatedArtifact","valueTriggerDefinition","valueUsageContext","valueDosage","valueMeta"])) return {"errors": errors, "warnings": warnings} diff --git a/examples/python-r4-us-core/fhir_types/hl7_fhir_r4_core/profiles/extension_own_prefix.py b/examples/python-r4-us-core/fhir_types/hl7_fhir_r4_core/profiles/extension_own_prefix.py index 1daa8953..207c26ba 100644 --- a/examples/python-r4-us-core/fhir_types/hl7_fhir_r4_core/profiles/extension_own_prefix.py +++ b/examples/python-r4-us-core/fhir_types/hl7_fhir_r4_core/profiles/extension_own_prefix.py @@ -8,7 +8,7 @@ from fhir_types.hl7_fhir_r4_core.base import Extension from fhir_types.profile_helpers import ( - build_resource, validate_choice_required, validate_fixed_value, validate_required + build_resource, validate_choice_prohibited, validate_choice_required, validate_fixed_value, validate_required ) @@ -67,5 +67,6 @@ def validate(self) -> dict[str, list[str]]: errors.extend(validate_required(self._resource, profile_name, "url")) errors.extend(validate_fixed_value(self._resource, profile_name, "url", "http://hl7.org/fhir/StructureDefinition/humanname-own-prefix")) errors.extend(validate_choice_required(self._resource, profile_name, ["valueString"])) + errors.extend(validate_choice_prohibited(self._resource, profile_name, ["valueBase64binary","valueBoolean","valueCanonical","valueCode","valueDate","valueDateTime","valueDecimal","valueId","valueInstant","valueInteger","valueMarkdown","valueOid","valuePositiveInt","valueTime","valueUnsignedInt","valueUri","valueUrl","valueUuid","valueAddress","valueAge","valueAnnotation","valueAttachment","valueCodeableConcept","valueCoding","valueContactPoint","valueCount","valueDistance","valueDuration","valueHumanName","valueIdentifier","valueMoney","valuePeriod","valueQuantity","valueRange","valueRatio","valueReference","valueSampledData","valueSignature","valueTiming","valueContactDetail","valueContributor","valueDataRequirement","valueExpression","valueParameterDefinition","valueRelatedArtifact","valueTriggerDefinition","valueUsageContext","valueDosage","valueMeta"])) return {"errors": errors, "warnings": warnings} diff --git a/examples/python-r4-us-core/fhir_types/hl7_fhir_r4_core/profiles/observation_observation_bodyweight.py b/examples/python-r4-us-core/fhir_types/hl7_fhir_r4_core/profiles/observation_observation_bodyweight.py index 05054783..4712df61 100644 --- a/examples/python-r4-us-core/fhir_types/hl7_fhir_r4_core/profiles/observation_observation_bodyweight.py +++ b/examples/python-r4-us-core/fhir_types/hl7_fhir_r4_core/profiles/observation_observation_bodyweight.py @@ -10,8 +10,8 @@ from fhir_types.hl7_fhir_r4_core.base import CodeableConcept, Period, Quantity, Reference from fhir_types.profile_helpers import ( apply_slice_match, build_resource, ensure_profile, ensure_slice_defaults, get_array_slice, matches_value, \ - set_array_slice, strip_match_keys, validate_choice_required, validate_enum, validate_fixed_value, validate_must_support, \ - validate_reference, validate_required, validate_slice_cardinality + set_array_slice, strip_match_keys, validate_choice_prohibited, validate_choice_required, validate_enum, \ + validate_fixed_value, validate_must_support, validate_reference, validate_required, validate_slice_cardinality ) @@ -151,8 +151,10 @@ def validate(self) -> dict[str, list[str]]: errors.extend(validate_required(self._resource, profile_name, "subject")) errors.extend(validate_reference(self._resource, profile_name, "subject", ["Patient"])) errors.extend(validate_choice_required(self._resource, profile_name, ["effectiveDateTime","effectivePeriod"])) + errors.extend(validate_choice_prohibited(self._resource, profile_name, ["effectiveTiming","effectiveInstant"])) errors.extend(validate_reference(self._resource, profile_name, "hasMember", ["MolecularSequence","QuestionnaireResponse","Observation"])) errors.extend(validate_reference(self._resource, profile_name, "derivedFrom", ["DocumentReference","ImagingStudy","Media","MolecularSequence","QuestionnaireResponse","Observation"])) + errors.extend(validate_choice_prohibited(self._resource, profile_name, ["valueCodeableConcept","valueString","valueBoolean","valueInteger","valueRange","valueRatio","valueSampledData","valueTime","valueDateTime","valuePeriod"])) warnings.extend(validate_enum(self._resource, profile_name, "category", ["social-history","vital-signs","imaging","laboratory","procedure","survey","exam","therapy","activity"])) warnings.extend(validate_enum(self._resource, profile_name, "code", ["85353-1","9279-1","8867-4","2708-6","8310-5","8302-2","9843-4","29463-7","39156-5","85354-9","8480-6","8462-4","8478-0"])) warnings.extend(validate_enum(self._resource, profile_name, "dataAbsentReason", ["unknown","asked-unknown","temp-unknown","not-asked","asked-declined","masked","not-applicable","unsupported","as-text","error","not-a-number","negative-infinity","positive-infinity","not-performed","not-permitted"])) diff --git a/examples/python-r4-us-core/fhir_types/hl7_fhir_r4_core/profiles/observation_observation_vitalsigns.py b/examples/python-r4-us-core/fhir_types/hl7_fhir_r4_core/profiles/observation_observation_vitalsigns.py index b9c29cd0..7b0b4aee 100644 --- a/examples/python-r4-us-core/fhir_types/hl7_fhir_r4_core/profiles/observation_observation_vitalsigns.py +++ b/examples/python-r4-us-core/fhir_types/hl7_fhir_r4_core/profiles/observation_observation_vitalsigns.py @@ -10,8 +10,8 @@ from fhir_types.hl7_fhir_r4_core.base import CodeableConcept, Period, Reference from fhir_types.profile_helpers import ( apply_slice_match, build_resource, ensure_profile, ensure_slice_defaults, get_array_slice, matches_value, \ - set_array_slice, strip_match_keys, validate_choice_required, validate_enum, validate_must_support, validate_reference, \ - validate_required, validate_slice_cardinality + set_array_slice, strip_match_keys, validate_choice_prohibited, validate_choice_required, validate_enum, \ + validate_must_support, validate_reference, validate_required, validate_slice_cardinality ) @@ -143,6 +143,7 @@ def validate(self) -> dict[str, list[str]]: errors.extend(validate_required(self._resource, profile_name, "subject")) errors.extend(validate_reference(self._resource, profile_name, "subject", ["Patient"])) errors.extend(validate_choice_required(self._resource, profile_name, ["effectiveDateTime","effectivePeriod"])) + errors.extend(validate_choice_prohibited(self._resource, profile_name, ["effectiveTiming","effectiveInstant"])) errors.extend(validate_reference(self._resource, profile_name, "hasMember", ["MolecularSequence","QuestionnaireResponse","Observation"])) errors.extend(validate_reference(self._resource, profile_name, "derivedFrom", ["DocumentReference","ImagingStudy","Media","MolecularSequence","QuestionnaireResponse","Observation"])) warnings.extend(validate_enum(self._resource, profile_name, "category", ["social-history","vital-signs","imaging","laboratory","procedure","survey","exam","therapy","activity"])) diff --git a/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/extension_uscore_ethnicity_extension.py b/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/extension_uscore_ethnicity_extension.py index 45993ecb..56cecf3a 100644 --- a/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/extension_uscore_ethnicity_extension.py +++ b/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/extension_uscore_ethnicity_extension.py @@ -11,7 +11,7 @@ from fhir_types.profile_helpers import ( _get_key, apply_slice_match, build_resource, ensure_slice_defaults, get_array_slice, get_extension_value, \ is_extension, is_record, matches_value, push_extension, set_array_slice, strip_match_keys, unwrap_slice_choice, \ - validate_fixed_value, validate_required, validate_slice_cardinality, wrap_slice_choice + validate_fixed_value, validate_required, validate_slice_cardinality, validate_slice_fields, wrap_slice_choice ) @@ -215,7 +215,10 @@ def validate(self) -> dict[str, list[str]]: warnings: list[str] = [] errors.extend(validate_required(self._resource, profile_name, "extension")) errors.extend(validate_slice_cardinality(self._resource, profile_name, "extension", {"url":"ombCategory"}, "ombCategory", 0, 1)) + errors.extend(validate_slice_fields(self._resource, profile_name, "extension", {"url":"ombCategory"}, "ombCategory", ["value","valueCoding"])) + errors.extend(validate_slice_fields(self._resource, profile_name, "extension", {"url":"detailed"}, "detailed", ["value","valueCoding"])) errors.extend(validate_slice_cardinality(self._resource, profile_name, "extension", {"url":"text"}, "text", 1, 1)) + errors.extend(validate_slice_fields(self._resource, profile_name, "extension", {"url":"text"}, "text", ["value","valueString"])) errors.extend(validate_required(self._resource, profile_name, "url")) errors.extend(validate_fixed_value(self._resource, profile_name, "url", "http://hl7.org/fhir/us/core/StructureDefinition/us-core-ethnicity")) return {"errors": errors, "warnings": warnings} diff --git a/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/extension_uscore_individual_sex_extension.py b/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/extension_uscore_individual_sex_extension.py index b011b1df..877b7c5a 100644 --- a/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/extension_uscore_individual_sex_extension.py +++ b/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/extension_uscore_individual_sex_extension.py @@ -9,7 +9,7 @@ from fhir_types.hl7_fhir_r4_core.base import Extension from fhir_types.hl7_fhir_r4_core.base import Coding from fhir_types.profile_helpers import ( - build_resource, validate_choice_required, validate_fixed_value, validate_required + build_resource, validate_choice_prohibited, validate_choice_required, validate_fixed_value, validate_required ) @@ -68,5 +68,6 @@ def validate(self) -> dict[str, list[str]]: errors.extend(validate_required(self._resource, profile_name, "url")) errors.extend(validate_fixed_value(self._resource, profile_name, "url", "http://hl7.org/fhir/us/core/StructureDefinition/us-core-individual-sex")) errors.extend(validate_choice_required(self._resource, profile_name, ["valueCoding"])) + errors.extend(validate_choice_prohibited(self._resource, profile_name, ["valueBase64binary","valueBoolean","valueCanonical","valueCode","valueDate","valueDateTime","valueDecimal","valueId","valueInstant","valueInteger","valueMarkdown","valueOid","valuePositiveInt","valueString","valueTime","valueUnsignedInt","valueUri","valueUrl","valueUuid","valueAddress","valueAge","valueAnnotation","valueAttachment","valueCodeableConcept","valueContactPoint","valueCount","valueDistance","valueDuration","valueHumanName","valueIdentifier","valueMoney","valuePeriod","valueQuantity","valueRange","valueRatio","valueReference","valueSampledData","valueSignature","valueTiming","valueContactDetail","valueContributor","valueDataRequirement","valueExpression","valueParameterDefinition","valueRelatedArtifact","valueTriggerDefinition","valueUsageContext","valueDosage","valueMeta"])) return {"errors": errors, "warnings": warnings} diff --git a/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/extension_uscore_interpreter_needed_extension.py b/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/extension_uscore_interpreter_needed_extension.py index 9d9fdb47..b5a2e845 100644 --- a/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/extension_uscore_interpreter_needed_extension.py +++ b/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/extension_uscore_interpreter_needed_extension.py @@ -9,7 +9,7 @@ from fhir_types.hl7_fhir_r4_core.base import Extension from fhir_types.hl7_fhir_r4_core.base import Coding from fhir_types.profile_helpers import ( - build_resource, validate_choice_required, validate_fixed_value, validate_required + build_resource, validate_choice_prohibited, validate_choice_required, validate_fixed_value, validate_required ) @@ -68,5 +68,6 @@ def validate(self) -> dict[str, list[str]]: errors.extend(validate_required(self._resource, profile_name, "url")) errors.extend(validate_fixed_value(self._resource, profile_name, "url", "http://hl7.org/fhir/us/core/StructureDefinition/us-core-interpreter-needed")) errors.extend(validate_choice_required(self._resource, profile_name, ["valueCoding"])) + errors.extend(validate_choice_prohibited(self._resource, profile_name, ["valueBase64binary","valueBoolean","valueCanonical","valueCode","valueDate","valueDateTime","valueDecimal","valueId","valueInstant","valueInteger","valueMarkdown","valueOid","valuePositiveInt","valueString","valueTime","valueUnsignedInt","valueUri","valueUrl","valueUuid","valueAddress","valueAge","valueAnnotation","valueAttachment","valueCodeableConcept","valueContactPoint","valueCount","valueDistance","valueDuration","valueHumanName","valueIdentifier","valueMoney","valuePeriod","valueQuantity","valueRange","valueRatio","valueReference","valueSampledData","valueSignature","valueTiming","valueContactDetail","valueContributor","valueDataRequirement","valueExpression","valueParameterDefinition","valueRelatedArtifact","valueTriggerDefinition","valueUsageContext","valueDosage","valueMeta"])) return {"errors": errors, "warnings": warnings} diff --git a/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/extension_uscore_race_extension.py b/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/extension_uscore_race_extension.py index 06ee4abe..f4ebf38f 100644 --- a/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/extension_uscore_race_extension.py +++ b/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/extension_uscore_race_extension.py @@ -11,7 +11,7 @@ from fhir_types.profile_helpers import ( _get_key, apply_slice_match, build_resource, ensure_slice_defaults, get_array_slice, get_extension_value, \ is_extension, is_record, matches_value, push_extension, set_array_slice, strip_match_keys, unwrap_slice_choice, \ - validate_fixed_value, validate_required, validate_slice_cardinality, wrap_slice_choice + validate_fixed_value, validate_required, validate_slice_cardinality, validate_slice_fields, wrap_slice_choice ) @@ -218,7 +218,10 @@ def validate(self) -> dict[str, list[str]]: warnings: list[str] = [] errors.extend(validate_required(self._resource, profile_name, "extension")) errors.extend(validate_slice_cardinality(self._resource, profile_name, "extension", {"url":"ombCategory"}, "ombCategory", 0, 6)) + errors.extend(validate_slice_fields(self._resource, profile_name, "extension", {"url":"ombCategory"}, "ombCategory", ["value","valueCoding"])) + errors.extend(validate_slice_fields(self._resource, profile_name, "extension", {"url":"detailed"}, "detailed", ["value","valueCoding"])) errors.extend(validate_slice_cardinality(self._resource, profile_name, "extension", {"url":"text"}, "text", 1, 1)) + errors.extend(validate_slice_fields(self._resource, profile_name, "extension", {"url":"text"}, "text", ["value","valueString"])) errors.extend(validate_required(self._resource, profile_name, "url")) errors.extend(validate_fixed_value(self._resource, profile_name, "url", "http://hl7.org/fhir/us/core/StructureDefinition/us-core-race")) return {"errors": errors, "warnings": warnings} diff --git a/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/extension_uscore_tribal_affiliation_extension.py b/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/extension_uscore_tribal_affiliation_extension.py index fc418b50..79e71a28 100644 --- a/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/extension_uscore_tribal_affiliation_extension.py +++ b/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/extension_uscore_tribal_affiliation_extension.py @@ -11,7 +11,7 @@ from fhir_types.profile_helpers import ( _get_key, apply_slice_match, build_resource, ensure_slice_defaults, get_array_slice, get_extension_value, \ is_extension, is_record, matches_value, push_extension, set_array_slice, strip_match_keys, unwrap_slice_choice, \ - validate_fixed_value, validate_required, validate_slice_cardinality, wrap_slice_choice + validate_fixed_value, validate_required, validate_slice_cardinality, validate_slice_fields, wrap_slice_choice ) @@ -165,7 +165,9 @@ def validate(self) -> dict[str, list[str]]: warnings: list[str] = [] errors.extend(validate_required(self._resource, profile_name, "extension")) errors.extend(validate_slice_cardinality(self._resource, profile_name, "extension", {"url":"tribalAffiliation"}, "tribalAffiliation", 1, 1)) + errors.extend(validate_slice_fields(self._resource, profile_name, "extension", {"url":"tribalAffiliation"}, "tribalAffiliation", ["value","valueCodeableConcept"])) errors.extend(validate_slice_cardinality(self._resource, profile_name, "extension", {"url":"isEnrolled"}, "isEnrolled", 0, 1)) + errors.extend(validate_slice_fields(self._resource, profile_name, "extension", {"url":"isEnrolled"}, "isEnrolled", ["value","valueBoolean"])) errors.extend(validate_required(self._resource, profile_name, "url")) errors.extend(validate_fixed_value(self._resource, profile_name, "url", "http://hl7.org/fhir/us/core/StructureDefinition/us-core-tribal-affiliation")) return {"errors": errors, "warnings": warnings} diff --git a/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/observation_uscore_blood_pressure_profile.py b/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/observation_uscore_blood_pressure_profile.py index 6ee1c5ea..1bcc1413 100644 --- a/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/observation_uscore_blood_pressure_profile.py +++ b/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/observation_uscore_blood_pressure_profile.py @@ -13,8 +13,9 @@ from fhir_types.hl7_fhir_r4_core.observation import ObservationComponent from fhir_types.profile_helpers import ( apply_slice_match, build_resource, ensure_profile, ensure_slice_defaults, get_array_slice, matches_value, \ - set_array_slice, strip_match_keys, unwrap_slice_choice, validate_choice_required, validate_enum, validate_fixed_value, \ - validate_must_support, validate_reference, validate_required, validate_slice_cardinality, wrap_slice_choice + set_array_slice, strip_match_keys, unwrap_slice_choice, validate_choice_prohibited, validate_choice_required, \ + validate_enum, validate_fixed_value, validate_must_support, validate_reference, validate_required, validate_slice_cardinality, \ + validate_slice_fields, wrap_slice_choice ) @@ -393,10 +394,13 @@ def validate(self) -> dict[str, list[str]]: errors.extend(validate_required(self._resource, profile_name, "subject")) errors.extend(validate_reference(self._resource, profile_name, "subject", ["Patient"])) errors.extend(validate_choice_required(self._resource, profile_name, ["effectiveDateTime","effectivePeriod"])) + errors.extend(validate_choice_prohibited(self._resource, profile_name, ["effectiveTiming","effectiveInstant"])) errors.extend(validate_reference(self._resource, profile_name, "hasMember", ["MolecularSequence","QuestionnaireResponse","Observation"])) errors.extend(validate_reference(self._resource, profile_name, "derivedFrom", ["DocumentReference","ImagingStudy","Media","MolecularSequence","QuestionnaireResponse","Observation"])) errors.extend(validate_slice_cardinality(self._resource, profile_name, "component", {"code":{"coding":[{"system":"http://loinc.org","code":"8480-6"}]}}, "systolic", 1, 1)) + errors.extend(validate_slice_fields(self._resource, profile_name, "component", {"code":{"coding":[{"system":"http://loinc.org","code":"8480-6"}]}}, "systolic", ["valueQuantity"])) errors.extend(validate_slice_cardinality(self._resource, profile_name, "component", {"code":{"coding":[{"system":"http://loinc.org","code":"8462-4"}]}}, "diastolic", 1, 1)) + errors.extend(validate_slice_fields(self._resource, profile_name, "component", {"code":{"coding":[{"system":"http://loinc.org","code":"8462-4"}]}}, "diastolic", ["valueQuantity"])) errors.extend(validate_reference(self._resource, profile_name, "performer", ["PractitionerRole","CareTeam","Organization","Patient","Practitioner","RelatedPerson"])) warnings.extend(validate_enum(self._resource, profile_name, "category", ["social-history","vital-signs","imaging","laboratory","procedure","survey","exam","therapy","activity"])) warnings.extend(validate_enum(self._resource, profile_name, "code", ["2708-6","29463-7","3140-1","3150-0","3151-8","39156-5","59408-5","59575-1","59576-9","77606-2","8287-5","8289-1","8302-2","8306-3","8310-5","8462-4","8478-0","8480-6","8867-4","9279-1","9843-4"])) diff --git a/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/observation_uscore_body_weight_profile.py b/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/observation_uscore_body_weight_profile.py index 00254658..58258b84 100644 --- a/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/observation_uscore_body_weight_profile.py +++ b/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/observation_uscore_body_weight_profile.py @@ -12,8 +12,8 @@ ) from fhir_types.profile_helpers import ( apply_slice_match, build_resource, ensure_profile, ensure_slice_defaults, get_array_slice, matches_value, \ - set_array_slice, strip_match_keys, validate_choice_required, validate_enum, validate_excluded, validate_fixed_value, \ - validate_must_support, validate_reference, validate_required, validate_slice_cardinality + set_array_slice, strip_match_keys, validate_choice_prohibited, validate_choice_required, validate_enum, \ + validate_fixed_value, validate_must_support, validate_reference, validate_required, validate_slice_cardinality ) @@ -223,19 +223,11 @@ def validate(self) -> dict[str, list[str]]: errors.extend(validate_required(self._resource, profile_name, "subject")) errors.extend(validate_reference(self._resource, profile_name, "subject", ["Patient"])) errors.extend(validate_choice_required(self._resource, profile_name, ["effectiveDateTime","effectivePeriod"])) + errors.extend(validate_choice_prohibited(self._resource, profile_name, ["effectiveTiming","effectiveInstant"])) errors.extend(validate_reference(self._resource, profile_name, "hasMember", ["MolecularSequence","QuestionnaireResponse","Observation"])) errors.extend(validate_reference(self._resource, profile_name, "derivedFrom", ["DocumentReference","ImagingStudy","Media","MolecularSequence","QuestionnaireResponse","Observation"])) errors.extend(validate_reference(self._resource, profile_name, "performer", ["PractitionerRole","CareTeam","Organization","Patient","Practitioner","RelatedPerson"])) - errors.extend(validate_excluded(self._resource, profile_name, "valueCodeableConcept")) - errors.extend(validate_excluded(self._resource, profile_name, "valueString")) - errors.extend(validate_excluded(self._resource, profile_name, "valueBoolean")) - errors.extend(validate_excluded(self._resource, profile_name, "valueInteger")) - errors.extend(validate_excluded(self._resource, profile_name, "valueRange")) - errors.extend(validate_excluded(self._resource, profile_name, "valueRatio")) - errors.extend(validate_excluded(self._resource, profile_name, "valueSampledData")) - errors.extend(validate_excluded(self._resource, profile_name, "valueTime")) - errors.extend(validate_excluded(self._resource, profile_name, "valueDateTime")) - errors.extend(validate_excluded(self._resource, profile_name, "valuePeriod")) + errors.extend(validate_choice_prohibited(self._resource, profile_name, ["valueCodeableConcept","valueString","valueBoolean","valueInteger","valueRange","valueRatio","valueSampledData","valueTime","valueDateTime","valuePeriod"])) warnings.extend(validate_enum(self._resource, profile_name, "category", ["social-history","vital-signs","imaging","laboratory","procedure","survey","exam","therapy","activity"])) warnings.extend(validate_enum(self._resource, profile_name, "code", ["2708-6","29463-7","3140-1","3150-0","3151-8","39156-5","59408-5","59575-1","59576-9","77606-2","8287-5","8289-1","8302-2","8306-3","8310-5","8462-4","8478-0","8480-6","8867-4","9279-1","9843-4"])) warnings.extend(validate_enum(self._resource, profile_name, "dataAbsentReason", ["unknown","asked-unknown","temp-unknown","not-asked","asked-declined","masked","not-applicable","unsupported","as-text","error","not-a-number","negative-infinity","positive-infinity","not-performed","not-permitted"])) diff --git a/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/observation_uscore_vital_signs_profile.py b/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/observation_uscore_vital_signs_profile.py index bbbbb9e3..2d4177fb 100644 --- a/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/observation_uscore_vital_signs_profile.py +++ b/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/observation_uscore_vital_signs_profile.py @@ -12,8 +12,8 @@ ) from fhir_types.profile_helpers import ( apply_slice_match, build_resource, ensure_profile, ensure_slice_defaults, get_array_slice, matches_value, \ - set_array_slice, strip_match_keys, validate_choice_required, validate_enum, validate_must_support, validate_reference, \ - validate_required, validate_slice_cardinality + set_array_slice, strip_match_keys, validate_choice_prohibited, validate_choice_required, validate_enum, \ + validate_must_support, validate_reference, validate_required, validate_slice_cardinality ) @@ -332,6 +332,7 @@ def validate(self) -> dict[str, list[str]]: errors.extend(validate_required(self._resource, profile_name, "subject")) errors.extend(validate_reference(self._resource, profile_name, "subject", ["Patient"])) errors.extend(validate_choice_required(self._resource, profile_name, ["effectiveDateTime","effectivePeriod"])) + errors.extend(validate_choice_prohibited(self._resource, profile_name, ["effectiveTiming","effectiveInstant"])) errors.extend(validate_reference(self._resource, profile_name, "hasMember", ["MolecularSequence","QuestionnaireResponse","Observation"])) errors.extend(validate_reference(self._resource, profile_name, "derivedFrom", ["DocumentReference","ImagingStudy","Media","MolecularSequence","QuestionnaireResponse","Observation"])) errors.extend(validate_reference(self._resource, profile_name, "performer", ["PractitionerRole","CareTeam","Organization","Patient","Practitioner","RelatedPerson"])) diff --git a/examples/python-r4-us-core/fhir_types/profile_helpers.py b/examples/python-r4-us-core/fhir_types/profile_helpers.py index 0cc130a2..f3146147 100644 --- a/examples/python-r4-us-core/fhir_types/profile_helpers.py +++ b/examples/python-r4-us-core/fhir_types/profile_helpers.py @@ -444,6 +444,29 @@ def validate_slice_cardinality( return errors +def validate_slice_fields( + res: object, + profile_name: str, + field: str, + match: Mapping[str, Any], + slice_name: str, + required_fields: Sequence[str], +) -> list[str]: + """Validates required fields within matched slice elements. For each array + item matching the discriminator, checks that the listed fields are present.""" + items = _get_field(res, field) or [] + if not isinstance(items, Iterable): + items = [] + errors: list[str] = [] + for item in items: + if not matches_value(item, match): + continue + for rf in required_fields: + if _get_field(item, rf) is None: + errors.append(f"{profile_name}.{field}[{slice_name}].{rf} is required") + return errors + + def validate_choice_required(res: object, profile_name: str, choices: Sequence[str]) -> list[str]: """Checks that at least one of the listed choice-type variants is present.""" if any(_get_field(res, c) is not None for c in choices): @@ -451,6 +474,17 @@ def validate_choice_required(res: object, profile_name: str, choices: Sequence[s return [f"{profile_name}: at least one of {', '.join(choices)} is required"] +def validate_choice_prohibited(res: object, profile_name: str, prohibited: Sequence[str]) -> list[str]: + """Checks that none of the listed prohibited choice-type variants is present. + E.g. a profile narrowing ``value[x]`` to ``value_quantity`` prohibits every + other variant.""" + return [ + f"{profile_name}: field '{c}' must not be present" + for c in prohibited + if _get_field(res, c) is not None + ] + + def validate_enum(res: object, profile_name: str, field: str, allowed: Sequence[str]) -> list[str]: """Checks that the value of ``field`` has a code within ``allowed``. Handles plain strings, Coding, and CodeableConcept.""" diff --git a/examples/python-r4-us-core/test_profile_bp.py b/examples/python-r4-us-core/test_profile_bp.py index 4b4f337f..25e094cb 100644 --- a/examples/python-r4-us-core/test_profile_bp.py +++ b/examples/python-r4-us-core/test_profile_bp.py @@ -116,6 +116,8 @@ def test_freshly_created_profile_is_not_yet_valid_missing_effective() -> None: errors = profile.validate()["errors"] assert errors == [ "UscoreBloodPressureProfile: at least one of effectiveDateTime, effectivePeriod is required", + "UscoreBloodPressureProfile.component[systolic].valueQuantity is required", + "UscoreBloodPressureProfile.component[diastolic].valueQuantity is required", ] From f3c75aed63b6a020f54daf3ad84fdc576fa09d99 Mon Sep 17 00:00:00 2001 From: Aleksandr Penskoi Date: Fri, 24 Jul 2026 16:15:14 +0400 Subject: [PATCH 08/16] ref: split validate_choice_prohibited variant list across lines --- .../python/profile-validation.ts | 4 +- .../__snapshots__/python.test.ts.snap | 59 ++++++++++++++++--- 2 files changed, 55 insertions(+), 8 deletions(-) diff --git a/src/api/writer-generator/python/profile-validation.ts b/src/api/writer-generator/python/profile-validation.ts index b3ac1087..e73c5811 100644 --- a/src/api/writer-generator/python/profile-validation.ts +++ b/src/api/writer-generator/python/profile-validation.ts @@ -39,7 +39,9 @@ export const collectValidateBody = ( helpers.add("validate_choice_prohibited"); const pyProhibited = field.prohibited.map((c) => pyFieldName(c, formatName)); errorLines.push( - `errors.extend(validate_choice_prohibited(self._resource, profile_name, ${JSON.stringify(pyProhibited)}))`, + "errors.extend(validate_choice_prohibited(self._resource, profile_name, [", + ...pyProhibited.map((c) => ` ${JSON.stringify(c)},`), + "]))", ); } continue; diff --git a/test/api/write-generator/__snapshots__/python.test.ts.snap b/test/api/write-generator/__snapshots__/python.test.ts.snap index bc617f0a..c98f6f76 100644 --- a/test/api/write-generator/__snapshots__/python.test.ts.snap +++ b/test/api/write-generator/__snapshots__/python.test.ts.snap @@ -564,10 +564,24 @@ class ObservationBodyweightProfile: errors.extend(validate_required(self._resource, profile_name, "subject")) errors.extend(validate_reference(self._resource, profile_name, "subject", ["Patient"])) errors.extend(validate_choice_required(self._resource, profile_name, ["effectiveDateTime","effectivePeriod"])) - errors.extend(validate_choice_prohibited(self._resource, profile_name, ["effectiveTiming","effectiveInstant"])) + errors.extend(validate_choice_prohibited(self._resource, profile_name, [ + "effectiveTiming", + "effectiveInstant", + ])) errors.extend(validate_reference(self._resource, profile_name, "hasMember", ["MolecularSequence","QuestionnaireResponse","Observation"])) errors.extend(validate_reference(self._resource, profile_name, "derivedFrom", ["DocumentReference","ImagingStudy","Media","MolecularSequence","QuestionnaireResponse","Observation"])) - errors.extend(validate_choice_prohibited(self._resource, profile_name, ["valueCodeableConcept","valueString","valueBoolean","valueInteger","valueRange","valueRatio","valueSampledData","valueTime","valueDateTime","valuePeriod"])) + errors.extend(validate_choice_prohibited(self._resource, profile_name, [ + "valueCodeableConcept", + "valueString", + "valueBoolean", + "valueInteger", + "valueRange", + "valueRatio", + "valueSampledData", + "valueTime", + "valueDateTime", + "valuePeriod", + ])) warnings.extend(validate_enum(self._resource, profile_name, "category", ["social-history","vital-signs","imaging","laboratory","procedure","survey","exam","therapy","activity"])) warnings.extend(validate_enum(self._resource, profile_name, "code", ["85353-1","9279-1","8867-4","2708-6","8310-5","8302-2","9843-4","29463-7","39156-5","85354-9","8480-6","8462-4","8478-0"])) warnings.extend(validate_enum(self._resource, profile_name, "dataAbsentReason", ["unknown","asked-unknown","temp-unknown","not-asked","asked-declined","masked","not-applicable","unsupported","as-text","error","not-a-number","negative-infinity","positive-infinity","not-performed","not-permitted"])) @@ -794,14 +808,28 @@ class ObservationBpProfile: errors.extend(validate_required(self._resource, profile_name, "subject")) errors.extend(validate_reference(self._resource, profile_name, "subject", ["Patient"])) errors.extend(validate_choice_required(self._resource, profile_name, ["effectiveDateTime","effectivePeriod"])) - errors.extend(validate_choice_prohibited(self._resource, profile_name, ["effectiveTiming","effectiveInstant"])) + errors.extend(validate_choice_prohibited(self._resource, profile_name, [ + "effectiveTiming", + "effectiveInstant", + ])) errors.extend(validate_reference(self._resource, profile_name, "hasMember", ["MolecularSequence","QuestionnaireResponse","Observation"])) errors.extend(validate_reference(self._resource, profile_name, "derivedFrom", ["DocumentReference","ImagingStudy","Media","MolecularSequence","QuestionnaireResponse","Observation"])) errors.extend(validate_slice_cardinality(self._resource, profile_name, "component", {"code":{"coding":[{"code":"8480-6","system":"http://loinc.org"}]}}, "SystolicBP", 1, 1)) errors.extend(validate_slice_fields(self._resource, profile_name, "component", {"code":{"coding":[{"code":"8480-6","system":"http://loinc.org"}]}}, "SystolicBP", ["valueQuantity"])) errors.extend(validate_slice_cardinality(self._resource, profile_name, "component", {"code":{"coding":[{"code":"8462-4","system":"http://loinc.org"}]}}, "DiastolicBP", 1, 1)) errors.extend(validate_slice_fields(self._resource, profile_name, "component", {"code":{"coding":[{"code":"8462-4","system":"http://loinc.org"}]}}, "DiastolicBP", ["valueQuantity"])) - errors.extend(validate_choice_prohibited(self._resource, profile_name, ["valueCodeableConcept","valueString","valueBoolean","valueInteger","valueRange","valueRatio","valueSampledData","valueTime","valueDateTime","valuePeriod"])) + errors.extend(validate_choice_prohibited(self._resource, profile_name, [ + "valueCodeableConcept", + "valueString", + "valueBoolean", + "valueInteger", + "valueRange", + "valueRatio", + "valueSampledData", + "valueTime", + "valueDateTime", + "valuePeriod", + ])) warnings.extend(validate_enum(self._resource, profile_name, "category", ["social-history","vital-signs","imaging","laboratory","procedure","survey","exam","therapy","activity"])) warnings.extend(validate_enum(self._resource, profile_name, "code", ["85353-1","9279-1","8867-4","2708-6","8310-5","8302-2","9843-4","29463-7","39156-5","85354-9","8480-6","8462-4","8478-0"])) warnings.extend(validate_enum(self._resource, profile_name, "dataAbsentReason", ["unknown","asked-unknown","temp-unknown","not-asked","asked-declined","masked","not-applicable","unsupported","as-text","error","not-a-number","negative-infinity","positive-infinity","not-performed","not-permitted"])) @@ -1475,7 +1503,10 @@ class UscoreBloodPressureProfile: errors.extend(validate_required(self._resource, profile_name, "subject")) errors.extend(validate_reference(self._resource, profile_name, "subject", ["Patient"])) errors.extend(validate_choice_required(self._resource, profile_name, ["effectiveDateTime","effectivePeriod"])) - errors.extend(validate_choice_prohibited(self._resource, profile_name, ["effectiveTiming","effectiveInstant"])) + errors.extend(validate_choice_prohibited(self._resource, profile_name, [ + "effectiveTiming", + "effectiveInstant", + ])) errors.extend(validate_reference(self._resource, profile_name, "hasMember", ["MolecularSequence","QuestionnaireResponse","Observation"])) errors.extend(validate_reference(self._resource, profile_name, "derivedFrom", ["DocumentReference","ImagingStudy","Media","MolecularSequence","QuestionnaireResponse","Observation"])) errors.extend(validate_slice_cardinality(self._resource, profile_name, "component", {"code":{"coding":[{"system":"http://loinc.org","code":"8480-6"}]}}, "systolic", 1, 1)) @@ -1719,11 +1750,25 @@ class UscoreBodyWeightProfile: errors.extend(validate_required(self._resource, profile_name, "subject")) errors.extend(validate_reference(self._resource, profile_name, "subject", ["Patient"])) errors.extend(validate_choice_required(self._resource, profile_name, ["effectiveDateTime","effectivePeriod"])) - errors.extend(validate_choice_prohibited(self._resource, profile_name, ["effectiveTiming","effectiveInstant"])) + errors.extend(validate_choice_prohibited(self._resource, profile_name, [ + "effectiveTiming", + "effectiveInstant", + ])) errors.extend(validate_reference(self._resource, profile_name, "hasMember", ["MolecularSequence","QuestionnaireResponse","Observation"])) errors.extend(validate_reference(self._resource, profile_name, "derivedFrom", ["DocumentReference","ImagingStudy","Media","MolecularSequence","QuestionnaireResponse","Observation"])) errors.extend(validate_reference(self._resource, profile_name, "performer", ["PractitionerRole","CareTeam","Organization","Patient","Practitioner","RelatedPerson"])) - errors.extend(validate_choice_prohibited(self._resource, profile_name, ["valueCodeableConcept","valueString","valueBoolean","valueInteger","valueRange","valueRatio","valueSampledData","valueTime","valueDateTime","valuePeriod"])) + errors.extend(validate_choice_prohibited(self._resource, profile_name, [ + "valueCodeableConcept", + "valueString", + "valueBoolean", + "valueInteger", + "valueRange", + "valueRatio", + "valueSampledData", + "valueTime", + "valueDateTime", + "valuePeriod", + ])) warnings.extend(validate_enum(self._resource, profile_name, "category", ["social-history","vital-signs","imaging","laboratory","procedure","survey","exam","therapy","activity"])) warnings.extend(validate_enum(self._resource, profile_name, "code", ["2708-6","29463-7","3140-1","3150-0","3151-8","39156-5","59408-5","59575-1","59576-9","77606-2","8287-5","8289-1","8302-2","8306-3","8310-5","8462-4","8478-0","8480-6","8867-4","9279-1","9843-4"])) warnings.extend(validate_enum(self._resource, profile_name, "dataAbsentReason", ["unknown","asked-unknown","temp-unknown","not-asked","asked-declined","masked","not-applicable","unsupported","as-text","error","not-a-number","negative-infinity","positive-infinity","not-performed","not-permitted"])) From ef710fdd8f0c5414db260b0a0ec45e8092c8697d Mon Sep 17 00:00:00 2001 From: Aleksandr Penskoi Date: Fri, 24 Jul 2026 16:15:14 +0400 Subject: [PATCH 09/16] chore(examples): regenerate python-r4-us-core with split prohibited variant lists --- .../profiles/extension_birth_place.py | 52 ++++++++++++++++++- .../profiles/extension_birth_time.py | 52 ++++++++++++++++++- .../profiles/extension_own_prefix.py | 52 ++++++++++++++++++- .../observation_observation_bodyweight.py | 18 ++++++- .../observation_observation_vitalsigns.py | 5 +- ...tension_uscore_individual_sex_extension.py | 52 ++++++++++++++++++- ...ion_uscore_interpreter_needed_extension.py | 52 ++++++++++++++++++- ...servation_uscore_blood_pressure_profile.py | 5 +- .../observation_uscore_body_weight_profile.py | 18 ++++++- .../observation_uscore_vital_signs_profile.py | 5 +- 10 files changed, 299 insertions(+), 12 deletions(-) diff --git a/examples/python-r4-us-core/fhir_types/hl7_fhir_r4_core/profiles/extension_birth_place.py b/examples/python-r4-us-core/fhir_types/hl7_fhir_r4_core/profiles/extension_birth_place.py index 4a1d2a74..0bce2d1e 100644 --- a/examples/python-r4-us-core/fhir_types/hl7_fhir_r4_core/profiles/extension_birth_place.py +++ b/examples/python-r4-us-core/fhir_types/hl7_fhir_r4_core/profiles/extension_birth_place.py @@ -68,6 +68,56 @@ def validate(self) -> dict[str, list[str]]: errors.extend(validate_required(self._resource, profile_name, "url")) errors.extend(validate_fixed_value(self._resource, profile_name, "url", "http://hl7.org/fhir/StructureDefinition/patient-birthPlace")) errors.extend(validate_choice_required(self._resource, profile_name, ["valueAddress"])) - errors.extend(validate_choice_prohibited(self._resource, profile_name, ["valueBase64binary","valueBoolean","valueCanonical","valueCode","valueDate","valueDateTime","valueDecimal","valueId","valueInstant","valueInteger","valueMarkdown","valueOid","valuePositiveInt","valueString","valueTime","valueUnsignedInt","valueUri","valueUrl","valueUuid","valueAge","valueAnnotation","valueAttachment","valueCodeableConcept","valueCoding","valueContactPoint","valueCount","valueDistance","valueDuration","valueHumanName","valueIdentifier","valueMoney","valuePeriod","valueQuantity","valueRange","valueRatio","valueReference","valueSampledData","valueSignature","valueTiming","valueContactDetail","valueContributor","valueDataRequirement","valueExpression","valueParameterDefinition","valueRelatedArtifact","valueTriggerDefinition","valueUsageContext","valueDosage","valueMeta"])) + errors.extend(validate_choice_prohibited(self._resource, profile_name, [ + "valueBase64binary", + "valueBoolean", + "valueCanonical", + "valueCode", + "valueDate", + "valueDateTime", + "valueDecimal", + "valueId", + "valueInstant", + "valueInteger", + "valueMarkdown", + "valueOid", + "valuePositiveInt", + "valueString", + "valueTime", + "valueUnsignedInt", + "valueUri", + "valueUrl", + "valueUuid", + "valueAge", + "valueAnnotation", + "valueAttachment", + "valueCodeableConcept", + "valueCoding", + "valueContactPoint", + "valueCount", + "valueDistance", + "valueDuration", + "valueHumanName", + "valueIdentifier", + "valueMoney", + "valuePeriod", + "valueQuantity", + "valueRange", + "valueRatio", + "valueReference", + "valueSampledData", + "valueSignature", + "valueTiming", + "valueContactDetail", + "valueContributor", + "valueDataRequirement", + "valueExpression", + "valueParameterDefinition", + "valueRelatedArtifact", + "valueTriggerDefinition", + "valueUsageContext", + "valueDosage", + "valueMeta", + ])) return {"errors": errors, "warnings": warnings} diff --git a/examples/python-r4-us-core/fhir_types/hl7_fhir_r4_core/profiles/extension_birth_time.py b/examples/python-r4-us-core/fhir_types/hl7_fhir_r4_core/profiles/extension_birth_time.py index 3734087b..388d111a 100644 --- a/examples/python-r4-us-core/fhir_types/hl7_fhir_r4_core/profiles/extension_birth_time.py +++ b/examples/python-r4-us-core/fhir_types/hl7_fhir_r4_core/profiles/extension_birth_time.py @@ -67,6 +67,56 @@ def validate(self) -> dict[str, list[str]]: errors.extend(validate_required(self._resource, profile_name, "url")) errors.extend(validate_fixed_value(self._resource, profile_name, "url", "http://hl7.org/fhir/StructureDefinition/patient-birthTime")) errors.extend(validate_choice_required(self._resource, profile_name, ["valueDateTime"])) - errors.extend(validate_choice_prohibited(self._resource, profile_name, ["valueBase64binary","valueBoolean","valueCanonical","valueCode","valueDate","valueDecimal","valueId","valueInstant","valueInteger","valueMarkdown","valueOid","valuePositiveInt","valueString","valueTime","valueUnsignedInt","valueUri","valueUrl","valueUuid","valueAddress","valueAge","valueAnnotation","valueAttachment","valueCodeableConcept","valueCoding","valueContactPoint","valueCount","valueDistance","valueDuration","valueHumanName","valueIdentifier","valueMoney","valuePeriod","valueQuantity","valueRange","valueRatio","valueReference","valueSampledData","valueSignature","valueTiming","valueContactDetail","valueContributor","valueDataRequirement","valueExpression","valueParameterDefinition","valueRelatedArtifact","valueTriggerDefinition","valueUsageContext","valueDosage","valueMeta"])) + errors.extend(validate_choice_prohibited(self._resource, profile_name, [ + "valueBase64binary", + "valueBoolean", + "valueCanonical", + "valueCode", + "valueDate", + "valueDecimal", + "valueId", + "valueInstant", + "valueInteger", + "valueMarkdown", + "valueOid", + "valuePositiveInt", + "valueString", + "valueTime", + "valueUnsignedInt", + "valueUri", + "valueUrl", + "valueUuid", + "valueAddress", + "valueAge", + "valueAnnotation", + "valueAttachment", + "valueCodeableConcept", + "valueCoding", + "valueContactPoint", + "valueCount", + "valueDistance", + "valueDuration", + "valueHumanName", + "valueIdentifier", + "valueMoney", + "valuePeriod", + "valueQuantity", + "valueRange", + "valueRatio", + "valueReference", + "valueSampledData", + "valueSignature", + "valueTiming", + "valueContactDetail", + "valueContributor", + "valueDataRequirement", + "valueExpression", + "valueParameterDefinition", + "valueRelatedArtifact", + "valueTriggerDefinition", + "valueUsageContext", + "valueDosage", + "valueMeta", + ])) return {"errors": errors, "warnings": warnings} diff --git a/examples/python-r4-us-core/fhir_types/hl7_fhir_r4_core/profiles/extension_own_prefix.py b/examples/python-r4-us-core/fhir_types/hl7_fhir_r4_core/profiles/extension_own_prefix.py index 207c26ba..8fc724ea 100644 --- a/examples/python-r4-us-core/fhir_types/hl7_fhir_r4_core/profiles/extension_own_prefix.py +++ b/examples/python-r4-us-core/fhir_types/hl7_fhir_r4_core/profiles/extension_own_prefix.py @@ -67,6 +67,56 @@ def validate(self) -> dict[str, list[str]]: errors.extend(validate_required(self._resource, profile_name, "url")) errors.extend(validate_fixed_value(self._resource, profile_name, "url", "http://hl7.org/fhir/StructureDefinition/humanname-own-prefix")) errors.extend(validate_choice_required(self._resource, profile_name, ["valueString"])) - errors.extend(validate_choice_prohibited(self._resource, profile_name, ["valueBase64binary","valueBoolean","valueCanonical","valueCode","valueDate","valueDateTime","valueDecimal","valueId","valueInstant","valueInteger","valueMarkdown","valueOid","valuePositiveInt","valueTime","valueUnsignedInt","valueUri","valueUrl","valueUuid","valueAddress","valueAge","valueAnnotation","valueAttachment","valueCodeableConcept","valueCoding","valueContactPoint","valueCount","valueDistance","valueDuration","valueHumanName","valueIdentifier","valueMoney","valuePeriod","valueQuantity","valueRange","valueRatio","valueReference","valueSampledData","valueSignature","valueTiming","valueContactDetail","valueContributor","valueDataRequirement","valueExpression","valueParameterDefinition","valueRelatedArtifact","valueTriggerDefinition","valueUsageContext","valueDosage","valueMeta"])) + errors.extend(validate_choice_prohibited(self._resource, profile_name, [ + "valueBase64binary", + "valueBoolean", + "valueCanonical", + "valueCode", + "valueDate", + "valueDateTime", + "valueDecimal", + "valueId", + "valueInstant", + "valueInteger", + "valueMarkdown", + "valueOid", + "valuePositiveInt", + "valueTime", + "valueUnsignedInt", + "valueUri", + "valueUrl", + "valueUuid", + "valueAddress", + "valueAge", + "valueAnnotation", + "valueAttachment", + "valueCodeableConcept", + "valueCoding", + "valueContactPoint", + "valueCount", + "valueDistance", + "valueDuration", + "valueHumanName", + "valueIdentifier", + "valueMoney", + "valuePeriod", + "valueQuantity", + "valueRange", + "valueRatio", + "valueReference", + "valueSampledData", + "valueSignature", + "valueTiming", + "valueContactDetail", + "valueContributor", + "valueDataRequirement", + "valueExpression", + "valueParameterDefinition", + "valueRelatedArtifact", + "valueTriggerDefinition", + "valueUsageContext", + "valueDosage", + "valueMeta", + ])) return {"errors": errors, "warnings": warnings} diff --git a/examples/python-r4-us-core/fhir_types/hl7_fhir_r4_core/profiles/observation_observation_bodyweight.py b/examples/python-r4-us-core/fhir_types/hl7_fhir_r4_core/profiles/observation_observation_bodyweight.py index 4712df61..9f19e59d 100644 --- a/examples/python-r4-us-core/fhir_types/hl7_fhir_r4_core/profiles/observation_observation_bodyweight.py +++ b/examples/python-r4-us-core/fhir_types/hl7_fhir_r4_core/profiles/observation_observation_bodyweight.py @@ -151,10 +151,24 @@ def validate(self) -> dict[str, list[str]]: errors.extend(validate_required(self._resource, profile_name, "subject")) errors.extend(validate_reference(self._resource, profile_name, "subject", ["Patient"])) errors.extend(validate_choice_required(self._resource, profile_name, ["effectiveDateTime","effectivePeriod"])) - errors.extend(validate_choice_prohibited(self._resource, profile_name, ["effectiveTiming","effectiveInstant"])) + errors.extend(validate_choice_prohibited(self._resource, profile_name, [ + "effectiveTiming", + "effectiveInstant", + ])) errors.extend(validate_reference(self._resource, profile_name, "hasMember", ["MolecularSequence","QuestionnaireResponse","Observation"])) errors.extend(validate_reference(self._resource, profile_name, "derivedFrom", ["DocumentReference","ImagingStudy","Media","MolecularSequence","QuestionnaireResponse","Observation"])) - errors.extend(validate_choice_prohibited(self._resource, profile_name, ["valueCodeableConcept","valueString","valueBoolean","valueInteger","valueRange","valueRatio","valueSampledData","valueTime","valueDateTime","valuePeriod"])) + errors.extend(validate_choice_prohibited(self._resource, profile_name, [ + "valueCodeableConcept", + "valueString", + "valueBoolean", + "valueInteger", + "valueRange", + "valueRatio", + "valueSampledData", + "valueTime", + "valueDateTime", + "valuePeriod", + ])) warnings.extend(validate_enum(self._resource, profile_name, "category", ["social-history","vital-signs","imaging","laboratory","procedure","survey","exam","therapy","activity"])) warnings.extend(validate_enum(self._resource, profile_name, "code", ["85353-1","9279-1","8867-4","2708-6","8310-5","8302-2","9843-4","29463-7","39156-5","85354-9","8480-6","8462-4","8478-0"])) warnings.extend(validate_enum(self._resource, profile_name, "dataAbsentReason", ["unknown","asked-unknown","temp-unknown","not-asked","asked-declined","masked","not-applicable","unsupported","as-text","error","not-a-number","negative-infinity","positive-infinity","not-performed","not-permitted"])) diff --git a/examples/python-r4-us-core/fhir_types/hl7_fhir_r4_core/profiles/observation_observation_vitalsigns.py b/examples/python-r4-us-core/fhir_types/hl7_fhir_r4_core/profiles/observation_observation_vitalsigns.py index 7b0b4aee..a8e33e93 100644 --- a/examples/python-r4-us-core/fhir_types/hl7_fhir_r4_core/profiles/observation_observation_vitalsigns.py +++ b/examples/python-r4-us-core/fhir_types/hl7_fhir_r4_core/profiles/observation_observation_vitalsigns.py @@ -143,7 +143,10 @@ def validate(self) -> dict[str, list[str]]: errors.extend(validate_required(self._resource, profile_name, "subject")) errors.extend(validate_reference(self._resource, profile_name, "subject", ["Patient"])) errors.extend(validate_choice_required(self._resource, profile_name, ["effectiveDateTime","effectivePeriod"])) - errors.extend(validate_choice_prohibited(self._resource, profile_name, ["effectiveTiming","effectiveInstant"])) + errors.extend(validate_choice_prohibited(self._resource, profile_name, [ + "effectiveTiming", + "effectiveInstant", + ])) errors.extend(validate_reference(self._resource, profile_name, "hasMember", ["MolecularSequence","QuestionnaireResponse","Observation"])) errors.extend(validate_reference(self._resource, profile_name, "derivedFrom", ["DocumentReference","ImagingStudy","Media","MolecularSequence","QuestionnaireResponse","Observation"])) warnings.extend(validate_enum(self._resource, profile_name, "category", ["social-history","vital-signs","imaging","laboratory","procedure","survey","exam","therapy","activity"])) diff --git a/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/extension_uscore_individual_sex_extension.py b/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/extension_uscore_individual_sex_extension.py index 877b7c5a..8f88b5f9 100644 --- a/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/extension_uscore_individual_sex_extension.py +++ b/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/extension_uscore_individual_sex_extension.py @@ -68,6 +68,56 @@ def validate(self) -> dict[str, list[str]]: errors.extend(validate_required(self._resource, profile_name, "url")) errors.extend(validate_fixed_value(self._resource, profile_name, "url", "http://hl7.org/fhir/us/core/StructureDefinition/us-core-individual-sex")) errors.extend(validate_choice_required(self._resource, profile_name, ["valueCoding"])) - errors.extend(validate_choice_prohibited(self._resource, profile_name, ["valueBase64binary","valueBoolean","valueCanonical","valueCode","valueDate","valueDateTime","valueDecimal","valueId","valueInstant","valueInteger","valueMarkdown","valueOid","valuePositiveInt","valueString","valueTime","valueUnsignedInt","valueUri","valueUrl","valueUuid","valueAddress","valueAge","valueAnnotation","valueAttachment","valueCodeableConcept","valueContactPoint","valueCount","valueDistance","valueDuration","valueHumanName","valueIdentifier","valueMoney","valuePeriod","valueQuantity","valueRange","valueRatio","valueReference","valueSampledData","valueSignature","valueTiming","valueContactDetail","valueContributor","valueDataRequirement","valueExpression","valueParameterDefinition","valueRelatedArtifact","valueTriggerDefinition","valueUsageContext","valueDosage","valueMeta"])) + errors.extend(validate_choice_prohibited(self._resource, profile_name, [ + "valueBase64binary", + "valueBoolean", + "valueCanonical", + "valueCode", + "valueDate", + "valueDateTime", + "valueDecimal", + "valueId", + "valueInstant", + "valueInteger", + "valueMarkdown", + "valueOid", + "valuePositiveInt", + "valueString", + "valueTime", + "valueUnsignedInt", + "valueUri", + "valueUrl", + "valueUuid", + "valueAddress", + "valueAge", + "valueAnnotation", + "valueAttachment", + "valueCodeableConcept", + "valueContactPoint", + "valueCount", + "valueDistance", + "valueDuration", + "valueHumanName", + "valueIdentifier", + "valueMoney", + "valuePeriod", + "valueQuantity", + "valueRange", + "valueRatio", + "valueReference", + "valueSampledData", + "valueSignature", + "valueTiming", + "valueContactDetail", + "valueContributor", + "valueDataRequirement", + "valueExpression", + "valueParameterDefinition", + "valueRelatedArtifact", + "valueTriggerDefinition", + "valueUsageContext", + "valueDosage", + "valueMeta", + ])) return {"errors": errors, "warnings": warnings} diff --git a/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/extension_uscore_interpreter_needed_extension.py b/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/extension_uscore_interpreter_needed_extension.py index b5a2e845..c4200c20 100644 --- a/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/extension_uscore_interpreter_needed_extension.py +++ b/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/extension_uscore_interpreter_needed_extension.py @@ -68,6 +68,56 @@ def validate(self) -> dict[str, list[str]]: errors.extend(validate_required(self._resource, profile_name, "url")) errors.extend(validate_fixed_value(self._resource, profile_name, "url", "http://hl7.org/fhir/us/core/StructureDefinition/us-core-interpreter-needed")) errors.extend(validate_choice_required(self._resource, profile_name, ["valueCoding"])) - errors.extend(validate_choice_prohibited(self._resource, profile_name, ["valueBase64binary","valueBoolean","valueCanonical","valueCode","valueDate","valueDateTime","valueDecimal","valueId","valueInstant","valueInteger","valueMarkdown","valueOid","valuePositiveInt","valueString","valueTime","valueUnsignedInt","valueUri","valueUrl","valueUuid","valueAddress","valueAge","valueAnnotation","valueAttachment","valueCodeableConcept","valueContactPoint","valueCount","valueDistance","valueDuration","valueHumanName","valueIdentifier","valueMoney","valuePeriod","valueQuantity","valueRange","valueRatio","valueReference","valueSampledData","valueSignature","valueTiming","valueContactDetail","valueContributor","valueDataRequirement","valueExpression","valueParameterDefinition","valueRelatedArtifact","valueTriggerDefinition","valueUsageContext","valueDosage","valueMeta"])) + errors.extend(validate_choice_prohibited(self._resource, profile_name, [ + "valueBase64binary", + "valueBoolean", + "valueCanonical", + "valueCode", + "valueDate", + "valueDateTime", + "valueDecimal", + "valueId", + "valueInstant", + "valueInteger", + "valueMarkdown", + "valueOid", + "valuePositiveInt", + "valueString", + "valueTime", + "valueUnsignedInt", + "valueUri", + "valueUrl", + "valueUuid", + "valueAddress", + "valueAge", + "valueAnnotation", + "valueAttachment", + "valueCodeableConcept", + "valueContactPoint", + "valueCount", + "valueDistance", + "valueDuration", + "valueHumanName", + "valueIdentifier", + "valueMoney", + "valuePeriod", + "valueQuantity", + "valueRange", + "valueRatio", + "valueReference", + "valueSampledData", + "valueSignature", + "valueTiming", + "valueContactDetail", + "valueContributor", + "valueDataRequirement", + "valueExpression", + "valueParameterDefinition", + "valueRelatedArtifact", + "valueTriggerDefinition", + "valueUsageContext", + "valueDosage", + "valueMeta", + ])) return {"errors": errors, "warnings": warnings} diff --git a/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/observation_uscore_blood_pressure_profile.py b/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/observation_uscore_blood_pressure_profile.py index 1bcc1413..ab903514 100644 --- a/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/observation_uscore_blood_pressure_profile.py +++ b/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/observation_uscore_blood_pressure_profile.py @@ -394,7 +394,10 @@ def validate(self) -> dict[str, list[str]]: errors.extend(validate_required(self._resource, profile_name, "subject")) errors.extend(validate_reference(self._resource, profile_name, "subject", ["Patient"])) errors.extend(validate_choice_required(self._resource, profile_name, ["effectiveDateTime","effectivePeriod"])) - errors.extend(validate_choice_prohibited(self._resource, profile_name, ["effectiveTiming","effectiveInstant"])) + errors.extend(validate_choice_prohibited(self._resource, profile_name, [ + "effectiveTiming", + "effectiveInstant", + ])) errors.extend(validate_reference(self._resource, profile_name, "hasMember", ["MolecularSequence","QuestionnaireResponse","Observation"])) errors.extend(validate_reference(self._resource, profile_name, "derivedFrom", ["DocumentReference","ImagingStudy","Media","MolecularSequence","QuestionnaireResponse","Observation"])) errors.extend(validate_slice_cardinality(self._resource, profile_name, "component", {"code":{"coding":[{"system":"http://loinc.org","code":"8480-6"}]}}, "systolic", 1, 1)) diff --git a/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/observation_uscore_body_weight_profile.py b/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/observation_uscore_body_weight_profile.py index 58258b84..ad926641 100644 --- a/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/observation_uscore_body_weight_profile.py +++ b/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/observation_uscore_body_weight_profile.py @@ -223,11 +223,25 @@ def validate(self) -> dict[str, list[str]]: errors.extend(validate_required(self._resource, profile_name, "subject")) errors.extend(validate_reference(self._resource, profile_name, "subject", ["Patient"])) errors.extend(validate_choice_required(self._resource, profile_name, ["effectiveDateTime","effectivePeriod"])) - errors.extend(validate_choice_prohibited(self._resource, profile_name, ["effectiveTiming","effectiveInstant"])) + errors.extend(validate_choice_prohibited(self._resource, profile_name, [ + "effectiveTiming", + "effectiveInstant", + ])) errors.extend(validate_reference(self._resource, profile_name, "hasMember", ["MolecularSequence","QuestionnaireResponse","Observation"])) errors.extend(validate_reference(self._resource, profile_name, "derivedFrom", ["DocumentReference","ImagingStudy","Media","MolecularSequence","QuestionnaireResponse","Observation"])) errors.extend(validate_reference(self._resource, profile_name, "performer", ["PractitionerRole","CareTeam","Organization","Patient","Practitioner","RelatedPerson"])) - errors.extend(validate_choice_prohibited(self._resource, profile_name, ["valueCodeableConcept","valueString","valueBoolean","valueInteger","valueRange","valueRatio","valueSampledData","valueTime","valueDateTime","valuePeriod"])) + errors.extend(validate_choice_prohibited(self._resource, profile_name, [ + "valueCodeableConcept", + "valueString", + "valueBoolean", + "valueInteger", + "valueRange", + "valueRatio", + "valueSampledData", + "valueTime", + "valueDateTime", + "valuePeriod", + ])) warnings.extend(validate_enum(self._resource, profile_name, "category", ["social-history","vital-signs","imaging","laboratory","procedure","survey","exam","therapy","activity"])) warnings.extend(validate_enum(self._resource, profile_name, "code", ["2708-6","29463-7","3140-1","3150-0","3151-8","39156-5","59408-5","59575-1","59576-9","77606-2","8287-5","8289-1","8302-2","8306-3","8310-5","8462-4","8478-0","8480-6","8867-4","9279-1","9843-4"])) warnings.extend(validate_enum(self._resource, profile_name, "dataAbsentReason", ["unknown","asked-unknown","temp-unknown","not-asked","asked-declined","masked","not-applicable","unsupported","as-text","error","not-a-number","negative-infinity","positive-infinity","not-performed","not-permitted"])) diff --git a/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/observation_uscore_vital_signs_profile.py b/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/observation_uscore_vital_signs_profile.py index 2d4177fb..9b8979b6 100644 --- a/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/observation_uscore_vital_signs_profile.py +++ b/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/observation_uscore_vital_signs_profile.py @@ -332,7 +332,10 @@ def validate(self) -> dict[str, list[str]]: errors.extend(validate_required(self._resource, profile_name, "subject")) errors.extend(validate_reference(self._resource, profile_name, "subject", ["Patient"])) errors.extend(validate_choice_required(self._resource, profile_name, ["effectiveDateTime","effectivePeriod"])) - errors.extend(validate_choice_prohibited(self._resource, profile_name, ["effectiveTiming","effectiveInstant"])) + errors.extend(validate_choice_prohibited(self._resource, profile_name, [ + "effectiveTiming", + "effectiveInstant", + ])) errors.extend(validate_reference(self._resource, profile_name, "hasMember", ["MolecularSequence","QuestionnaireResponse","Observation"])) errors.extend(validate_reference(self._resource, profile_name, "derivedFrom", ["DocumentReference","ImagingStudy","Media","MolecularSequence","QuestionnaireResponse","Observation"])) errors.extend(validate_reference(self._resource, profile_name, "performer", ["PractitionerRole","CareTeam","Organization","Patient","Practitioner","RelatedPerson"])) From d5ce82a7fa0990188cd61790138cefde95c705bf Mon Sep 17 00:00:00 2001 From: Aleksandr Penskoi Date: Fri, 24 Jul 2026 16:24:21 +0400 Subject: [PATCH 10/16] ref: wrap list-carrying validation calls via shared pushListValidation Emit errors.extend(/validate_xxx(..., [/items/])) across four lines for validate_choice_required, validate_choice_prohibited, validate_enum, validate_reference, and validate_slice_fields; list items stay on one line. --- .../python/profile-validation.ts | 44 +-- .../__snapshots__/python.test.ts.snap | 271 ++++++++++++------ 2 files changed, 213 insertions(+), 102 deletions(-) diff --git a/src/api/writer-generator/python/profile-validation.ts b/src/api/writer-generator/python/profile-validation.ts index e73c5811..d00e5885 100644 --- a/src/api/writer-generator/python/profile-validation.ts +++ b/src/api/writer-generator/python/profile-validation.ts @@ -13,6 +13,24 @@ import { pyFieldName } from "./profile-naming"; // Validation body collection // --------------------------------------------------------------------------- +/** Emit `.extend((self._resource, profile_name, , []))` + * with the call and its trailing list argument split across lines: + * + * errors.extend( + * validate_enum(self._resource, profile_name, "code", [ + * "85353-1","9279-1",... + * ])) + */ +const pushListValidation = (lines: string[], target: string, fn: string, args: string[], items: string[]): void => { + const argList = ["self._resource", "profile_name", ...args].join(", "); + lines.push( + `${target}.extend(`, + ` ${fn}(${argList}, [`, + ` ${items.map((i) => JSON.stringify(i)).join(",")}`, + "]))", + ); +}; + /** Walk fields once and emit validate() body lines into `out`, returning the * set of helper function names referenced. Pure: no writer side effects. */ export const collectValidateBody = ( @@ -31,18 +49,12 @@ export const collectValidateBody = ( if (field.required) { helpers.add("validate_choice_required"); const pyChoices = field.choices.map((c) => pyFieldName(c, formatName)); - errorLines.push( - `errors.extend(validate_choice_required(self._resource, profile_name, ${JSON.stringify(pyChoices)}))`, - ); + pushListValidation(errorLines, "errors", "validate_choice_required", [], pyChoices); } if (field.prohibited?.length) { helpers.add("validate_choice_prohibited"); const pyProhibited = field.prohibited.map((c) => pyFieldName(c, formatName)); - errorLines.push( - "errors.extend(validate_choice_prohibited(self._resource, profile_name, [", - ...pyProhibited.map((c) => ` ${JSON.stringify(c)},`), - "]))", - ); + pushListValidation(errorLines, "errors", "validate_choice_prohibited", [], pyProhibited); } continue; } @@ -91,9 +103,7 @@ const collectRegularFieldValidation = ( helpers.add("validate_enum"); const target = field.enum.isOpen ? warningLines : errorLines; const listName = field.enum.isOpen ? "warnings" : "errors"; - target.push( - `${listName}.extend(validate_enum(self._resource, profile_name, ${JSON.stringify(pyName)}, ${JSON.stringify(field.enum.values)}))`, - ); + pushListValidation(target, listName, "validate_enum", [JSON.stringify(pyName)], field.enum.values); } if (field.mustSupport && !field.required) { helpers.add("validate_must_support"); @@ -104,9 +114,7 @@ const collectRegularFieldValidation = ( if (field.reference && field.reference.resource.length > 0) { helpers.add("validate_reference"); const allowed = field.reference.resource.map((ref) => tsIndex.findLastSpecializationByIdentifier(ref).name); - errorLines.push( - `errors.extend(validate_reference(self._resource, profile_name, ${JSON.stringify(pyName)}, ${JSON.stringify(allowed)}))`, - ); + pushListValidation(errorLines, "errors", "validate_reference", [JSON.stringify(pyName)], allowed); } if (field.slicing?.slices) { collectSliceValidation(field, pyName, helpers, errorLines, tsIndex, formatName); @@ -147,8 +155,12 @@ const collectSliceValidation = ( } if (sliceRequiredFields.length > 0) { helpers.add("validate_slice_fields"); - errorLines.push( - `errors.extend(validate_slice_fields(self._resource, profile_name, ${JSON.stringify(name)}, ${JSON.stringify(match)}, ${JSON.stringify(sliceName)}, ${JSON.stringify(sliceRequiredFields)}))`, + pushListValidation( + errorLines, + "errors", + "validate_slice_fields", + [JSON.stringify(name), JSON.stringify(match), JSON.stringify(sliceName)], + sliceRequiredFields, ); } } diff --git a/test/api/write-generator/__snapshots__/python.test.ts.snap b/test/api/write-generator/__snapshots__/python.test.ts.snap index c98f6f76..13cb897b 100644 --- a/test/api/write-generator/__snapshots__/python.test.ts.snap +++ b/test/api/write-generator/__snapshots__/python.test.ts.snap @@ -556,35 +556,51 @@ class ObservationBodyweightProfile: errors: list[str] = [] warnings: list[str] = [] errors.extend(validate_required(self._resource, profile_name, "status")) - errors.extend(validate_enum(self._resource, profile_name, "status", ["registered","preliminary","final","amended","corrected","cancelled","entered-in-error","unknown"])) + errors.extend( + validate_enum(self._resource, profile_name, "status", [ + "registered","preliminary","final","amended","corrected","cancelled","entered-in-error","unknown" + ])) errors.extend(validate_required(self._resource, profile_name, "category")) errors.extend(validate_slice_cardinality(self._resource, profile_name, "category", {"coding":[{"code":"vital-signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}, "VSCat", 1, 1)) errors.extend(validate_required(self._resource, profile_name, "code")) errors.extend(validate_fixed_value(self._resource, profile_name, "code", {"coding":[{"code":"29463-7","system":"http://loinc.org"}]})) errors.extend(validate_required(self._resource, profile_name, "subject")) - errors.extend(validate_reference(self._resource, profile_name, "subject", ["Patient"])) - errors.extend(validate_choice_required(self._resource, profile_name, ["effectiveDateTime","effectivePeriod"])) - errors.extend(validate_choice_prohibited(self._resource, profile_name, [ - "effectiveTiming", - "effectiveInstant", + errors.extend( + validate_reference(self._resource, profile_name, "subject", [ + "Patient" + ])) + errors.extend( + validate_choice_required(self._resource, profile_name, [ + "effectiveDateTime","effectivePeriod" + ])) + errors.extend( + validate_choice_prohibited(self._resource, profile_name, [ + "effectiveTiming","effectiveInstant" + ])) + errors.extend( + validate_reference(self._resource, profile_name, "hasMember", [ + "MolecularSequence","QuestionnaireResponse","Observation" + ])) + errors.extend( + validate_reference(self._resource, profile_name, "derivedFrom", [ + "DocumentReference","ImagingStudy","Media","MolecularSequence","QuestionnaireResponse","Observation" + ])) + errors.extend( + validate_choice_prohibited(self._resource, profile_name, [ + "valueCodeableConcept","valueString","valueBoolean","valueInteger","valueRange","valueRatio","valueSampledData","valueTime","valueDateTime","valuePeriod" ])) - errors.extend(validate_reference(self._resource, profile_name, "hasMember", ["MolecularSequence","QuestionnaireResponse","Observation"])) - errors.extend(validate_reference(self._resource, profile_name, "derivedFrom", ["DocumentReference","ImagingStudy","Media","MolecularSequence","QuestionnaireResponse","Observation"])) - errors.extend(validate_choice_prohibited(self._resource, profile_name, [ - "valueCodeableConcept", - "valueString", - "valueBoolean", - "valueInteger", - "valueRange", - "valueRatio", - "valueSampledData", - "valueTime", - "valueDateTime", - "valuePeriod", + warnings.extend( + validate_enum(self._resource, profile_name, "category", [ + "social-history","vital-signs","imaging","laboratory","procedure","survey","exam","therapy","activity" + ])) + warnings.extend( + validate_enum(self._resource, profile_name, "code", [ + "85353-1","9279-1","8867-4","2708-6","8310-5","8302-2","9843-4","29463-7","39156-5","85354-9","8480-6","8462-4","8478-0" + ])) + warnings.extend( + validate_enum(self._resource, profile_name, "dataAbsentReason", [ + "unknown","asked-unknown","temp-unknown","not-asked","asked-declined","masked","not-applicable","unsupported","as-text","error","not-a-number","negative-infinity","positive-infinity","not-performed","not-permitted" ])) - warnings.extend(validate_enum(self._resource, profile_name, "category", ["social-history","vital-signs","imaging","laboratory","procedure","survey","exam","therapy","activity"])) - warnings.extend(validate_enum(self._resource, profile_name, "code", ["85353-1","9279-1","8867-4","2708-6","8310-5","8302-2","9843-4","29463-7","39156-5","85354-9","8480-6","8462-4","8478-0"])) - warnings.extend(validate_enum(self._resource, profile_name, "dataAbsentReason", ["unknown","asked-unknown","temp-unknown","not-asked","asked-declined","masked","not-applicable","unsupported","as-text","error","not-a-number","negative-infinity","positive-infinity","not-performed","not-permitted"])) warnings.extend(validate_must_support(self._resource, profile_name, "dataAbsentReason")) return {"errors": errors, "warnings": warnings} @@ -800,39 +816,61 @@ class ObservationBpProfile: errors: list[str] = [] warnings: list[str] = [] errors.extend(validate_required(self._resource, profile_name, "status")) - errors.extend(validate_enum(self._resource, profile_name, "status", ["registered","preliminary","final","amended","corrected","cancelled","entered-in-error","unknown"])) + errors.extend( + validate_enum(self._resource, profile_name, "status", [ + "registered","preliminary","final","amended","corrected","cancelled","entered-in-error","unknown" + ])) errors.extend(validate_required(self._resource, profile_name, "category")) errors.extend(validate_slice_cardinality(self._resource, profile_name, "category", {"coding":[{"code":"vital-signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}, "VSCat", 1, 1)) errors.extend(validate_required(self._resource, profile_name, "code")) errors.extend(validate_fixed_value(self._resource, profile_name, "code", {"coding":[{"code":"85354-9","system":"http://loinc.org"}]})) errors.extend(validate_required(self._resource, profile_name, "subject")) - errors.extend(validate_reference(self._resource, profile_name, "subject", ["Patient"])) - errors.extend(validate_choice_required(self._resource, profile_name, ["effectiveDateTime","effectivePeriod"])) - errors.extend(validate_choice_prohibited(self._resource, profile_name, [ - "effectiveTiming", - "effectiveInstant", + errors.extend( + validate_reference(self._resource, profile_name, "subject", [ + "Patient" + ])) + errors.extend( + validate_choice_required(self._resource, profile_name, [ + "effectiveDateTime","effectivePeriod" + ])) + errors.extend( + validate_choice_prohibited(self._resource, profile_name, [ + "effectiveTiming","effectiveInstant" + ])) + errors.extend( + validate_reference(self._resource, profile_name, "hasMember", [ + "MolecularSequence","QuestionnaireResponse","Observation" + ])) + errors.extend( + validate_reference(self._resource, profile_name, "derivedFrom", [ + "DocumentReference","ImagingStudy","Media","MolecularSequence","QuestionnaireResponse","Observation" ])) - errors.extend(validate_reference(self._resource, profile_name, "hasMember", ["MolecularSequence","QuestionnaireResponse","Observation"])) - errors.extend(validate_reference(self._resource, profile_name, "derivedFrom", ["DocumentReference","ImagingStudy","Media","MolecularSequence","QuestionnaireResponse","Observation"])) errors.extend(validate_slice_cardinality(self._resource, profile_name, "component", {"code":{"coding":[{"code":"8480-6","system":"http://loinc.org"}]}}, "SystolicBP", 1, 1)) - errors.extend(validate_slice_fields(self._resource, profile_name, "component", {"code":{"coding":[{"code":"8480-6","system":"http://loinc.org"}]}}, "SystolicBP", ["valueQuantity"])) + errors.extend( + validate_slice_fields(self._resource, profile_name, "component", {"code":{"coding":[{"code":"8480-6","system":"http://loinc.org"}]}}, "SystolicBP", [ + "valueQuantity" + ])) errors.extend(validate_slice_cardinality(self._resource, profile_name, "component", {"code":{"coding":[{"code":"8462-4","system":"http://loinc.org"}]}}, "DiastolicBP", 1, 1)) - errors.extend(validate_slice_fields(self._resource, profile_name, "component", {"code":{"coding":[{"code":"8462-4","system":"http://loinc.org"}]}}, "DiastolicBP", ["valueQuantity"])) - errors.extend(validate_choice_prohibited(self._resource, profile_name, [ - "valueCodeableConcept", - "valueString", - "valueBoolean", - "valueInteger", - "valueRange", - "valueRatio", - "valueSampledData", - "valueTime", - "valueDateTime", - "valuePeriod", + errors.extend( + validate_slice_fields(self._resource, profile_name, "component", {"code":{"coding":[{"code":"8462-4","system":"http://loinc.org"}]}}, "DiastolicBP", [ + "valueQuantity" + ])) + errors.extend( + validate_choice_prohibited(self._resource, profile_name, [ + "valueCodeableConcept","valueString","valueBoolean","valueInteger","valueRange","valueRatio","valueSampledData","valueTime","valueDateTime","valuePeriod" + ])) + warnings.extend( + validate_enum(self._resource, profile_name, "category", [ + "social-history","vital-signs","imaging","laboratory","procedure","survey","exam","therapy","activity" + ])) + warnings.extend( + validate_enum(self._resource, profile_name, "code", [ + "85353-1","9279-1","8867-4","2708-6","8310-5","8302-2","9843-4","29463-7","39156-5","85354-9","8480-6","8462-4","8478-0" + ])) + warnings.extend( + validate_enum(self._resource, profile_name, "dataAbsentReason", [ + "unknown","asked-unknown","temp-unknown","not-asked","asked-declined","masked","not-applicable","unsupported","as-text","error","not-a-number","negative-infinity","positive-infinity","not-performed","not-permitted" ])) - warnings.extend(validate_enum(self._resource, profile_name, "category", ["social-history","vital-signs","imaging","laboratory","procedure","survey","exam","therapy","activity"])) - warnings.extend(validate_enum(self._resource, profile_name, "code", ["85353-1","9279-1","8867-4","2708-6","8310-5","8302-2","9843-4","29463-7","39156-5","85354-9","8480-6","8462-4","8478-0"])) - warnings.extend(validate_enum(self._resource, profile_name, "dataAbsentReason", ["unknown","asked-unknown","temp-unknown","not-asked","asked-declined","masked","not-applicable","unsupported","as-text","error","not-a-number","negative-infinity","positive-infinity","not-performed","not-permitted"])) warnings.extend(validate_must_support(self._resource, profile_name, "dataAbsentReason")) return {"errors": errors, "warnings": warnings} @@ -1495,28 +1533,61 @@ class UscoreBloodPressureProfile: errors: list[str] = [] warnings: list[str] = [] errors.extend(validate_required(self._resource, profile_name, "status")) - errors.extend(validate_enum(self._resource, profile_name, "status", ["registered","preliminary","final","amended","corrected","cancelled","entered-in-error","unknown"])) + errors.extend( + validate_enum(self._resource, profile_name, "status", [ + "registered","preliminary","final","amended","corrected","cancelled","entered-in-error","unknown" + ])) errors.extend(validate_required(self._resource, profile_name, "category")) errors.extend(validate_slice_cardinality(self._resource, profile_name, "category", {"coding":[{"code":"vital-signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}, "VSCat", 1, 1)) errors.extend(validate_required(self._resource, profile_name, "code")) errors.extend(validate_fixed_value(self._resource, profile_name, "code", {"coding":[{"system":"http://loinc.org","code":"85354-9"}]})) errors.extend(validate_required(self._resource, profile_name, "subject")) - errors.extend(validate_reference(self._resource, profile_name, "subject", ["Patient"])) - errors.extend(validate_choice_required(self._resource, profile_name, ["effectiveDateTime","effectivePeriod"])) - errors.extend(validate_choice_prohibited(self._resource, profile_name, [ - "effectiveTiming", - "effectiveInstant", + errors.extend( + validate_reference(self._resource, profile_name, "subject", [ + "Patient" + ])) + errors.extend( + validate_choice_required(self._resource, profile_name, [ + "effectiveDateTime","effectivePeriod" + ])) + errors.extend( + validate_choice_prohibited(self._resource, profile_name, [ + "effectiveTiming","effectiveInstant" + ])) + errors.extend( + validate_reference(self._resource, profile_name, "hasMember", [ + "MolecularSequence","QuestionnaireResponse","Observation" + ])) + errors.extend( + validate_reference(self._resource, profile_name, "derivedFrom", [ + "DocumentReference","ImagingStudy","Media","MolecularSequence","QuestionnaireResponse","Observation" ])) - errors.extend(validate_reference(self._resource, profile_name, "hasMember", ["MolecularSequence","QuestionnaireResponse","Observation"])) - errors.extend(validate_reference(self._resource, profile_name, "derivedFrom", ["DocumentReference","ImagingStudy","Media","MolecularSequence","QuestionnaireResponse","Observation"])) errors.extend(validate_slice_cardinality(self._resource, profile_name, "component", {"code":{"coding":[{"system":"http://loinc.org","code":"8480-6"}]}}, "systolic", 1, 1)) - errors.extend(validate_slice_fields(self._resource, profile_name, "component", {"code":{"coding":[{"system":"http://loinc.org","code":"8480-6"}]}}, "systolic", ["valueQuantity"])) + errors.extend( + validate_slice_fields(self._resource, profile_name, "component", {"code":{"coding":[{"system":"http://loinc.org","code":"8480-6"}]}}, "systolic", [ + "valueQuantity" + ])) errors.extend(validate_slice_cardinality(self._resource, profile_name, "component", {"code":{"coding":[{"system":"http://loinc.org","code":"8462-4"}]}}, "diastolic", 1, 1)) - errors.extend(validate_slice_fields(self._resource, profile_name, "component", {"code":{"coding":[{"system":"http://loinc.org","code":"8462-4"}]}}, "diastolic", ["valueQuantity"])) - errors.extend(validate_reference(self._resource, profile_name, "performer", ["PractitionerRole","CareTeam","Organization","Patient","Practitioner","RelatedPerson"])) - warnings.extend(validate_enum(self._resource, profile_name, "category", ["social-history","vital-signs","imaging","laboratory","procedure","survey","exam","therapy","activity"])) - warnings.extend(validate_enum(self._resource, profile_name, "code", ["2708-6","29463-7","3140-1","3150-0","3151-8","39156-5","59408-5","59575-1","59576-9","77606-2","8287-5","8289-1","8302-2","8306-3","8310-5","8462-4","8478-0","8480-6","8867-4","9279-1","9843-4"])) - warnings.extend(validate_enum(self._resource, profile_name, "dataAbsentReason", ["unknown","asked-unknown","temp-unknown","not-asked","asked-declined","masked","not-applicable","unsupported","as-text","error","not-a-number","negative-infinity","positive-infinity","not-performed","not-permitted"])) + errors.extend( + validate_slice_fields(self._resource, profile_name, "component", {"code":{"coding":[{"system":"http://loinc.org","code":"8462-4"}]}}, "diastolic", [ + "valueQuantity" + ])) + errors.extend( + validate_reference(self._resource, profile_name, "performer", [ + "PractitionerRole","CareTeam","Organization","Patient","Practitioner","RelatedPerson" + ])) + warnings.extend( + validate_enum(self._resource, profile_name, "category", [ + "social-history","vital-signs","imaging","laboratory","procedure","survey","exam","therapy","activity" + ])) + warnings.extend( + validate_enum(self._resource, profile_name, "code", [ + "2708-6","29463-7","3140-1","3150-0","3151-8","39156-5","59408-5","59575-1","59576-9","77606-2","8287-5","8289-1","8302-2","8306-3","8310-5","8462-4","8478-0","8480-6","8867-4","9279-1","9843-4" + ])) + warnings.extend( + validate_enum(self._resource, profile_name, "dataAbsentReason", [ + "unknown","asked-unknown","temp-unknown","not-asked","asked-declined","masked","not-applicable","unsupported","as-text","error","not-a-number","negative-infinity","positive-infinity","not-performed","not-permitted" + ])) warnings.extend(validate_must_support(self._resource, profile_name, "dataAbsentReason")) warnings.extend(validate_must_support(self._resource, profile_name, "performer")) return {"errors": errors, "warnings": warnings} @@ -1742,36 +1813,55 @@ class UscoreBodyWeightProfile: errors: list[str] = [] warnings: list[str] = [] errors.extend(validate_required(self._resource, profile_name, "status")) - errors.extend(validate_enum(self._resource, profile_name, "status", ["registered","preliminary","final","amended","corrected","cancelled","entered-in-error","unknown"])) + errors.extend( + validate_enum(self._resource, profile_name, "status", [ + "registered","preliminary","final","amended","corrected","cancelled","entered-in-error","unknown" + ])) errors.extend(validate_required(self._resource, profile_name, "category")) errors.extend(validate_slice_cardinality(self._resource, profile_name, "category", {"coding":[{"code":"vital-signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}, "VSCat", 1, 1)) errors.extend(validate_required(self._resource, profile_name, "code")) errors.extend(validate_fixed_value(self._resource, profile_name, "code", {"coding":[{"system":"http://loinc.org","code":"29463-7"}]})) errors.extend(validate_required(self._resource, profile_name, "subject")) - errors.extend(validate_reference(self._resource, profile_name, "subject", ["Patient"])) - errors.extend(validate_choice_required(self._resource, profile_name, ["effectiveDateTime","effectivePeriod"])) - errors.extend(validate_choice_prohibited(self._resource, profile_name, [ - "effectiveTiming", - "effectiveInstant", + errors.extend( + validate_reference(self._resource, profile_name, "subject", [ + "Patient" + ])) + errors.extend( + validate_choice_required(self._resource, profile_name, [ + "effectiveDateTime","effectivePeriod" ])) - errors.extend(validate_reference(self._resource, profile_name, "hasMember", ["MolecularSequence","QuestionnaireResponse","Observation"])) - errors.extend(validate_reference(self._resource, profile_name, "derivedFrom", ["DocumentReference","ImagingStudy","Media","MolecularSequence","QuestionnaireResponse","Observation"])) - errors.extend(validate_reference(self._resource, profile_name, "performer", ["PractitionerRole","CareTeam","Organization","Patient","Practitioner","RelatedPerson"])) - errors.extend(validate_choice_prohibited(self._resource, profile_name, [ - "valueCodeableConcept", - "valueString", - "valueBoolean", - "valueInteger", - "valueRange", - "valueRatio", - "valueSampledData", - "valueTime", - "valueDateTime", - "valuePeriod", + errors.extend( + validate_choice_prohibited(self._resource, profile_name, [ + "effectiveTiming","effectiveInstant" + ])) + errors.extend( + validate_reference(self._resource, profile_name, "hasMember", [ + "MolecularSequence","QuestionnaireResponse","Observation" + ])) + errors.extend( + validate_reference(self._resource, profile_name, "derivedFrom", [ + "DocumentReference","ImagingStudy","Media","MolecularSequence","QuestionnaireResponse","Observation" + ])) + errors.extend( + validate_reference(self._resource, profile_name, "performer", [ + "PractitionerRole","CareTeam","Organization","Patient","Practitioner","RelatedPerson" + ])) + errors.extend( + validate_choice_prohibited(self._resource, profile_name, [ + "valueCodeableConcept","valueString","valueBoolean","valueInteger","valueRange","valueRatio","valueSampledData","valueTime","valueDateTime","valuePeriod" + ])) + warnings.extend( + validate_enum(self._resource, profile_name, "category", [ + "social-history","vital-signs","imaging","laboratory","procedure","survey","exam","therapy","activity" + ])) + warnings.extend( + validate_enum(self._resource, profile_name, "code", [ + "2708-6","29463-7","3140-1","3150-0","3151-8","39156-5","59408-5","59575-1","59576-9","77606-2","8287-5","8289-1","8302-2","8306-3","8310-5","8462-4","8478-0","8480-6","8867-4","9279-1","9843-4" + ])) + warnings.extend( + validate_enum(self._resource, profile_name, "dataAbsentReason", [ + "unknown","asked-unknown","temp-unknown","not-asked","asked-declined","masked","not-applicable","unsupported","as-text","error","not-a-number","negative-infinity","positive-infinity","not-performed","not-permitted" ])) - warnings.extend(validate_enum(self._resource, profile_name, "category", ["social-history","vital-signs","imaging","laboratory","procedure","survey","exam","therapy","activity"])) - warnings.extend(validate_enum(self._resource, profile_name, "code", ["2708-6","29463-7","3140-1","3150-0","3151-8","39156-5","59408-5","59575-1","59576-9","77606-2","8287-5","8289-1","8302-2","8306-3","8310-5","8462-4","8478-0","8480-6","8867-4","9279-1","9843-4"])) - warnings.extend(validate_enum(self._resource, profile_name, "dataAbsentReason", ["unknown","asked-unknown","temp-unknown","not-asked","asked-declined","masked","not-applicable","unsupported","as-text","error","not-a-number","negative-infinity","positive-infinity","not-performed","not-permitted"])) warnings.extend(validate_must_support(self._resource, profile_name, "dataAbsentReason")) warnings.extend(validate_must_support(self._resource, profile_name, "performer")) return {"errors": errors, "warnings": warnings} @@ -2000,10 +2090,19 @@ class UscoreRaceExtension: warnings: list[str] = [] errors.extend(validate_required(self._resource, profile_name, "extension")) errors.extend(validate_slice_cardinality(self._resource, profile_name, "extension", {"url":"ombCategory"}, "ombCategory", 0, 6)) - errors.extend(validate_slice_fields(self._resource, profile_name, "extension", {"url":"ombCategory"}, "ombCategory", ["value","valueCoding"])) - errors.extend(validate_slice_fields(self._resource, profile_name, "extension", {"url":"detailed"}, "detailed", ["value","valueCoding"])) + errors.extend( + validate_slice_fields(self._resource, profile_name, "extension", {"url":"ombCategory"}, "ombCategory", [ + "value","valueCoding" + ])) + errors.extend( + validate_slice_fields(self._resource, profile_name, "extension", {"url":"detailed"}, "detailed", [ + "value","valueCoding" + ])) errors.extend(validate_slice_cardinality(self._resource, profile_name, "extension", {"url":"text"}, "text", 1, 1)) - errors.extend(validate_slice_fields(self._resource, profile_name, "extension", {"url":"text"}, "text", ["value","valueString"])) + errors.extend( + validate_slice_fields(self._resource, profile_name, "extension", {"url":"text"}, "text", [ + "value","valueString" + ])) errors.extend(validate_required(self._resource, profile_name, "url")) errors.extend(validate_fixed_value(self._resource, profile_name, "url", "http://hl7.org/fhir/us/core/StructureDefinition/us-core-race")) return {"errors": errors, "warnings": warnings} From 99db3f9459c45ac48c76792f1abd78563faed000 Mon Sep 17 00:00:00 2001 From: Aleksandr Penskoi Date: Fri, 24 Jul 2026 16:24:21 +0400 Subject: [PATCH 11/16] chore(examples): regenerate python-r4-us-core with wrapped validation calls --- .../profiles/extension_birth_place.py | 58 ++--------------- .../profiles/extension_birth_time.py | 58 ++--------------- .../profiles/extension_own_prefix.py | 58 ++--------------- .../observation_observation_bodyweight.py | 60 ++++++++++------- .../observation_observation_vitalsigns.py | 46 +++++++++---- .../extension_uscore_ethnicity_extension.py | 15 ++++- ...tension_uscore_individual_sex_extension.py | 58 ++--------------- ...ion_uscore_interpreter_needed_extension.py | 58 ++--------------- .../extension_uscore_race_extension.py | 15 ++++- ...ion_uscore_tribal_affiliation_extension.py | 10 ++- ...servation_uscore_blood_pressure_profile.py | 61 +++++++++++++---- .../observation_uscore_body_weight_profile.py | 65 ++++++++++++------- .../observation_uscore_vital_signs_profile.py | 51 +++++++++++---- 13 files changed, 268 insertions(+), 345 deletions(-) diff --git a/examples/python-r4-us-core/fhir_types/hl7_fhir_r4_core/profiles/extension_birth_place.py b/examples/python-r4-us-core/fhir_types/hl7_fhir_r4_core/profiles/extension_birth_place.py index 0bce2d1e..ca2d7e19 100644 --- a/examples/python-r4-us-core/fhir_types/hl7_fhir_r4_core/profiles/extension_birth_place.py +++ b/examples/python-r4-us-core/fhir_types/hl7_fhir_r4_core/profiles/extension_birth_place.py @@ -67,57 +67,13 @@ def validate(self) -> dict[str, list[str]]: warnings: list[str] = [] errors.extend(validate_required(self._resource, profile_name, "url")) errors.extend(validate_fixed_value(self._resource, profile_name, "url", "http://hl7.org/fhir/StructureDefinition/patient-birthPlace")) - errors.extend(validate_choice_required(self._resource, profile_name, ["valueAddress"])) - errors.extend(validate_choice_prohibited(self._resource, profile_name, [ - "valueBase64binary", - "valueBoolean", - "valueCanonical", - "valueCode", - "valueDate", - "valueDateTime", - "valueDecimal", - "valueId", - "valueInstant", - "valueInteger", - "valueMarkdown", - "valueOid", - "valuePositiveInt", - "valueString", - "valueTime", - "valueUnsignedInt", - "valueUri", - "valueUrl", - "valueUuid", - "valueAge", - "valueAnnotation", - "valueAttachment", - "valueCodeableConcept", - "valueCoding", - "valueContactPoint", - "valueCount", - "valueDistance", - "valueDuration", - "valueHumanName", - "valueIdentifier", - "valueMoney", - "valuePeriod", - "valueQuantity", - "valueRange", - "valueRatio", - "valueReference", - "valueSampledData", - "valueSignature", - "valueTiming", - "valueContactDetail", - "valueContributor", - "valueDataRequirement", - "valueExpression", - "valueParameterDefinition", - "valueRelatedArtifact", - "valueTriggerDefinition", - "valueUsageContext", - "valueDosage", - "valueMeta", + errors.extend( + validate_choice_required(self._resource, profile_name, [ + "valueAddress" + ])) + errors.extend( + validate_choice_prohibited(self._resource, profile_name, [ + "valueBase64binary","valueBoolean","valueCanonical","valueCode","valueDate","valueDateTime","valueDecimal","valueId","valueInstant","valueInteger","valueMarkdown","valueOid","valuePositiveInt","valueString","valueTime","valueUnsignedInt","valueUri","valueUrl","valueUuid","valueAge","valueAnnotation","valueAttachment","valueCodeableConcept","valueCoding","valueContactPoint","valueCount","valueDistance","valueDuration","valueHumanName","valueIdentifier","valueMoney","valuePeriod","valueQuantity","valueRange","valueRatio","valueReference","valueSampledData","valueSignature","valueTiming","valueContactDetail","valueContributor","valueDataRequirement","valueExpression","valueParameterDefinition","valueRelatedArtifact","valueTriggerDefinition","valueUsageContext","valueDosage","valueMeta" ])) return {"errors": errors, "warnings": warnings} diff --git a/examples/python-r4-us-core/fhir_types/hl7_fhir_r4_core/profiles/extension_birth_time.py b/examples/python-r4-us-core/fhir_types/hl7_fhir_r4_core/profiles/extension_birth_time.py index 388d111a..f3236787 100644 --- a/examples/python-r4-us-core/fhir_types/hl7_fhir_r4_core/profiles/extension_birth_time.py +++ b/examples/python-r4-us-core/fhir_types/hl7_fhir_r4_core/profiles/extension_birth_time.py @@ -66,57 +66,13 @@ def validate(self) -> dict[str, list[str]]: warnings: list[str] = [] errors.extend(validate_required(self._resource, profile_name, "url")) errors.extend(validate_fixed_value(self._resource, profile_name, "url", "http://hl7.org/fhir/StructureDefinition/patient-birthTime")) - errors.extend(validate_choice_required(self._resource, profile_name, ["valueDateTime"])) - errors.extend(validate_choice_prohibited(self._resource, profile_name, [ - "valueBase64binary", - "valueBoolean", - "valueCanonical", - "valueCode", - "valueDate", - "valueDecimal", - "valueId", - "valueInstant", - "valueInteger", - "valueMarkdown", - "valueOid", - "valuePositiveInt", - "valueString", - "valueTime", - "valueUnsignedInt", - "valueUri", - "valueUrl", - "valueUuid", - "valueAddress", - "valueAge", - "valueAnnotation", - "valueAttachment", - "valueCodeableConcept", - "valueCoding", - "valueContactPoint", - "valueCount", - "valueDistance", - "valueDuration", - "valueHumanName", - "valueIdentifier", - "valueMoney", - "valuePeriod", - "valueQuantity", - "valueRange", - "valueRatio", - "valueReference", - "valueSampledData", - "valueSignature", - "valueTiming", - "valueContactDetail", - "valueContributor", - "valueDataRequirement", - "valueExpression", - "valueParameterDefinition", - "valueRelatedArtifact", - "valueTriggerDefinition", - "valueUsageContext", - "valueDosage", - "valueMeta", + errors.extend( + validate_choice_required(self._resource, profile_name, [ + "valueDateTime" + ])) + errors.extend( + validate_choice_prohibited(self._resource, profile_name, [ + "valueBase64binary","valueBoolean","valueCanonical","valueCode","valueDate","valueDecimal","valueId","valueInstant","valueInteger","valueMarkdown","valueOid","valuePositiveInt","valueString","valueTime","valueUnsignedInt","valueUri","valueUrl","valueUuid","valueAddress","valueAge","valueAnnotation","valueAttachment","valueCodeableConcept","valueCoding","valueContactPoint","valueCount","valueDistance","valueDuration","valueHumanName","valueIdentifier","valueMoney","valuePeriod","valueQuantity","valueRange","valueRatio","valueReference","valueSampledData","valueSignature","valueTiming","valueContactDetail","valueContributor","valueDataRequirement","valueExpression","valueParameterDefinition","valueRelatedArtifact","valueTriggerDefinition","valueUsageContext","valueDosage","valueMeta" ])) return {"errors": errors, "warnings": warnings} diff --git a/examples/python-r4-us-core/fhir_types/hl7_fhir_r4_core/profiles/extension_own_prefix.py b/examples/python-r4-us-core/fhir_types/hl7_fhir_r4_core/profiles/extension_own_prefix.py index 8fc724ea..a99f8b95 100644 --- a/examples/python-r4-us-core/fhir_types/hl7_fhir_r4_core/profiles/extension_own_prefix.py +++ b/examples/python-r4-us-core/fhir_types/hl7_fhir_r4_core/profiles/extension_own_prefix.py @@ -66,57 +66,13 @@ def validate(self) -> dict[str, list[str]]: warnings: list[str] = [] errors.extend(validate_required(self._resource, profile_name, "url")) errors.extend(validate_fixed_value(self._resource, profile_name, "url", "http://hl7.org/fhir/StructureDefinition/humanname-own-prefix")) - errors.extend(validate_choice_required(self._resource, profile_name, ["valueString"])) - errors.extend(validate_choice_prohibited(self._resource, profile_name, [ - "valueBase64binary", - "valueBoolean", - "valueCanonical", - "valueCode", - "valueDate", - "valueDateTime", - "valueDecimal", - "valueId", - "valueInstant", - "valueInteger", - "valueMarkdown", - "valueOid", - "valuePositiveInt", - "valueTime", - "valueUnsignedInt", - "valueUri", - "valueUrl", - "valueUuid", - "valueAddress", - "valueAge", - "valueAnnotation", - "valueAttachment", - "valueCodeableConcept", - "valueCoding", - "valueContactPoint", - "valueCount", - "valueDistance", - "valueDuration", - "valueHumanName", - "valueIdentifier", - "valueMoney", - "valuePeriod", - "valueQuantity", - "valueRange", - "valueRatio", - "valueReference", - "valueSampledData", - "valueSignature", - "valueTiming", - "valueContactDetail", - "valueContributor", - "valueDataRequirement", - "valueExpression", - "valueParameterDefinition", - "valueRelatedArtifact", - "valueTriggerDefinition", - "valueUsageContext", - "valueDosage", - "valueMeta", + errors.extend( + validate_choice_required(self._resource, profile_name, [ + "valueString" + ])) + errors.extend( + validate_choice_prohibited(self._resource, profile_name, [ + "valueBase64binary","valueBoolean","valueCanonical","valueCode","valueDate","valueDateTime","valueDecimal","valueId","valueInstant","valueInteger","valueMarkdown","valueOid","valuePositiveInt","valueTime","valueUnsignedInt","valueUri","valueUrl","valueUuid","valueAddress","valueAge","valueAnnotation","valueAttachment","valueCodeableConcept","valueCoding","valueContactPoint","valueCount","valueDistance","valueDuration","valueHumanName","valueIdentifier","valueMoney","valuePeriod","valueQuantity","valueRange","valueRatio","valueReference","valueSampledData","valueSignature","valueTiming","valueContactDetail","valueContributor","valueDataRequirement","valueExpression","valueParameterDefinition","valueRelatedArtifact","valueTriggerDefinition","valueUsageContext","valueDosage","valueMeta" ])) return {"errors": errors, "warnings": warnings} diff --git a/examples/python-r4-us-core/fhir_types/hl7_fhir_r4_core/profiles/observation_observation_bodyweight.py b/examples/python-r4-us-core/fhir_types/hl7_fhir_r4_core/profiles/observation_observation_bodyweight.py index 9f19e59d..2ab344f0 100644 --- a/examples/python-r4-us-core/fhir_types/hl7_fhir_r4_core/profiles/observation_observation_bodyweight.py +++ b/examples/python-r4-us-core/fhir_types/hl7_fhir_r4_core/profiles/observation_observation_bodyweight.py @@ -143,35 +143,51 @@ def validate(self) -> dict[str, list[str]]: errors: list[str] = [] warnings: list[str] = [] errors.extend(validate_required(self._resource, profile_name, "status")) - errors.extend(validate_enum(self._resource, profile_name, "status", ["registered","preliminary","final","amended","corrected","cancelled","entered-in-error","unknown"])) + errors.extend( + validate_enum(self._resource, profile_name, "status", [ + "registered","preliminary","final","amended","corrected","cancelled","entered-in-error","unknown" + ])) errors.extend(validate_required(self._resource, profile_name, "category")) errors.extend(validate_slice_cardinality(self._resource, profile_name, "category", {"coding":[{"code":"vital-signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}, "VSCat", 1, 1)) errors.extend(validate_required(self._resource, profile_name, "code")) errors.extend(validate_fixed_value(self._resource, profile_name, "code", {"coding":[{"code":"29463-7","system":"http://loinc.org"}]})) errors.extend(validate_required(self._resource, profile_name, "subject")) - errors.extend(validate_reference(self._resource, profile_name, "subject", ["Patient"])) - errors.extend(validate_choice_required(self._resource, profile_name, ["effectiveDateTime","effectivePeriod"])) - errors.extend(validate_choice_prohibited(self._resource, profile_name, [ - "effectiveTiming", - "effectiveInstant", + errors.extend( + validate_reference(self._resource, profile_name, "subject", [ + "Patient" + ])) + errors.extend( + validate_choice_required(self._resource, profile_name, [ + "effectiveDateTime","effectivePeriod" + ])) + errors.extend( + validate_choice_prohibited(self._resource, profile_name, [ + "effectiveTiming","effectiveInstant" + ])) + errors.extend( + validate_reference(self._resource, profile_name, "hasMember", [ + "MolecularSequence","QuestionnaireResponse","Observation" + ])) + errors.extend( + validate_reference(self._resource, profile_name, "derivedFrom", [ + "DocumentReference","ImagingStudy","Media","MolecularSequence","QuestionnaireResponse","Observation" + ])) + errors.extend( + validate_choice_prohibited(self._resource, profile_name, [ + "valueCodeableConcept","valueString","valueBoolean","valueInteger","valueRange","valueRatio","valueSampledData","valueTime","valueDateTime","valuePeriod" + ])) + warnings.extend( + validate_enum(self._resource, profile_name, "category", [ + "social-history","vital-signs","imaging","laboratory","procedure","survey","exam","therapy","activity" + ])) + warnings.extend( + validate_enum(self._resource, profile_name, "code", [ + "85353-1","9279-1","8867-4","2708-6","8310-5","8302-2","9843-4","29463-7","39156-5","85354-9","8480-6","8462-4","8478-0" ])) - errors.extend(validate_reference(self._resource, profile_name, "hasMember", ["MolecularSequence","QuestionnaireResponse","Observation"])) - errors.extend(validate_reference(self._resource, profile_name, "derivedFrom", ["DocumentReference","ImagingStudy","Media","MolecularSequence","QuestionnaireResponse","Observation"])) - errors.extend(validate_choice_prohibited(self._resource, profile_name, [ - "valueCodeableConcept", - "valueString", - "valueBoolean", - "valueInteger", - "valueRange", - "valueRatio", - "valueSampledData", - "valueTime", - "valueDateTime", - "valuePeriod", + warnings.extend( + validate_enum(self._resource, profile_name, "dataAbsentReason", [ + "unknown","asked-unknown","temp-unknown","not-asked","asked-declined","masked","not-applicable","unsupported","as-text","error","not-a-number","negative-infinity","positive-infinity","not-performed","not-permitted" ])) - warnings.extend(validate_enum(self._resource, profile_name, "category", ["social-history","vital-signs","imaging","laboratory","procedure","survey","exam","therapy","activity"])) - warnings.extend(validate_enum(self._resource, profile_name, "code", ["85353-1","9279-1","8867-4","2708-6","8310-5","8302-2","9843-4","29463-7","39156-5","85354-9","8480-6","8462-4","8478-0"])) - warnings.extend(validate_enum(self._resource, profile_name, "dataAbsentReason", ["unknown","asked-unknown","temp-unknown","not-asked","asked-declined","masked","not-applicable","unsupported","as-text","error","not-a-number","negative-infinity","positive-infinity","not-performed","not-permitted"])) warnings.extend(validate_must_support(self._resource, profile_name, "dataAbsentReason")) return {"errors": errors, "warnings": warnings} diff --git a/examples/python-r4-us-core/fhir_types/hl7_fhir_r4_core/profiles/observation_observation_vitalsigns.py b/examples/python-r4-us-core/fhir_types/hl7_fhir_r4_core/profiles/observation_observation_vitalsigns.py index a8e33e93..4c1b7fa6 100644 --- a/examples/python-r4-us-core/fhir_types/hl7_fhir_r4_core/profiles/observation_observation_vitalsigns.py +++ b/examples/python-r4-us-core/fhir_types/hl7_fhir_r4_core/profiles/observation_observation_vitalsigns.py @@ -136,22 +136,46 @@ def validate(self) -> dict[str, list[str]]: errors: list[str] = [] warnings: list[str] = [] errors.extend(validate_required(self._resource, profile_name, "status")) - errors.extend(validate_enum(self._resource, profile_name, "status", ["registered","preliminary","final","amended","corrected","cancelled","entered-in-error","unknown"])) + errors.extend( + validate_enum(self._resource, profile_name, "status", [ + "registered","preliminary","final","amended","corrected","cancelled","entered-in-error","unknown" + ])) errors.extend(validate_required(self._resource, profile_name, "category")) errors.extend(validate_slice_cardinality(self._resource, profile_name, "category", {"coding":[{"code":"vital-signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}, "VSCat", 1, 1)) errors.extend(validate_required(self._resource, profile_name, "code")) errors.extend(validate_required(self._resource, profile_name, "subject")) - errors.extend(validate_reference(self._resource, profile_name, "subject", ["Patient"])) - errors.extend(validate_choice_required(self._resource, profile_name, ["effectiveDateTime","effectivePeriod"])) - errors.extend(validate_choice_prohibited(self._resource, profile_name, [ - "effectiveTiming", - "effectiveInstant", + errors.extend( + validate_reference(self._resource, profile_name, "subject", [ + "Patient" + ])) + errors.extend( + validate_choice_required(self._resource, profile_name, [ + "effectiveDateTime","effectivePeriod" + ])) + errors.extend( + validate_choice_prohibited(self._resource, profile_name, [ + "effectiveTiming","effectiveInstant" + ])) + errors.extend( + validate_reference(self._resource, profile_name, "hasMember", [ + "MolecularSequence","QuestionnaireResponse","Observation" + ])) + errors.extend( + validate_reference(self._resource, profile_name, "derivedFrom", [ + "DocumentReference","ImagingStudy","Media","MolecularSequence","QuestionnaireResponse","Observation" + ])) + warnings.extend( + validate_enum(self._resource, profile_name, "category", [ + "social-history","vital-signs","imaging","laboratory","procedure","survey","exam","therapy","activity" + ])) + warnings.extend( + validate_enum(self._resource, profile_name, "code", [ + "85353-1","9279-1","8867-4","2708-6","8310-5","8302-2","9843-4","29463-7","39156-5","85354-9","8480-6","8462-4","8478-0" + ])) + warnings.extend( + validate_enum(self._resource, profile_name, "dataAbsentReason", [ + "unknown","asked-unknown","temp-unknown","not-asked","asked-declined","masked","not-applicable","unsupported","as-text","error","not-a-number","negative-infinity","positive-infinity","not-performed","not-permitted" ])) - errors.extend(validate_reference(self._resource, profile_name, "hasMember", ["MolecularSequence","QuestionnaireResponse","Observation"])) - errors.extend(validate_reference(self._resource, profile_name, "derivedFrom", ["DocumentReference","ImagingStudy","Media","MolecularSequence","QuestionnaireResponse","Observation"])) - warnings.extend(validate_enum(self._resource, profile_name, "category", ["social-history","vital-signs","imaging","laboratory","procedure","survey","exam","therapy","activity"])) - warnings.extend(validate_enum(self._resource, profile_name, "code", ["85353-1","9279-1","8867-4","2708-6","8310-5","8302-2","9843-4","29463-7","39156-5","85354-9","8480-6","8462-4","8478-0"])) - warnings.extend(validate_enum(self._resource, profile_name, "dataAbsentReason", ["unknown","asked-unknown","temp-unknown","not-asked","asked-declined","masked","not-applicable","unsupported","as-text","error","not-a-number","negative-infinity","positive-infinity","not-performed","not-permitted"])) warnings.extend(validate_must_support(self._resource, profile_name, "dataAbsentReason")) return {"errors": errors, "warnings": warnings} diff --git a/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/extension_uscore_ethnicity_extension.py b/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/extension_uscore_ethnicity_extension.py index 56cecf3a..df04873c 100644 --- a/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/extension_uscore_ethnicity_extension.py +++ b/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/extension_uscore_ethnicity_extension.py @@ -215,10 +215,19 @@ def validate(self) -> dict[str, list[str]]: warnings: list[str] = [] errors.extend(validate_required(self._resource, profile_name, "extension")) errors.extend(validate_slice_cardinality(self._resource, profile_name, "extension", {"url":"ombCategory"}, "ombCategory", 0, 1)) - errors.extend(validate_slice_fields(self._resource, profile_name, "extension", {"url":"ombCategory"}, "ombCategory", ["value","valueCoding"])) - errors.extend(validate_slice_fields(self._resource, profile_name, "extension", {"url":"detailed"}, "detailed", ["value","valueCoding"])) + errors.extend( + validate_slice_fields(self._resource, profile_name, "extension", {"url":"ombCategory"}, "ombCategory", [ + "value","valueCoding" + ])) + errors.extend( + validate_slice_fields(self._resource, profile_name, "extension", {"url":"detailed"}, "detailed", [ + "value","valueCoding" + ])) errors.extend(validate_slice_cardinality(self._resource, profile_name, "extension", {"url":"text"}, "text", 1, 1)) - errors.extend(validate_slice_fields(self._resource, profile_name, "extension", {"url":"text"}, "text", ["value","valueString"])) + errors.extend( + validate_slice_fields(self._resource, profile_name, "extension", {"url":"text"}, "text", [ + "value","valueString" + ])) errors.extend(validate_required(self._resource, profile_name, "url")) errors.extend(validate_fixed_value(self._resource, profile_name, "url", "http://hl7.org/fhir/us/core/StructureDefinition/us-core-ethnicity")) return {"errors": errors, "warnings": warnings} diff --git a/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/extension_uscore_individual_sex_extension.py b/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/extension_uscore_individual_sex_extension.py index 8f88b5f9..60431896 100644 --- a/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/extension_uscore_individual_sex_extension.py +++ b/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/extension_uscore_individual_sex_extension.py @@ -67,57 +67,13 @@ def validate(self) -> dict[str, list[str]]: warnings: list[str] = [] errors.extend(validate_required(self._resource, profile_name, "url")) errors.extend(validate_fixed_value(self._resource, profile_name, "url", "http://hl7.org/fhir/us/core/StructureDefinition/us-core-individual-sex")) - errors.extend(validate_choice_required(self._resource, profile_name, ["valueCoding"])) - errors.extend(validate_choice_prohibited(self._resource, profile_name, [ - "valueBase64binary", - "valueBoolean", - "valueCanonical", - "valueCode", - "valueDate", - "valueDateTime", - "valueDecimal", - "valueId", - "valueInstant", - "valueInteger", - "valueMarkdown", - "valueOid", - "valuePositiveInt", - "valueString", - "valueTime", - "valueUnsignedInt", - "valueUri", - "valueUrl", - "valueUuid", - "valueAddress", - "valueAge", - "valueAnnotation", - "valueAttachment", - "valueCodeableConcept", - "valueContactPoint", - "valueCount", - "valueDistance", - "valueDuration", - "valueHumanName", - "valueIdentifier", - "valueMoney", - "valuePeriod", - "valueQuantity", - "valueRange", - "valueRatio", - "valueReference", - "valueSampledData", - "valueSignature", - "valueTiming", - "valueContactDetail", - "valueContributor", - "valueDataRequirement", - "valueExpression", - "valueParameterDefinition", - "valueRelatedArtifact", - "valueTriggerDefinition", - "valueUsageContext", - "valueDosage", - "valueMeta", + errors.extend( + validate_choice_required(self._resource, profile_name, [ + "valueCoding" + ])) + errors.extend( + validate_choice_prohibited(self._resource, profile_name, [ + "valueBase64binary","valueBoolean","valueCanonical","valueCode","valueDate","valueDateTime","valueDecimal","valueId","valueInstant","valueInteger","valueMarkdown","valueOid","valuePositiveInt","valueString","valueTime","valueUnsignedInt","valueUri","valueUrl","valueUuid","valueAddress","valueAge","valueAnnotation","valueAttachment","valueCodeableConcept","valueContactPoint","valueCount","valueDistance","valueDuration","valueHumanName","valueIdentifier","valueMoney","valuePeriod","valueQuantity","valueRange","valueRatio","valueReference","valueSampledData","valueSignature","valueTiming","valueContactDetail","valueContributor","valueDataRequirement","valueExpression","valueParameterDefinition","valueRelatedArtifact","valueTriggerDefinition","valueUsageContext","valueDosage","valueMeta" ])) return {"errors": errors, "warnings": warnings} diff --git a/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/extension_uscore_interpreter_needed_extension.py b/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/extension_uscore_interpreter_needed_extension.py index c4200c20..a6237749 100644 --- a/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/extension_uscore_interpreter_needed_extension.py +++ b/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/extension_uscore_interpreter_needed_extension.py @@ -67,57 +67,13 @@ def validate(self) -> dict[str, list[str]]: warnings: list[str] = [] errors.extend(validate_required(self._resource, profile_name, "url")) errors.extend(validate_fixed_value(self._resource, profile_name, "url", "http://hl7.org/fhir/us/core/StructureDefinition/us-core-interpreter-needed")) - errors.extend(validate_choice_required(self._resource, profile_name, ["valueCoding"])) - errors.extend(validate_choice_prohibited(self._resource, profile_name, [ - "valueBase64binary", - "valueBoolean", - "valueCanonical", - "valueCode", - "valueDate", - "valueDateTime", - "valueDecimal", - "valueId", - "valueInstant", - "valueInteger", - "valueMarkdown", - "valueOid", - "valuePositiveInt", - "valueString", - "valueTime", - "valueUnsignedInt", - "valueUri", - "valueUrl", - "valueUuid", - "valueAddress", - "valueAge", - "valueAnnotation", - "valueAttachment", - "valueCodeableConcept", - "valueContactPoint", - "valueCount", - "valueDistance", - "valueDuration", - "valueHumanName", - "valueIdentifier", - "valueMoney", - "valuePeriod", - "valueQuantity", - "valueRange", - "valueRatio", - "valueReference", - "valueSampledData", - "valueSignature", - "valueTiming", - "valueContactDetail", - "valueContributor", - "valueDataRequirement", - "valueExpression", - "valueParameterDefinition", - "valueRelatedArtifact", - "valueTriggerDefinition", - "valueUsageContext", - "valueDosage", - "valueMeta", + errors.extend( + validate_choice_required(self._resource, profile_name, [ + "valueCoding" + ])) + errors.extend( + validate_choice_prohibited(self._resource, profile_name, [ + "valueBase64binary","valueBoolean","valueCanonical","valueCode","valueDate","valueDateTime","valueDecimal","valueId","valueInstant","valueInteger","valueMarkdown","valueOid","valuePositiveInt","valueString","valueTime","valueUnsignedInt","valueUri","valueUrl","valueUuid","valueAddress","valueAge","valueAnnotation","valueAttachment","valueCodeableConcept","valueContactPoint","valueCount","valueDistance","valueDuration","valueHumanName","valueIdentifier","valueMoney","valuePeriod","valueQuantity","valueRange","valueRatio","valueReference","valueSampledData","valueSignature","valueTiming","valueContactDetail","valueContributor","valueDataRequirement","valueExpression","valueParameterDefinition","valueRelatedArtifact","valueTriggerDefinition","valueUsageContext","valueDosage","valueMeta" ])) return {"errors": errors, "warnings": warnings} diff --git a/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/extension_uscore_race_extension.py b/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/extension_uscore_race_extension.py index f4ebf38f..34bb4b32 100644 --- a/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/extension_uscore_race_extension.py +++ b/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/extension_uscore_race_extension.py @@ -218,10 +218,19 @@ def validate(self) -> dict[str, list[str]]: warnings: list[str] = [] errors.extend(validate_required(self._resource, profile_name, "extension")) errors.extend(validate_slice_cardinality(self._resource, profile_name, "extension", {"url":"ombCategory"}, "ombCategory", 0, 6)) - errors.extend(validate_slice_fields(self._resource, profile_name, "extension", {"url":"ombCategory"}, "ombCategory", ["value","valueCoding"])) - errors.extend(validate_slice_fields(self._resource, profile_name, "extension", {"url":"detailed"}, "detailed", ["value","valueCoding"])) + errors.extend( + validate_slice_fields(self._resource, profile_name, "extension", {"url":"ombCategory"}, "ombCategory", [ + "value","valueCoding" + ])) + errors.extend( + validate_slice_fields(self._resource, profile_name, "extension", {"url":"detailed"}, "detailed", [ + "value","valueCoding" + ])) errors.extend(validate_slice_cardinality(self._resource, profile_name, "extension", {"url":"text"}, "text", 1, 1)) - errors.extend(validate_slice_fields(self._resource, profile_name, "extension", {"url":"text"}, "text", ["value","valueString"])) + errors.extend( + validate_slice_fields(self._resource, profile_name, "extension", {"url":"text"}, "text", [ + "value","valueString" + ])) errors.extend(validate_required(self._resource, profile_name, "url")) errors.extend(validate_fixed_value(self._resource, profile_name, "url", "http://hl7.org/fhir/us/core/StructureDefinition/us-core-race")) return {"errors": errors, "warnings": warnings} diff --git a/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/extension_uscore_tribal_affiliation_extension.py b/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/extension_uscore_tribal_affiliation_extension.py index 79e71a28..de5dc3c9 100644 --- a/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/extension_uscore_tribal_affiliation_extension.py +++ b/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/extension_uscore_tribal_affiliation_extension.py @@ -165,9 +165,15 @@ def validate(self) -> dict[str, list[str]]: warnings: list[str] = [] errors.extend(validate_required(self._resource, profile_name, "extension")) errors.extend(validate_slice_cardinality(self._resource, profile_name, "extension", {"url":"tribalAffiliation"}, "tribalAffiliation", 1, 1)) - errors.extend(validate_slice_fields(self._resource, profile_name, "extension", {"url":"tribalAffiliation"}, "tribalAffiliation", ["value","valueCodeableConcept"])) + errors.extend( + validate_slice_fields(self._resource, profile_name, "extension", {"url":"tribalAffiliation"}, "tribalAffiliation", [ + "value","valueCodeableConcept" + ])) errors.extend(validate_slice_cardinality(self._resource, profile_name, "extension", {"url":"isEnrolled"}, "isEnrolled", 0, 1)) - errors.extend(validate_slice_fields(self._resource, profile_name, "extension", {"url":"isEnrolled"}, "isEnrolled", ["value","valueBoolean"])) + errors.extend( + validate_slice_fields(self._resource, profile_name, "extension", {"url":"isEnrolled"}, "isEnrolled", [ + "value","valueBoolean" + ])) errors.extend(validate_required(self._resource, profile_name, "url")) errors.extend(validate_fixed_value(self._resource, profile_name, "url", "http://hl7.org/fhir/us/core/StructureDefinition/us-core-tribal-affiliation")) return {"errors": errors, "warnings": warnings} diff --git a/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/observation_uscore_blood_pressure_profile.py b/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/observation_uscore_blood_pressure_profile.py index ab903514..d9fc0b45 100644 --- a/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/observation_uscore_blood_pressure_profile.py +++ b/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/observation_uscore_blood_pressure_profile.py @@ -386,28 +386,61 @@ def validate(self) -> dict[str, list[str]]: errors: list[str] = [] warnings: list[str] = [] errors.extend(validate_required(self._resource, profile_name, "status")) - errors.extend(validate_enum(self._resource, profile_name, "status", ["registered","preliminary","final","amended","corrected","cancelled","entered-in-error","unknown"])) + errors.extend( + validate_enum(self._resource, profile_name, "status", [ + "registered","preliminary","final","amended","corrected","cancelled","entered-in-error","unknown" + ])) errors.extend(validate_required(self._resource, profile_name, "category")) errors.extend(validate_slice_cardinality(self._resource, profile_name, "category", {"coding":[{"code":"vital-signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}, "VSCat", 1, 1)) errors.extend(validate_required(self._resource, profile_name, "code")) errors.extend(validate_fixed_value(self._resource, profile_name, "code", {"coding":[{"system":"http://loinc.org","code":"85354-9"}]})) errors.extend(validate_required(self._resource, profile_name, "subject")) - errors.extend(validate_reference(self._resource, profile_name, "subject", ["Patient"])) - errors.extend(validate_choice_required(self._resource, profile_name, ["effectiveDateTime","effectivePeriod"])) - errors.extend(validate_choice_prohibited(self._resource, profile_name, [ - "effectiveTiming", - "effectiveInstant", + errors.extend( + validate_reference(self._resource, profile_name, "subject", [ + "Patient" + ])) + errors.extend( + validate_choice_required(self._resource, profile_name, [ + "effectiveDateTime","effectivePeriod" + ])) + errors.extend( + validate_choice_prohibited(self._resource, profile_name, [ + "effectiveTiming","effectiveInstant" + ])) + errors.extend( + validate_reference(self._resource, profile_name, "hasMember", [ + "MolecularSequence","QuestionnaireResponse","Observation" + ])) + errors.extend( + validate_reference(self._resource, profile_name, "derivedFrom", [ + "DocumentReference","ImagingStudy","Media","MolecularSequence","QuestionnaireResponse","Observation" ])) - errors.extend(validate_reference(self._resource, profile_name, "hasMember", ["MolecularSequence","QuestionnaireResponse","Observation"])) - errors.extend(validate_reference(self._resource, profile_name, "derivedFrom", ["DocumentReference","ImagingStudy","Media","MolecularSequence","QuestionnaireResponse","Observation"])) errors.extend(validate_slice_cardinality(self._resource, profile_name, "component", {"code":{"coding":[{"system":"http://loinc.org","code":"8480-6"}]}}, "systolic", 1, 1)) - errors.extend(validate_slice_fields(self._resource, profile_name, "component", {"code":{"coding":[{"system":"http://loinc.org","code":"8480-6"}]}}, "systolic", ["valueQuantity"])) + errors.extend( + validate_slice_fields(self._resource, profile_name, "component", {"code":{"coding":[{"system":"http://loinc.org","code":"8480-6"}]}}, "systolic", [ + "valueQuantity" + ])) errors.extend(validate_slice_cardinality(self._resource, profile_name, "component", {"code":{"coding":[{"system":"http://loinc.org","code":"8462-4"}]}}, "diastolic", 1, 1)) - errors.extend(validate_slice_fields(self._resource, profile_name, "component", {"code":{"coding":[{"system":"http://loinc.org","code":"8462-4"}]}}, "diastolic", ["valueQuantity"])) - errors.extend(validate_reference(self._resource, profile_name, "performer", ["PractitionerRole","CareTeam","Organization","Patient","Practitioner","RelatedPerson"])) - warnings.extend(validate_enum(self._resource, profile_name, "category", ["social-history","vital-signs","imaging","laboratory","procedure","survey","exam","therapy","activity"])) - warnings.extend(validate_enum(self._resource, profile_name, "code", ["2708-6","29463-7","3140-1","3150-0","3151-8","39156-5","59408-5","59575-1","59576-9","77606-2","8287-5","8289-1","8302-2","8306-3","8310-5","8462-4","8478-0","8480-6","8867-4","9279-1","9843-4"])) - warnings.extend(validate_enum(self._resource, profile_name, "dataAbsentReason", ["unknown","asked-unknown","temp-unknown","not-asked","asked-declined","masked","not-applicable","unsupported","as-text","error","not-a-number","negative-infinity","positive-infinity","not-performed","not-permitted"])) + errors.extend( + validate_slice_fields(self._resource, profile_name, "component", {"code":{"coding":[{"system":"http://loinc.org","code":"8462-4"}]}}, "diastolic", [ + "valueQuantity" + ])) + errors.extend( + validate_reference(self._resource, profile_name, "performer", [ + "PractitionerRole","CareTeam","Organization","Patient","Practitioner","RelatedPerson" + ])) + warnings.extend( + validate_enum(self._resource, profile_name, "category", [ + "social-history","vital-signs","imaging","laboratory","procedure","survey","exam","therapy","activity" + ])) + warnings.extend( + validate_enum(self._resource, profile_name, "code", [ + "2708-6","29463-7","3140-1","3150-0","3151-8","39156-5","59408-5","59575-1","59576-9","77606-2","8287-5","8289-1","8302-2","8306-3","8310-5","8462-4","8478-0","8480-6","8867-4","9279-1","9843-4" + ])) + warnings.extend( + validate_enum(self._resource, profile_name, "dataAbsentReason", [ + "unknown","asked-unknown","temp-unknown","not-asked","asked-declined","masked","not-applicable","unsupported","as-text","error","not-a-number","negative-infinity","positive-infinity","not-performed","not-permitted" + ])) warnings.extend(validate_must_support(self._resource, profile_name, "dataAbsentReason")) warnings.extend(validate_must_support(self._resource, profile_name, "performer")) return {"errors": errors, "warnings": warnings} diff --git a/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/observation_uscore_body_weight_profile.py b/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/observation_uscore_body_weight_profile.py index ad926641..e766eb5e 100644 --- a/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/observation_uscore_body_weight_profile.py +++ b/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/observation_uscore_body_weight_profile.py @@ -215,36 +215,55 @@ def validate(self) -> dict[str, list[str]]: errors: list[str] = [] warnings: list[str] = [] errors.extend(validate_required(self._resource, profile_name, "status")) - errors.extend(validate_enum(self._resource, profile_name, "status", ["registered","preliminary","final","amended","corrected","cancelled","entered-in-error","unknown"])) + errors.extend( + validate_enum(self._resource, profile_name, "status", [ + "registered","preliminary","final","amended","corrected","cancelled","entered-in-error","unknown" + ])) errors.extend(validate_required(self._resource, profile_name, "category")) errors.extend(validate_slice_cardinality(self._resource, profile_name, "category", {"coding":[{"code":"vital-signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}, "VSCat", 1, 1)) errors.extend(validate_required(self._resource, profile_name, "code")) errors.extend(validate_fixed_value(self._resource, profile_name, "code", {"coding":[{"system":"http://loinc.org","code":"29463-7"}]})) errors.extend(validate_required(self._resource, profile_name, "subject")) - errors.extend(validate_reference(self._resource, profile_name, "subject", ["Patient"])) - errors.extend(validate_choice_required(self._resource, profile_name, ["effectiveDateTime","effectivePeriod"])) - errors.extend(validate_choice_prohibited(self._resource, profile_name, [ - "effectiveTiming", - "effectiveInstant", + errors.extend( + validate_reference(self._resource, profile_name, "subject", [ + "Patient" + ])) + errors.extend( + validate_choice_required(self._resource, profile_name, [ + "effectiveDateTime","effectivePeriod" + ])) + errors.extend( + validate_choice_prohibited(self._resource, profile_name, [ + "effectiveTiming","effectiveInstant" + ])) + errors.extend( + validate_reference(self._resource, profile_name, "hasMember", [ + "MolecularSequence","QuestionnaireResponse","Observation" + ])) + errors.extend( + validate_reference(self._resource, profile_name, "derivedFrom", [ + "DocumentReference","ImagingStudy","Media","MolecularSequence","QuestionnaireResponse","Observation" + ])) + errors.extend( + validate_reference(self._resource, profile_name, "performer", [ + "PractitionerRole","CareTeam","Organization","Patient","Practitioner","RelatedPerson" + ])) + errors.extend( + validate_choice_prohibited(self._resource, profile_name, [ + "valueCodeableConcept","valueString","valueBoolean","valueInteger","valueRange","valueRatio","valueSampledData","valueTime","valueDateTime","valuePeriod" + ])) + warnings.extend( + validate_enum(self._resource, profile_name, "category", [ + "social-history","vital-signs","imaging","laboratory","procedure","survey","exam","therapy","activity" + ])) + warnings.extend( + validate_enum(self._resource, profile_name, "code", [ + "2708-6","29463-7","3140-1","3150-0","3151-8","39156-5","59408-5","59575-1","59576-9","77606-2","8287-5","8289-1","8302-2","8306-3","8310-5","8462-4","8478-0","8480-6","8867-4","9279-1","9843-4" ])) - errors.extend(validate_reference(self._resource, profile_name, "hasMember", ["MolecularSequence","QuestionnaireResponse","Observation"])) - errors.extend(validate_reference(self._resource, profile_name, "derivedFrom", ["DocumentReference","ImagingStudy","Media","MolecularSequence","QuestionnaireResponse","Observation"])) - errors.extend(validate_reference(self._resource, profile_name, "performer", ["PractitionerRole","CareTeam","Organization","Patient","Practitioner","RelatedPerson"])) - errors.extend(validate_choice_prohibited(self._resource, profile_name, [ - "valueCodeableConcept", - "valueString", - "valueBoolean", - "valueInteger", - "valueRange", - "valueRatio", - "valueSampledData", - "valueTime", - "valueDateTime", - "valuePeriod", + warnings.extend( + validate_enum(self._resource, profile_name, "dataAbsentReason", [ + "unknown","asked-unknown","temp-unknown","not-asked","asked-declined","masked","not-applicable","unsupported","as-text","error","not-a-number","negative-infinity","positive-infinity","not-performed","not-permitted" ])) - warnings.extend(validate_enum(self._resource, profile_name, "category", ["social-history","vital-signs","imaging","laboratory","procedure","survey","exam","therapy","activity"])) - warnings.extend(validate_enum(self._resource, profile_name, "code", ["2708-6","29463-7","3140-1","3150-0","3151-8","39156-5","59408-5","59575-1","59576-9","77606-2","8287-5","8289-1","8302-2","8306-3","8310-5","8462-4","8478-0","8480-6","8867-4","9279-1","9843-4"])) - warnings.extend(validate_enum(self._resource, profile_name, "dataAbsentReason", ["unknown","asked-unknown","temp-unknown","not-asked","asked-declined","masked","not-applicable","unsupported","as-text","error","not-a-number","negative-infinity","positive-infinity","not-performed","not-permitted"])) warnings.extend(validate_must_support(self._resource, profile_name, "dataAbsentReason")) warnings.extend(validate_must_support(self._resource, profile_name, "performer")) return {"errors": errors, "warnings": warnings} diff --git a/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/observation_uscore_vital_signs_profile.py b/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/observation_uscore_vital_signs_profile.py index 9b8979b6..3e2c8c88 100644 --- a/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/observation_uscore_vital_signs_profile.py +++ b/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/observation_uscore_vital_signs_profile.py @@ -325,23 +325,50 @@ def validate(self) -> dict[str, list[str]]: errors: list[str] = [] warnings: list[str] = [] errors.extend(validate_required(self._resource, profile_name, "status")) - errors.extend(validate_enum(self._resource, profile_name, "status", ["registered","preliminary","final","amended","corrected","cancelled","entered-in-error","unknown"])) + errors.extend( + validate_enum(self._resource, profile_name, "status", [ + "registered","preliminary","final","amended","corrected","cancelled","entered-in-error","unknown" + ])) errors.extend(validate_required(self._resource, profile_name, "category")) errors.extend(validate_slice_cardinality(self._resource, profile_name, "category", {"coding":[{"code":"vital-signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}, "VSCat", 1, 1)) errors.extend(validate_required(self._resource, profile_name, "code")) errors.extend(validate_required(self._resource, profile_name, "subject")) - errors.extend(validate_reference(self._resource, profile_name, "subject", ["Patient"])) - errors.extend(validate_choice_required(self._resource, profile_name, ["effectiveDateTime","effectivePeriod"])) - errors.extend(validate_choice_prohibited(self._resource, profile_name, [ - "effectiveTiming", - "effectiveInstant", + errors.extend( + validate_reference(self._resource, profile_name, "subject", [ + "Patient" + ])) + errors.extend( + validate_choice_required(self._resource, profile_name, [ + "effectiveDateTime","effectivePeriod" + ])) + errors.extend( + validate_choice_prohibited(self._resource, profile_name, [ + "effectiveTiming","effectiveInstant" + ])) + errors.extend( + validate_reference(self._resource, profile_name, "hasMember", [ + "MolecularSequence","QuestionnaireResponse","Observation" + ])) + errors.extend( + validate_reference(self._resource, profile_name, "derivedFrom", [ + "DocumentReference","ImagingStudy","Media","MolecularSequence","QuestionnaireResponse","Observation" + ])) + errors.extend( + validate_reference(self._resource, profile_name, "performer", [ + "PractitionerRole","CareTeam","Organization","Patient","Practitioner","RelatedPerson" + ])) + warnings.extend( + validate_enum(self._resource, profile_name, "category", [ + "social-history","vital-signs","imaging","laboratory","procedure","survey","exam","therapy","activity" + ])) + warnings.extend( + validate_enum(self._resource, profile_name, "code", [ + "2708-6","29463-7","3140-1","3150-0","3151-8","39156-5","59408-5","59575-1","59576-9","77606-2","8287-5","8289-1","8302-2","8306-3","8310-5","8462-4","8478-0","8480-6","8867-4","9279-1","9843-4" + ])) + warnings.extend( + validate_enum(self._resource, profile_name, "dataAbsentReason", [ + "unknown","asked-unknown","temp-unknown","not-asked","asked-declined","masked","not-applicable","unsupported","as-text","error","not-a-number","negative-infinity","positive-infinity","not-performed","not-permitted" ])) - errors.extend(validate_reference(self._resource, profile_name, "hasMember", ["MolecularSequence","QuestionnaireResponse","Observation"])) - errors.extend(validate_reference(self._resource, profile_name, "derivedFrom", ["DocumentReference","ImagingStudy","Media","MolecularSequence","QuestionnaireResponse","Observation"])) - errors.extend(validate_reference(self._resource, profile_name, "performer", ["PractitionerRole","CareTeam","Organization","Patient","Practitioner","RelatedPerson"])) - warnings.extend(validate_enum(self._resource, profile_name, "category", ["social-history","vital-signs","imaging","laboratory","procedure","survey","exam","therapy","activity"])) - warnings.extend(validate_enum(self._resource, profile_name, "code", ["2708-6","29463-7","3140-1","3150-0","3151-8","39156-5","59408-5","59575-1","59576-9","77606-2","8287-5","8289-1","8302-2","8306-3","8310-5","8462-4","8478-0","8480-6","8867-4","9279-1","9843-4"])) - warnings.extend(validate_enum(self._resource, profile_name, "dataAbsentReason", ["unknown","asked-unknown","temp-unknown","not-asked","asked-declined","masked","not-applicable","unsupported","as-text","error","not-a-number","negative-infinity","positive-infinity","not-performed","not-permitted"])) warnings.extend(validate_must_support(self._resource, profile_name, "dataAbsentReason")) warnings.extend(validate_must_support(self._resource, profile_name, "performer")) return {"errors": errors, "warnings": warnings} From 2ed104a4900dfb286d16ba3692e52d96f360a809 Mon Sep 17 00:00:00 2001 From: Aleksandr Penskoi Date: Fri, 24 Jul 2026 16:51:09 +0400 Subject: [PATCH 12/16] feat(py): comment accessor reference targets with replaced profile URLs Python's Reference annotation carries no target types, so profile accessors get a trailing comment listing the resolved reference targets; profile targets replaced by their base resource keep the profile URL for traceability (port of the TypeScript writer's reference type comments). --- .../python/profile-factory.ts | 75 +++++++++++++++---- .../__snapshots__/python.test.ts.snap | 16 ++-- 2 files changed, 70 insertions(+), 21 deletions(-) diff --git a/src/api/writer-generator/python/profile-factory.ts b/src/api/writer-generator/python/profile-factory.ts index 1e04370d..14aee89c 100644 --- a/src/api/writer-generator/python/profile-factory.ts +++ b/src/api/writer-generator/python/profile-factory.ts @@ -22,8 +22,14 @@ import type { Python } from "./writer"; export type ProfileFactoryInfo = { autoFields: { name: string; value: string }[]; sliceAutoFields: { name: string; pyType: string; typeId: TypeIdentifier; sliceNames: string[] }[]; - params: { name: string; pyType: string; typeId: TypeIdentifier }[]; - accessors: { name: string; pyType: string; typeId: TypeIdentifier; choiceSiblings?: string[] }[]; + params: { name: string; pyType: string; typeId: TypeIdentifier; refComment?: string }[]; + accessors: { + name: string; + pyType: string; + typeId: TypeIdentifier; + choiceSiblings?: string[]; + refComment?: string; + }[]; }; // --------------------------------------------------------------------------- @@ -48,6 +54,27 @@ export const fieldPyType = ( return field.array ? `list[${base}]` : base; }; +/** Trailing `#` comment documenting a reference field's targets (the Python + * `Reference` annotation carries no target types). Profile targets are + * replaced by their base resource type; the profile URLs are kept in the + * comment to make server-side validation errors traceable. */ +export const pyReferenceComment = ( + field: RegularField | ChoiceFieldInstance, + resolveRef: TypeSchemaIndex["findLastSpecializationByIdentifier"], +): string | undefined => { + if (!field.reference || field.reference.resource.length === 0) return undefined; + const profilesByResource: Record = {}; + for (const profile of field.reference.profiles ?? []) { + (profilesByResource[resolveRef(profile).name] ??= []).push(profile.url); + } + const refs = field.reference.resource.map((original) => { + const name = resolveRef(original).name; + const profiles = profilesByResource[name]; + return profiles ? `${name}(${profiles.join(", ")})` : name; + }); + return ` # Reference[${refs.join(" | ")}]`; +}; + // --------------------------------------------------------------------------- // Factory info collection // --------------------------------------------------------------------------- @@ -58,6 +85,7 @@ const tryPromoteChoice = ( fields: Record, params: ProfileFactoryInfo["params"], promotedChoices: Set, + resolveRef: TypeSchemaIndex["findLastSpecializationByIdentifier"], ): void => { if (!isChoiceDeclarationField(field) || !field.required || field.choices.length !== 1) return; const choiceName = field.choices[0]; @@ -65,7 +93,12 @@ const tryPromoteChoice = ( const choiceField = fields[choiceName]; if (!choiceField || !isChoiceInstanceField(choiceField)) return; const pyType = pyTypeFromIdentifier(choiceField.type) + (choiceField.array ? "[]" : ""); - params.push({ name: choiceName, pyType, typeId: choiceField.type }); + params.push({ + name: choiceName, + pyType, + typeId: choiceField.type, + refComment: pyReferenceComment(choiceField, resolveRef), + }); promotedChoices.add(choiceName); }; @@ -87,7 +120,7 @@ const collectBaseRequiredParams = ( if (isChoiceDeclarationField(field)) continue; if (isNotChoiceDeclarationField(field) && field.type) { const pyType = fieldPyType(field, resolveRef); - params.push({ name, pyType, typeId: field.type }); + params.push({ name, pyType, typeId: field.type, refComment: pyReferenceComment(field, resolveRef) }); } } }; @@ -124,7 +157,7 @@ export const collectProfileFactoryInfo = ( } if (isChoiceDeclarationField(field)) { - tryPromoteChoice(field, fields, params, promotedChoices); + tryPromoteChoice(field, fields, params, promotedChoices, resolveRef); continue; } @@ -133,7 +166,12 @@ export const collectProfileFactoryInfo = ( autoFields.push({ name, value: field.array ? `[${value}]` : value }); if (isNotChoiceDeclarationField(field) && field.type) { const pyType = fieldPyType(field, resolveRef); - autoAccessors.push({ name, pyType, typeId: field.type }); + autoAccessors.push({ + name, + pyType, + typeId: field.type, + refComment: pyReferenceComment(field, resolveRef), + }); } continue; } @@ -144,7 +182,12 @@ export const collectProfileFactoryInfo = ( if (field.type) { const pyType = fieldPyType(field, resolveRef); sliceAutoFields.push({ name, pyType, typeId: field.type, sliceNames }); - autoAccessors.push({ name, pyType, typeId: field.type }); + autoAccessors.push({ + name, + pyType, + typeId: field.type, + refComment: pyReferenceComment(field, resolveRef), + }); } continue; } @@ -152,7 +195,7 @@ export const collectProfileFactoryInfo = ( if (field.required) { const pyType = fieldPyType(field, resolveRef); - params.push({ name, pyType, typeId: field.type }); + params.push({ name, pyType, typeId: field.type, refComment: pyReferenceComment(field, resolveRef) }); } } @@ -168,7 +211,13 @@ export const collectProfileFactoryInfo = ( if (promotedChoices.has(name)) continue; const pyType = pyTypeFromIdentifier(field.type) + (field.array ? "[]" : ""); const choiceSiblings = (choiceGroups.get(name) ?? []).filter((s) => s !== name && !promotedChoices.has(s)); - choiceAccessors.push({ name, pyType, typeId: field.type, choiceSiblings }); + choiceAccessors.push({ + name, + pyType, + typeId: field.type, + choiceSiblings, + refComment: pyReferenceComment(field, resolveRef), + }); } return { autoFields, sliceAutoFields, params, accessors: [...autoAccessors, ...choiceAccessors] }; @@ -280,12 +329,12 @@ export const generateFieldAccessors = ( for (const p of factoryInfo.params) { const fieldName = pyFieldName(p.name, fmt); const methodSuffix = pySnakeName(p.name); - w.line(`def get_${methodSuffix}(self) -> ${p.pyType} | None:`); + w.line(`def get_${methodSuffix}(self) -> ${p.pyType} | None:${p.refComment ?? ""}`); w.indentBlock(() => { w.line(`return cast('${p.pyType} | None', getattr(self._resource, ${JSON.stringify(fieldName)}, None))`); }); w.line(); - w.line(`def set_${methodSuffix}(self, value: ${p.pyType}) -> "${className}":`); + w.line(`def set_${methodSuffix}(self, value: ${p.pyType}) -> "${className}":${p.refComment ?? ""}`); w.indentBlock(() => { w.line(`setattr(self._resource, ${JSON.stringify(fieldName)}, value)`); w.line("return self"); @@ -297,12 +346,12 @@ export const generateFieldAccessors = ( const methodSuffix = pySnakeName(a.name); if (extSliceMethodBaseNames.has(methodSuffix)) continue; const fieldName = pyFieldName(a.name, fmt); - w.line(`def get_${methodSuffix}(self) -> ${a.pyType} | None:`); + w.line(`def get_${methodSuffix}(self) -> ${a.pyType} | None:${a.refComment ?? ""}`); w.indentBlock(() => { w.line(`return cast('${a.pyType} | None', getattr(self._resource, ${JSON.stringify(fieldName)}, None))`); }); w.line(); - w.line(`def set_${methodSuffix}(self, value: ${a.pyType}) -> "${className}":`); + w.line(`def set_${methodSuffix}(self, value: ${a.pyType}) -> "${className}":${a.refComment ?? ""}`); w.indentBlock(() => { if (a.choiceSiblings?.length) { for (const sibling of a.choiceSiblings) { diff --git a/test/api/write-generator/__snapshots__/python.test.ts.snap b/test/api/write-generator/__snapshots__/python.test.ts.snap index 13cb897b..8d244545 100644 --- a/test/api/write-generator/__snapshots__/python.test.ts.snap +++ b/test/api/write-generator/__snapshots__/python.test.ts.snap @@ -486,10 +486,10 @@ class ObservationBodyweightProfile: setattr(self._resource, "status", value) return self - def get_subject(self) -> Reference | None: + def get_subject(self) -> Reference | None: # Reference[Patient] return cast('Reference | None', getattr(self._resource, "subject", None)) - def set_subject(self, value: Reference) -> "ObservationBodyweightProfile": + def set_subject(self, value: Reference) -> "ObservationBodyweightProfile": # Reference[Patient] setattr(self._resource, "subject", value) return self @@ -695,10 +695,10 @@ class ObservationBpProfile: setattr(self._resource, "status", value) return self - def get_subject(self) -> Reference | None: + def get_subject(self) -> Reference | None: # Reference[Patient] return cast('Reference | None', getattr(self._resource, "subject", None)) - def set_subject(self, value: Reference) -> "ObservationBpProfile": + def set_subject(self, value: Reference) -> "ObservationBpProfile": # Reference[Patient] setattr(self._resource, "subject", value) return self @@ -1232,10 +1232,10 @@ class UscoreBloodPressureProfile: setattr(self._resource, "status", value) return self - def get_subject(self) -> Reference | None: + def get_subject(self) -> Reference | None: # Reference[Patient(http://hl7.org/fhir/us/core/StructureDefinition/us-core-patient)] return cast('Reference | None', getattr(self._resource, "subject", None)) - def set_subject(self, value: Reference) -> "UscoreBloodPressureProfile": + def set_subject(self, value: Reference) -> "UscoreBloodPressureProfile": # Reference[Patient(http://hl7.org/fhir/us/core/StructureDefinition/us-core-patient)] setattr(self._resource, "subject", value) return self @@ -1673,10 +1673,10 @@ class UscoreBodyWeightProfile: setattr(self._resource, "status", value) return self - def get_subject(self) -> Reference | None: + def get_subject(self) -> Reference | None: # Reference[Patient(http://hl7.org/fhir/us/core/StructureDefinition/us-core-patient)] return cast('Reference | None', getattr(self._resource, "subject", None)) - def set_subject(self, value: Reference) -> "UscoreBodyWeightProfile": + def set_subject(self, value: Reference) -> "UscoreBodyWeightProfile": # Reference[Patient(http://hl7.org/fhir/us/core/StructureDefinition/us-core-patient)] setattr(self._resource, "subject", value) return self From 54fbb70094600fac8d0c142f009351917e3af8ab Mon Sep 17 00:00:00 2001 From: Aleksandr Penskoi Date: Fri, 24 Jul 2026 16:51:09 +0400 Subject: [PATCH 13/16] chore(examples): regenerate python-r4-us-core with reference target comments --- .../profiles/observation_observation_bodyweight.py | 4 ++-- .../profiles/observation_observation_vitalsigns.py | 4 ++-- .../profiles/observation_uscore_blood_pressure_profile.py | 4 ++-- .../profiles/observation_uscore_body_weight_profile.py | 4 ++-- .../profiles/observation_uscore_vital_signs_profile.py | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/examples/python-r4-us-core/fhir_types/hl7_fhir_r4_core/profiles/observation_observation_bodyweight.py b/examples/python-r4-us-core/fhir_types/hl7_fhir_r4_core/profiles/observation_observation_bodyweight.py index 2ab344f0..af9a3042 100644 --- a/examples/python-r4-us-core/fhir_types/hl7_fhir_r4_core/profiles/observation_observation_bodyweight.py +++ b/examples/python-r4-us-core/fhir_types/hl7_fhir_r4_core/profiles/observation_observation_bodyweight.py @@ -73,10 +73,10 @@ def set_status(self, value: Literal["registered", "preliminary", "final", "amend setattr(self._resource, "status", value) return self - def get_subject(self) -> Reference | None: + def get_subject(self) -> Reference | None: # Reference[Patient] return cast('Reference | None', getattr(self._resource, "subject", None)) - def set_subject(self, value: Reference) -> "ObservationBodyweightProfile": + def set_subject(self, value: Reference) -> "ObservationBodyweightProfile": # Reference[Patient] setattr(self._resource, "subject", value) return self diff --git a/examples/python-r4-us-core/fhir_types/hl7_fhir_r4_core/profiles/observation_observation_vitalsigns.py b/examples/python-r4-us-core/fhir_types/hl7_fhir_r4_core/profiles/observation_observation_vitalsigns.py index 4c1b7fa6..85852811 100644 --- a/examples/python-r4-us-core/fhir_types/hl7_fhir_r4_core/profiles/observation_observation_vitalsigns.py +++ b/examples/python-r4-us-core/fhir_types/hl7_fhir_r4_core/profiles/observation_observation_vitalsigns.py @@ -80,10 +80,10 @@ def set_code(self, value: CodeableConcept) -> "ObservationVitalsignsProfile": setattr(self._resource, "code", value) return self - def get_subject(self) -> Reference | None: + def get_subject(self) -> Reference | None: # Reference[Patient] return cast('Reference | None', getattr(self._resource, "subject", None)) - def set_subject(self, value: Reference) -> "ObservationVitalsignsProfile": + def set_subject(self, value: Reference) -> "ObservationVitalsignsProfile": # Reference[Patient] setattr(self._resource, "subject", value) return self diff --git a/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/observation_uscore_blood_pressure_profile.py b/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/observation_uscore_blood_pressure_profile.py index d9fc0b45..d30a79e1 100644 --- a/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/observation_uscore_blood_pressure_profile.py +++ b/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/observation_uscore_blood_pressure_profile.py @@ -85,10 +85,10 @@ def set_status(self, value: Literal["registered", "preliminary", "final", "amend setattr(self._resource, "status", value) return self - def get_subject(self) -> Reference | None: + def get_subject(self) -> Reference | None: # Reference[Patient(http://hl7.org/fhir/us/core/StructureDefinition/us-core-patient)] return cast('Reference | None', getattr(self._resource, "subject", None)) - def set_subject(self, value: Reference) -> "UscoreBloodPressureProfile": + def set_subject(self, value: Reference) -> "UscoreBloodPressureProfile": # Reference[Patient(http://hl7.org/fhir/us/core/StructureDefinition/us-core-patient)] setattr(self._resource, "subject", value) return self diff --git a/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/observation_uscore_body_weight_profile.py b/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/observation_uscore_body_weight_profile.py index e766eb5e..60995cdb 100644 --- a/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/observation_uscore_body_weight_profile.py +++ b/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/observation_uscore_body_weight_profile.py @@ -75,10 +75,10 @@ def set_status(self, value: Literal["registered", "preliminary", "final", "amend setattr(self._resource, "status", value) return self - def get_subject(self) -> Reference | None: + def get_subject(self) -> Reference | None: # Reference[Patient(http://hl7.org/fhir/us/core/StructureDefinition/us-core-patient)] return cast('Reference | None', getattr(self._resource, "subject", None)) - def set_subject(self, value: Reference) -> "UscoreBodyWeightProfile": + def set_subject(self, value: Reference) -> "UscoreBodyWeightProfile": # Reference[Patient(http://hl7.org/fhir/us/core/StructureDefinition/us-core-patient)] setattr(self._resource, "subject", value) return self diff --git a/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/observation_uscore_vital_signs_profile.py b/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/observation_uscore_vital_signs_profile.py index 3e2c8c88..d0687722 100644 --- a/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/observation_uscore_vital_signs_profile.py +++ b/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/observation_uscore_vital_signs_profile.py @@ -82,10 +82,10 @@ def set_code(self, value: CodeableConcept) -> "UscoreVitalSignsProfile": setattr(self._resource, "code", value) return self - def get_subject(self) -> Reference | None: + def get_subject(self) -> Reference | None: # Reference[Patient(http://hl7.org/fhir/us/core/StructureDefinition/us-core-patient)] return cast('Reference | None', getattr(self._resource, "subject", None)) - def set_subject(self, value: Reference) -> "UscoreVitalSignsProfile": + def set_subject(self, value: Reference) -> "UscoreVitalSignsProfile": # Reference[Patient(http://hl7.org/fhir/us/core/StructureDefinition/us-core-patient)] setattr(self._resource, "subject", value) return self From 6a4933088d28dfefabf91ba73f13aa3f668172d8 Mon Sep 17 00:00:00 2001 From: Aleksandr Penskoi Date: Fri, 24 Jul 2026 17:13:34 +0400 Subject: [PATCH 14/16] feat(py): parametrize Reference by target resource types MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reference becomes Generic[T] (type: T | None) via the existing Coding/CodeableConcept rewrite machinery, and reference fields are annotated as Reference[Literal["Patient", ...]] in models and profile accessors — mirroring the TypeScript Reference<"Patient" | ...>. Targets resolving to a family type (e.g. Resource) keep the bare Reference. Accessor comments now carry only the replaced profile target URLs. --- .../writer-generator/python/naming-utils.ts | 22 +++++ .../python/profile-factory.ts | 82 +++++++++---------- src/api/writer-generator/python/writer.ts | 8 ++ 3 files changed, 67 insertions(+), 45 deletions(-) diff --git a/src/api/writer-generator/python/naming-utils.ts b/src/api/writer-generator/python/naming-utils.ts index 6decb290..fe5f26c3 100644 --- a/src/api/writer-generator/python/naming-utils.ts +++ b/src/api/writer-generator/python/naming-utils.ts @@ -1,4 +1,6 @@ import { pascalCase, snakeCase, uppercaseFirstLetterOfEach } from "@root/api/writer-generator/utils"; +import type { TypeSchemaIndex } from "@root/typeschema/utils"; +import type { ChoiceFieldInstance, RegularField } from "@typeschema/types.ts"; import { isPrimitiveIdentifier, type TypeIdentifier } from "@typeschema/types.ts"; export const PRIMITIVE_TYPE_MAP: Record = { @@ -121,3 +123,23 @@ export const pyTypeFromIdentifier = (id: TypeIdentifier): string => { if (prim !== undefined) return prim; return deriveResourceName(id); }; + +/** `Literal[...]` type argument for a `Reference` field's targets, mirroring + * the TypeScript writer's `Reference<"Patient" | ...>`. Returns undefined + * when there are no targets or a target is a family type (e.g. `Resource`), + * where the bare `Reference` (defaulting to `str`) is the right annotation. */ +export const pyReferenceTypeParam = ( + field: RegularField | ChoiceFieldInstance, + tsIndex: TypeSchemaIndex, +): string | undefined => { + if (!field.reference || field.reference.resource.length === 0) return undefined; + const isFamilyType = (ref: TypeIdentifier): boolean => { + const schema = tsIndex.resolveType(ref); + if (!schema || !("typeFamily" in schema)) return false; + return (schema.typeFamily?.resources?.length ?? 0) > 0; + }; + const resolved = field.reference.resource.map((ref) => tsIndex.findLastSpecializationByIdentifier(ref)); + if (resolved.some(isFamilyType)) return undefined; + const names = [...new Set(resolved.map((ref) => ref.name))]; + return `Literal[${names.map((n) => JSON.stringify(n)).join(", ")}]`; +}; diff --git a/src/api/writer-generator/python/profile-factory.ts b/src/api/writer-generator/python/profile-factory.ts index 14aee89c..b7ca5f40 100644 --- a/src/api/writer-generator/python/profile-factory.ts +++ b/src/api/writer-generator/python/profile-factory.ts @@ -10,7 +10,7 @@ import { type TypeIdentifier, } from "@root/typeschema/types"; import type { TypeSchemaIndex } from "@root/typeschema/utils"; -import { pyTypeFromIdentifier } from "./naming-utils"; +import { pyReferenceTypeParam, pyTypeFromIdentifier } from "./naming-utils"; import { pyFieldName, pySliceStaticName, pySnakeName } from "./profile-naming"; import { collectRequiredSliceNames } from "./profile-slices"; import type { Python } from "./writer"; @@ -44,35 +44,27 @@ export type ProfileFactoryInfo = { export const fieldPyType = ( field: RegularField | ChoiceFieldInstance, resolveRef?: TypeSchemaIndex["findLastSpecializationByIdentifier"], + tsIndex?: TypeSchemaIndex, ): string => { const resolved = resolveRef ? resolveRef(field.type) : field.type; - const base = pyTypeFromIdentifier(resolved); + let base = pyTypeFromIdentifier(resolved); if (base === "str" && field.enum && !field.enum.isOpen && field.enum.values.length > 0) { const literal = `Literal[${field.enum.values.map((v) => JSON.stringify(v)).join(", ")}]`; return field.array ? `list[${literal}]` : literal; } + if (base === "Reference" && tsIndex) { + const typeParam = pyReferenceTypeParam(field, tsIndex); + if (typeParam) base = `Reference[${typeParam}]`; + } return field.array ? `list[${base}]` : base; }; -/** Trailing `#` comment documenting a reference field's targets (the Python - * `Reference` annotation carries no target types). Profile targets are - * replaced by their base resource type; the profile URLs are kept in the - * comment to make server-side validation errors traceable. */ -export const pyReferenceComment = ( - field: RegularField | ChoiceFieldInstance, - resolveRef: TypeSchemaIndex["findLastSpecializationByIdentifier"], -): string | undefined => { - if (!field.reference || field.reference.resource.length === 0) return undefined; - const profilesByResource: Record = {}; - for (const profile of field.reference.profiles ?? []) { - (profilesByResource[resolveRef(profile).name] ??= []).push(profile.url); - } - const refs = field.reference.resource.map((original) => { - const name = resolveRef(original).name; - const profiles = profilesByResource[name]; - return profiles ? `${name}(${profiles.join(", ")})` : name; - }); - return ` # Reference[${refs.join(" | ")}]`; +/** Trailing `#` comment with the profile URLs of a reference field's targets. + * Profile targets are replaced by their base resource type in the annotation; + * the URLs are kept here to make server-side validation errors traceable. */ +export const pyReferenceComment = (field: RegularField | ChoiceFieldInstance): string | undefined => { + const urls = (field.reference?.profiles ?? []).map((profile) => profile.url); + return urls.length > 0 ? ` # ${urls.join(", ")}` : undefined; }; // --------------------------------------------------------------------------- @@ -85,23 +77,33 @@ const tryPromoteChoice = ( fields: Record, params: ProfileFactoryInfo["params"], promotedChoices: Set, - resolveRef: TypeSchemaIndex["findLastSpecializationByIdentifier"], + tsIndex: TypeSchemaIndex, ): void => { if (!isChoiceDeclarationField(field) || !field.required || field.choices.length !== 1) return; const choiceName = field.choices[0]; if (!choiceName) return; const choiceField = fields[choiceName]; if (!choiceField || !isChoiceInstanceField(choiceField)) return; - const pyType = pyTypeFromIdentifier(choiceField.type) + (choiceField.array ? "[]" : ""); + const pyType = pyChoiceInstanceType(choiceField, tsIndex); params.push({ name: choiceName, pyType, typeId: choiceField.type, - refComment: pyReferenceComment(choiceField, resolveRef), + refComment: pyReferenceComment(choiceField), }); promotedChoices.add(choiceName); }; +/** Python type for a choice variant, with Reference targets parametrized. */ +const pyChoiceInstanceType = (field: ChoiceFieldInstance, tsIndex: TypeSchemaIndex): string => { + let base = pyTypeFromIdentifier(field.type); + if (base === "Reference") { + const typeParam = pyReferenceTypeParam(field, tsIndex); + if (typeParam) base = `Reference[${typeParam}]`; + } + return base + (field.array ? "[]" : ""); +}; + /** Include base-type required fields not already covered by profile constraints. */ const collectBaseRequiredParams = ( tsIndex: TypeSchemaIndex, @@ -119,8 +121,8 @@ const collectBaseRequiredParams = ( if (isChoiceInstanceField(field)) continue; if (isChoiceDeclarationField(field)) continue; if (isNotChoiceDeclarationField(field) && field.type) { - const pyType = fieldPyType(field, resolveRef); - params.push({ name, pyType, typeId: field.type, refComment: pyReferenceComment(field, resolveRef) }); + const pyType = fieldPyType(field, resolveRef, tsIndex); + params.push({ name, pyType, typeId: field.type, refComment: pyReferenceComment(field) }); } } }; @@ -157,7 +159,7 @@ export const collectProfileFactoryInfo = ( } if (isChoiceDeclarationField(field)) { - tryPromoteChoice(field, fields, params, promotedChoices, resolveRef); + tryPromoteChoice(field, fields, params, promotedChoices, tsIndex); continue; } @@ -165,13 +167,8 @@ export const collectProfileFactoryInfo = ( const value = JSON.stringify(field.valueConstraint.value); autoFields.push({ name, value: field.array ? `[${value}]` : value }); if (isNotChoiceDeclarationField(field) && field.type) { - const pyType = fieldPyType(field, resolveRef); - autoAccessors.push({ - name, - pyType, - typeId: field.type, - refComment: pyReferenceComment(field, resolveRef), - }); + const pyType = fieldPyType(field, resolveRef, tsIndex); + autoAccessors.push({ name, pyType, typeId: field.type, refComment: pyReferenceComment(field) }); } continue; } @@ -180,22 +177,17 @@ export const collectProfileFactoryInfo = ( const sliceNames = collectRequiredSliceNames(field); if (sliceNames) { if (field.type) { - const pyType = fieldPyType(field, resolveRef); + const pyType = fieldPyType(field, resolveRef, tsIndex); sliceAutoFields.push({ name, pyType, typeId: field.type, sliceNames }); - autoAccessors.push({ - name, - pyType, - typeId: field.type, - refComment: pyReferenceComment(field, resolveRef), - }); + autoAccessors.push({ name, pyType, typeId: field.type, refComment: pyReferenceComment(field) }); } continue; } } if (field.required) { - const pyType = fieldPyType(field, resolveRef); - params.push({ name, pyType, typeId: field.type, refComment: pyReferenceComment(field, resolveRef) }); + const pyType = fieldPyType(field, resolveRef, tsIndex); + params.push({ name, pyType, typeId: field.type, refComment: pyReferenceComment(field) }); } } @@ -209,14 +201,14 @@ export const collectProfileFactoryInfo = ( const choiceAccessors: ProfileFactoryInfo["accessors"] = []; for (const [name, field] of pendingChoiceInstances) { if (promotedChoices.has(name)) continue; - const pyType = pyTypeFromIdentifier(field.type) + (field.array ? "[]" : ""); + const pyType = pyChoiceInstanceType(field, tsIndex); const choiceSiblings = (choiceGroups.get(name) ?? []).filter((s) => s !== name && !promotedChoices.has(s)); choiceAccessors.push({ name, pyType, typeId: field.type, choiceSiblings, - refComment: pyReferenceComment(field, resolveRef), + refComment: pyReferenceComment(field), }); } diff --git a/src/api/writer-generator/python/writer.ts b/src/api/writer-generator/python/writer.ts index bb8e4a9c..3ed991cb 100644 --- a/src/api/writer-generator/python/writer.ts +++ b/src/api/writer-generator/python/writer.ts @@ -24,6 +24,7 @@ import { type SpecializationTypeSchema, type TypeIdentifier, } from "@typeschema/types.ts"; +import { pyReferenceTypeParam } from "./naming-utils"; import { generateNewProfiles } from "./profile"; export const resolvePyAssets = (fn: string) => { @@ -48,6 +49,7 @@ const MAX_IMPORT_LINE_LENGTH = 100; const GENERIC_FIELD_REWRITES: Record> = { Coding: { code: "T" }, CodeableConcept: { coding: "Coding[T]" }, + Reference: { type: "T" }, }; const leafOf = (path: string[]): string => path[path.length - 1] ?? ""; @@ -590,6 +592,12 @@ export class Python extends Writer { } } + if (fieldType === "Reference" && "reference" in field && field.reference) { + assert(this.tsIndex !== undefined); + const typeParam = pyReferenceTypeParam(field, this.tsIndex); + if (typeParam) fieldType = `Reference[${typeParam}]`; + } + if (field.array) { fieldType = `PyList[${fieldType}]`; } From 054683fa9fe2bed8d429fd67a90e3124b7219704 Mon Sep 17 00:00:00 2001 From: Aleksandr Penskoi Date: Fri, 24 Jul 2026 17:13:34 +0400 Subject: [PATCH 15/16] test(py): update snapshots for parametrized Reference types --- .../__snapshots__/python.test.ts.snap | 48 +++++++++---------- .../__snapshots__/local-package.test.ts.snap | 10 ++-- 2 files changed, 29 insertions(+), 29 deletions(-) diff --git a/test/api/write-generator/__snapshots__/python.test.ts.snap b/test/api/write-generator/__snapshots__/python.test.ts.snap index 8d244545..98e4389a 100644 --- a/test/api/write-generator/__snapshots__/python.test.ts.snap +++ b/test/api/write-generator/__snapshots__/python.test.ts.snap @@ -144,14 +144,14 @@ class PatientContact(BackboneElement): address: Address | None = Field(None, alias="address", serialization_alias="address") gender: Literal["male", "female", "other", "unknown"] | None = Field(None, alias="gender", serialization_alias="gender") name: HumanName | None = Field(None, alias="name", serialization_alias="name") - organization: Reference | None = Field(None, alias="organization", serialization_alias="organization") + organization: Reference[Literal["Organization"]] | None = Field(None, alias="organization", serialization_alias="organization") period: Period | None = Field(None, alias="period", serialization_alias="period") relationship: PyList[CodeableConcept] | None = Field(None, alias="relationship", serialization_alias="relationship") telecom: PyList[ContactPoint] | None = Field(None, alias="telecom", serialization_alias="telecom") class PatientLink(BackboneElement): model_config = ConfigDict(validate_by_name=True, serialize_by_alias=True, extra="forbid") - other: Reference = Field(alias="other", serialization_alias="other") + other: Reference[Literal["Patient", "RelatedPerson"]] = Field(alias="other", serialization_alias="other") type: Literal["replaced-by", "replaces", "refer", "seealso"] = Field(alias="type", serialization_alias="type") @@ -172,10 +172,10 @@ class Patient(DomainResource): deceasedBoolean: bool | None = Field(None, alias="deceasedBoolean", serialization_alias="deceasedBoolean") deceasedDateTime: str | None = Field(None, alias="deceasedDateTime", serialization_alias="deceasedDateTime") gender: Literal["male", "female", "other", "unknown"] | None = Field(None, alias="gender", serialization_alias="gender") - generalPractitioner: PyList[Reference] | None = Field(None, alias="generalPractitioner", serialization_alias="generalPractitioner") + generalPractitioner: PyList[Reference[Literal["Organization", "Practitioner", "PractitionerRole"]]] | None = Field(None, alias="generalPractitioner", serialization_alias="generalPractitioner") identifier: PyList[Identifier] | None = Field(None, alias="identifier", serialization_alias="identifier") link: PyList[PatientLink] | None = Field(None, alias="link", serialization_alias="link") - managingOrganization: Reference | None = Field(None, alias="managingOrganization", serialization_alias="managingOrganization") + managingOrganization: Reference[Literal["Organization"]] | None = Field(None, alias="managingOrganization", serialization_alias="managingOrganization") maritalStatus: CodeableConcept[Literal["A", "D", "I", "L", "M", "P", "S", "T", "U", "W", "UNK"] | str] | None = Field(None, alias="maritalStatus", serialization_alias="maritalStatus") multipleBirthBoolean: bool | None = Field(None, alias="multipleBirthBoolean", serialization_alias="multipleBirthBoolean") multipleBirthInteger: int | None = Field(None, alias="multipleBirthInteger", serialization_alias="multipleBirthInteger") @@ -459,7 +459,7 @@ class ObservationBodyweightProfile: return cls(resource) @classmethod - def create_resource(cls, *, category: list[CodeableConcept] | None = None, status: Literal["registered", "preliminary", "final", "amended", "corrected", "cancelled", "entered-in-error", "unknown"], subject: Reference) -> Observation: + def create_resource(cls, *, category: list[CodeableConcept] | None = None, status: Literal["registered", "preliminary", "final", "amended", "corrected", "cancelled", "entered-in-error", "unknown"], subject: Reference[Literal["Patient"]]) -> Observation: category_with_defaults = ensure_slice_defaults(list(category or []), cls._vscat_slice_match) return build_resource( @@ -473,7 +473,7 @@ class ObservationBodyweightProfile: ) @classmethod - def create(cls, *, category: list[CodeableConcept] | None = None, status: Literal["registered", "preliminary", "final", "amended", "corrected", "cancelled", "entered-in-error", "unknown"], subject: Reference) -> "ObservationBodyweightProfile": + def create(cls, *, category: list[CodeableConcept] | None = None, status: Literal["registered", "preliminary", "final", "amended", "corrected", "cancelled", "entered-in-error", "unknown"], subject: Reference[Literal["Patient"]]) -> "ObservationBodyweightProfile": return cls.apply(cls.create_resource(category=category, status=status, subject=subject)) def to_resource(self) -> Observation: @@ -486,10 +486,10 @@ class ObservationBodyweightProfile: setattr(self._resource, "status", value) return self - def get_subject(self) -> Reference | None: # Reference[Patient] - return cast('Reference | None', getattr(self._resource, "subject", None)) + def get_subject(self) -> Reference[Literal["Patient"]] | None: + return cast('Reference[Literal["Patient"]] | None', getattr(self._resource, "subject", None)) - def set_subject(self, value: Reference) -> "ObservationBodyweightProfile": # Reference[Patient] + def set_subject(self, value: Reference[Literal["Patient"]]) -> "ObservationBodyweightProfile": setattr(self._resource, "subject", value) return self @@ -662,7 +662,7 @@ class ObservationBpProfile: return cls(resource) @classmethod - def create_resource(cls, *, category: list[CodeableConcept] | None = None, component: list[BackboneElement] | None = None, status: Literal["registered", "preliminary", "final", "amended", "corrected", "cancelled", "entered-in-error", "unknown"], subject: Reference) -> Observation: + def create_resource(cls, *, category: list[CodeableConcept] | None = None, component: list[BackboneElement] | None = None, status: Literal["registered", "preliminary", "final", "amended", "corrected", "cancelled", "entered-in-error", "unknown"], subject: Reference[Literal["Patient"]]) -> Observation: category_with_defaults = ensure_slice_defaults(list(category or []), cls._vscat_slice_match) component_with_defaults = ensure_slice_defaults( list(component or []), @@ -682,7 +682,7 @@ class ObservationBpProfile: ) @classmethod - def create(cls, *, category: list[CodeableConcept] | None = None, component: list[BackboneElement] | None = None, status: Literal["registered", "preliminary", "final", "amended", "corrected", "cancelled", "entered-in-error", "unknown"], subject: Reference) -> "ObservationBpProfile": + def create(cls, *, category: list[CodeableConcept] | None = None, component: list[BackboneElement] | None = None, status: Literal["registered", "preliminary", "final", "amended", "corrected", "cancelled", "entered-in-error", "unknown"], subject: Reference[Literal["Patient"]]) -> "ObservationBpProfile": return cls.apply(cls.create_resource(category=category, component=component, status=status, subject=subject)) def to_resource(self) -> Observation: @@ -695,10 +695,10 @@ class ObservationBpProfile: setattr(self._resource, "status", value) return self - def get_subject(self) -> Reference | None: # Reference[Patient] - return cast('Reference | None', getattr(self._resource, "subject", None)) + def get_subject(self) -> Reference[Literal["Patient"]] | None: + return cast('Reference[Literal["Patient"]] | None', getattr(self._resource, "subject", None)) - def set_subject(self, value: Reference) -> "ObservationBpProfile": # Reference[Patient] + def set_subject(self, value: Reference[Literal["Patient"]]) -> "ObservationBpProfile": setattr(self._resource, "subject", value) return self @@ -1199,7 +1199,7 @@ class UscoreBloodPressureProfile: return cls(resource) @classmethod - def create_resource(cls, *, category: list[CodeableConcept] | None = None, component: list[BackboneElement] | None = None, status: Literal["registered", "preliminary", "final", "amended", "corrected", "cancelled", "entered-in-error", "unknown"], subject: Reference) -> Observation: + def create_resource(cls, *, category: list[CodeableConcept] | None = None, component: list[BackboneElement] | None = None, status: Literal["registered", "preliminary", "final", "amended", "corrected", "cancelled", "entered-in-error", "unknown"], subject: Reference[Literal["Patient"]]) -> Observation: category_with_defaults = ensure_slice_defaults(list(category or []), cls._vscat_slice_match) component_with_defaults = ensure_slice_defaults( list(component or []), @@ -1219,7 +1219,7 @@ class UscoreBloodPressureProfile: ) @classmethod - def create(cls, *, category: list[CodeableConcept] | None = None, component: list[BackboneElement] | None = None, status: Literal["registered", "preliminary", "final", "amended", "corrected", "cancelled", "entered-in-error", "unknown"], subject: Reference) -> "UscoreBloodPressureProfile": + def create(cls, *, category: list[CodeableConcept] | None = None, component: list[BackboneElement] | None = None, status: Literal["registered", "preliminary", "final", "amended", "corrected", "cancelled", "entered-in-error", "unknown"], subject: Reference[Literal["Patient"]]) -> "UscoreBloodPressureProfile": return cls.apply(cls.create_resource(category=category, component=component, status=status, subject=subject)) def to_resource(self) -> Observation: @@ -1232,10 +1232,10 @@ class UscoreBloodPressureProfile: setattr(self._resource, "status", value) return self - def get_subject(self) -> Reference | None: # Reference[Patient(http://hl7.org/fhir/us/core/StructureDefinition/us-core-patient)] - return cast('Reference | None', getattr(self._resource, "subject", None)) + def get_subject(self) -> Reference[Literal["Patient"]] | None: # http://hl7.org/fhir/us/core/StructureDefinition/us-core-patient + return cast('Reference[Literal["Patient"]] | None', getattr(self._resource, "subject", None)) - def set_subject(self, value: Reference) -> "UscoreBloodPressureProfile": # Reference[Patient(http://hl7.org/fhir/us/core/StructureDefinition/us-core-patient)] + def set_subject(self, value: Reference[Literal["Patient"]]) -> "UscoreBloodPressureProfile": # http://hl7.org/fhir/us/core/StructureDefinition/us-core-patient setattr(self._resource, "subject", value) return self @@ -1646,7 +1646,7 @@ class UscoreBodyWeightProfile: return cls(resource) @classmethod - def create_resource(cls, *, category: list[CodeableConcept] | None = None, status: Literal["registered", "preliminary", "final", "amended", "corrected", "cancelled", "entered-in-error", "unknown"], subject: Reference) -> Observation: + def create_resource(cls, *, category: list[CodeableConcept] | None = None, status: Literal["registered", "preliminary", "final", "amended", "corrected", "cancelled", "entered-in-error", "unknown"], subject: Reference[Literal["Patient"]]) -> Observation: category_with_defaults = ensure_slice_defaults(list(category or []), cls._vscat_slice_match) return build_resource( @@ -1660,7 +1660,7 @@ class UscoreBodyWeightProfile: ) @classmethod - def create(cls, *, category: list[CodeableConcept] | None = None, status: Literal["registered", "preliminary", "final", "amended", "corrected", "cancelled", "entered-in-error", "unknown"], subject: Reference) -> "UscoreBodyWeightProfile": + def create(cls, *, category: list[CodeableConcept] | None = None, status: Literal["registered", "preliminary", "final", "amended", "corrected", "cancelled", "entered-in-error", "unknown"], subject: Reference[Literal["Patient"]]) -> "UscoreBodyWeightProfile": return cls.apply(cls.create_resource(category=category, status=status, subject=subject)) def to_resource(self) -> Observation: @@ -1673,10 +1673,10 @@ class UscoreBodyWeightProfile: setattr(self._resource, "status", value) return self - def get_subject(self) -> Reference | None: # Reference[Patient(http://hl7.org/fhir/us/core/StructureDefinition/us-core-patient)] - return cast('Reference | None', getattr(self._resource, "subject", None)) + def get_subject(self) -> Reference[Literal["Patient"]] | None: # http://hl7.org/fhir/us/core/StructureDefinition/us-core-patient + return cast('Reference[Literal["Patient"]] | None', getattr(self._resource, "subject", None)) - def set_subject(self, value: Reference) -> "UscoreBodyWeightProfile": # Reference[Patient(http://hl7.org/fhir/us/core/StructureDefinition/us-core-patient)] + def set_subject(self, value: Reference[Literal["Patient"]]) -> "UscoreBodyWeightProfile": # http://hl7.org/fhir/us/core/StructureDefinition/us-core-patient setattr(self._resource, "subject", value) return self diff --git a/test/api/write-generator/multi-package/__snapshots__/local-package.test.ts.snap b/test/api/write-generator/multi-package/__snapshots__/local-package.test.ts.snap index 94a6b778..fdb15d85 100644 --- a/test/api/write-generator/multi-package/__snapshots__/local-package.test.ts.snap +++ b/test/api/write-generator/multi-package/__snapshots__/local-package.test.ts.snap @@ -217,7 +217,7 @@ class ExampleNotebook(DomainResource): serialization_alias='resourceType', pattern='ExampleNotebook' ) - author: Reference = Field(alias="author", serialization_alias="author") + author: Reference[Literal["Patient", "Practitioner"]] = Field(alias="author", serialization_alias="author") content: str = Field(alias="content", serialization_alias="content") identifier: Identifier = Field(alias="identifier", serialization_alias="identifier") tag: PyList[Coding] | None = Field(None, alias="tag", serialization_alias="tag") @@ -313,14 +313,14 @@ class PatientContact(BackboneElement): address: Address | None = Field(None, alias="address", serialization_alias="address") gender: Literal["male", "female", "other", "unknown"] | None = Field(None, alias="gender", serialization_alias="gender") name: HumanName | None = Field(None, alias="name", serialization_alias="name") - organization: Reference | None = Field(None, alias="organization", serialization_alias="organization") + organization: Reference[Literal["Organization"]] | None = Field(None, alias="organization", serialization_alias="organization") period: Period | None = Field(None, alias="period", serialization_alias="period") relationship: PyList[CodeableConcept] | None = Field(None, alias="relationship", serialization_alias="relationship") telecom: PyList[ContactPoint] | None = Field(None, alias="telecom", serialization_alias="telecom") class PatientLink(BackboneElement): model_config = ConfigDict(validate_by_name=True, serialize_by_alias=True, extra="forbid") - other: Reference = Field(alias="other", serialization_alias="other") + other: Reference[Literal["Patient", "RelatedPerson"]] = Field(alias="other", serialization_alias="other") type: Literal["replaced-by", "replaces", "refer", "seealso"] = Field(alias="type", serialization_alias="type") @@ -340,10 +340,10 @@ class Patient(DomainResource): deceasedBoolean: bool | None = Field(None, alias="deceasedBoolean", serialization_alias="deceasedBoolean") deceasedDateTime: str | None = Field(None, alias="deceasedDateTime", serialization_alias="deceasedDateTime") gender: Literal["male", "female", "other", "unknown"] | None = Field(None, alias="gender", serialization_alias="gender") - generalPractitioner: PyList[Reference] | None = Field(None, alias="generalPractitioner", serialization_alias="generalPractitioner") + generalPractitioner: PyList[Reference[Literal["Organization", "Practitioner", "PractitionerRole"]]] | None = Field(None, alias="generalPractitioner", serialization_alias="generalPractitioner") identifier: PyList[Identifier] | None = Field(None, alias="identifier", serialization_alias="identifier") link: PyList[PatientLink] | None = Field(None, alias="link", serialization_alias="link") - managingOrganization: Reference | None = Field(None, alias="managingOrganization", serialization_alias="managingOrganization") + managingOrganization: Reference[Literal["Organization"]] | None = Field(None, alias="managingOrganization", serialization_alias="managingOrganization") maritalStatus: CodeableConcept[Literal["A", "D", "I", "L", "M", "P", "S", "T", "U", "W", "UNK"] | str] | None = Field(None, alias="maritalStatus", serialization_alias="maritalStatus") multipleBirthBoolean: bool | None = Field(None, alias="multipleBirthBoolean", serialization_alias="multipleBirthBoolean") multipleBirthInteger: int | None = Field(None, alias="multipleBirthInteger", serialization_alias="multipleBirthInteger") From dfa0859e28bb6c9ad28840ac73ac948c03acb296 Mon Sep 17 00:00:00 2001 From: Aleksandr Penskoi Date: Fri, 24 Jul 2026 17:13:34 +0400 Subject: [PATCH 16/16] chore(examples): regenerate python examples with parametrized Reference types --- .../fhir_types/hl7_fhir_r4_core/base.py | 18 +++++++++--------- .../fhir_types/hl7_fhir_r4_core/observation.py | 18 +++++++++--------- .../hl7_fhir_r4_core/organization.py | 4 ++-- .../fhir_types/hl7_fhir_r4_core/patient.py | 8 ++++---- .../observation_observation_bodyweight.py | 10 +++++----- .../observation_observation_vitalsigns.py | 10 +++++----- ...bservation_uscore_blood_pressure_profile.py | 10 +++++----- .../observation_uscore_body_weight_profile.py | 10 +++++----- .../observation_uscore_vital_signs_profile.py | 10 +++++----- 9 files changed, 49 insertions(+), 49 deletions(-) diff --git a/examples/python-r4-us-core/fhir_types/hl7_fhir_r4_core/base.py b/examples/python-r4-us-core/fhir_types/hl7_fhir_r4_core/base.py index a8d255ca..a3b5662a 100644 --- a/examples/python-r4-us-core/fhir_types/hl7_fhir_r4_core/base.py +++ b/examples/python-r4-us-core/fhir_types/hl7_fhir_r4_core/base.py @@ -61,7 +61,7 @@ class Age(Quantity): class Annotation(Element): model_config = ConfigDict(validate_by_name=True, serialize_by_alias=True, extra="forbid") - authorReference: Reference | None = Field(None, alias="authorReference", serialization_alias="authorReference") + authorReference: Reference[Literal["Organization", "Patient", "Practitioner", "RelatedPerson"]] | None = Field(None, alias="authorReference", serialization_alias="authorReference") authorString: str | None = Field(None, alias="authorString", serialization_alias="authorString") authorStringExtension: Element | None = Field(None, alias="_authorString", serialization_alias="_authorString") text: str = Field(alias="text", serialization_alias="text") @@ -183,7 +183,7 @@ class DataRequirement(Element): profileExtension: PyList[Element | None] | None = Field(None, alias="_profile", serialization_alias="_profile") sort: PyList[DataRequirementSort] | None = Field(None, alias="sort", serialization_alias="sort") subjectCodeableConcept: CodeableConcept | None = Field(None, alias="subjectCodeableConcept", serialization_alias="subjectCodeableConcept") - subjectReference: Reference | None = Field(None, alias="subjectReference", serialization_alias="subjectReference") + subjectReference: Reference[Literal["Group"]] | None = Field(None, alias="subjectReference", serialization_alias="subjectReference") type: str = Field(alias="type", serialization_alias="type") typeExtension: Element | None = Field(None, alias="_type", serialization_alias="_type") @@ -346,7 +346,7 @@ class HumanName(Element): class Identifier(Element): model_config = ConfigDict(validate_by_name=True, serialize_by_alias=True, extra="forbid") - assigner: Reference | None = Field(None, alias="assigner", serialization_alias="assigner") + assigner: Reference[Literal["Organization"]] | None = Field(None, alias="assigner", serialization_alias="assigner") period: Period | None = Field(None, alias="period", serialization_alias="period") system: str | None = Field(None, alias="system", serialization_alias="system") systemExtension: Element | None = Field(None, alias="_system", serialization_alias="_system") @@ -425,14 +425,14 @@ class Ratio(Element): numerator: Quantity | None = Field(None, alias="numerator", serialization_alias="numerator") -class Reference(Element): +class Reference(Element, Generic[T]): model_config = ConfigDict(validate_by_name=True, serialize_by_alias=True, extra="forbid") display: str | None = Field(None, alias="display", serialization_alias="display") displayExtension: Element | None = Field(None, alias="_display", serialization_alias="_display") identifier: Identifier | None = Field(None, alias="identifier", serialization_alias="identifier") reference: str | None = Field(None, alias="reference", serialization_alias="reference") referenceExtension: Element | None = Field(None, alias="_reference", serialization_alias="_reference") - type: str | None = Field(None, alias="type", serialization_alias="type") + type: T | None = Field(None, alias="type", serialization_alias="type") typeExtension: Element | None = Field(None, alias="_type", serialization_alias="_type") @@ -474,7 +474,7 @@ class Signature(Element): model_config = ConfigDict(validate_by_name=True, serialize_by_alias=True, extra="forbid") data: str | None = Field(None, alias="data", serialization_alias="data") dataExtension: Element | None = Field(None, alias="_data", serialization_alias="_data") - onBehalfOf: Reference | None = Field(None, alias="onBehalfOf", serialization_alias="onBehalfOf") + onBehalfOf: Reference[Literal["Device", "Organization", "Patient", "Practitioner", "PractitionerRole", "RelatedPerson"]] | None = Field(None, alias="onBehalfOf", serialization_alias="onBehalfOf") sigFormat: str | None = Field(None, alias="sigFormat", serialization_alias="sigFormat") sigFormatExtension: Element | None = Field(None, alias="_sigFormat", serialization_alias="_sigFormat") targetFormat: str | None = Field(None, alias="targetFormat", serialization_alias="targetFormat") @@ -482,7 +482,7 @@ class Signature(Element): type: PyList[Coding[Literal["1.2.840.10065.1.12.1.1", "1.2.840.10065.1.12.1.2", "1.2.840.10065.1.12.1.3", "1.2.840.10065.1.12.1.4", "1.2.840.10065.1.12.1.5", "1.2.840.10065.1.12.1.6", "1.2.840.10065.1.12.1.7", "1.2.840.10065.1.12.1.8", "1.2.840.10065.1.12.1.9", "1.2.840.10065.1.12.1.10", "1.2.840.10065.1.12.1.11", "1.2.840.10065.1.12.1.12", "1.2.840.10065.1.12.1.13", "1.2.840.10065.1.12.1.14", "1.2.840.10065.1.12.1.15", "1.2.840.10065.1.12.1.16", "1.2.840.10065.1.12.1.17", "1.2.840.10065.1.12.1.18"] | str]] = Field(alias="type", serialization_alias="type") when: str = Field(alias="when", serialization_alias="when") whenExtension: Element | None = Field(None, alias="_when", serialization_alias="_when") - who: Reference = Field(alias="who", serialization_alias="who") + who: Reference[Literal["Device", "Organization", "Patient", "Practitioner", "PractitionerRole", "RelatedPerson"]] = Field(alias="who", serialization_alias="who") class TimingRepeat(Element): @@ -524,7 +524,7 @@ class TriggerDefinition(Element): timingDateExtension: Element | None = Field(None, alias="_timingDate", serialization_alias="_timingDate") timingDateTime: str | None = Field(None, alias="timingDateTime", serialization_alias="timingDateTime") timingDateTimeExtension: Element | None = Field(None, alias="_timingDateTime", serialization_alias="_timingDateTime") - timingReference: Reference | None = Field(None, alias="timingReference", serialization_alias="timingReference") + timingReference: Reference[Literal["Schedule"]] | None = Field(None, alias="timingReference", serialization_alias="timingReference") timingTiming: Timing | None = Field(None, alias="timingTiming", serialization_alias="timingTiming") type: Literal["named-event", "periodic", "data-changed", "data-added", "data-modified", "data-removed", "data-accessed", "data-access-ended"] = Field(alias="type", serialization_alias="type") typeExtension: Element | None = Field(None, alias="_type", serialization_alias="_type") @@ -536,6 +536,6 @@ class UsageContext(Element): valueCodeableConcept: CodeableConcept | None = Field(None, alias="valueCodeableConcept", serialization_alias="valueCodeableConcept") valueQuantity: Quantity | None = Field(None, alias="valueQuantity", serialization_alias="valueQuantity") valueRange: Range | None = Field(None, alias="valueRange", serialization_alias="valueRange") - valueReference: Reference | None = Field(None, alias="valueReference", serialization_alias="valueReference") + valueReference: Reference[Literal["Group", "HealthcareService", "InsurancePlan", "Location", "Organization", "PlanDefinition", "ResearchStudy"]] | None = Field(None, alias="valueReference", serialization_alias="valueReference") diff --git a/examples/python-r4-us-core/fhir_types/hl7_fhir_r4_core/observation.py b/examples/python-r4-us-core/fhir_types/hl7_fhir_r4_core/observation.py index 2807d46f..f108ee6f 100644 --- a/examples/python-r4-us-core/fhir_types/hl7_fhir_r4_core/observation.py +++ b/examples/python-r4-us-core/fhir_types/hl7_fhir_r4_core/observation.py @@ -52,36 +52,36 @@ class Observation(DomainResource): serialization_alias='resourceType', pattern='Observation' ) - basedOn: PyList[Reference] | None = Field(None, alias="basedOn", serialization_alias="basedOn") + basedOn: PyList[Reference[Literal["CarePlan", "DeviceRequest", "ImmunizationRecommendation", "MedicationRequest", "NutritionOrder", "ServiceRequest"]]] | None = Field(None, alias="basedOn", serialization_alias="basedOn") bodySite: CodeableConcept | None = Field(None, alias="bodySite", serialization_alias="bodySite") category: PyList[CodeableConcept[Literal["social-history", "vital-signs", "imaging", "laboratory", "procedure", "survey", "exam", "therapy", "activity"] | str]] | None = Field(None, alias="category", serialization_alias="category") code: CodeableConcept = Field(alias="code", serialization_alias="code") component: PyList[ObservationComponent] | None = Field(None, alias="component", serialization_alias="component") dataAbsentReason: CodeableConcept[Literal["unknown", "asked-unknown", "temp-unknown", "not-asked", "asked-declined", "masked", "not-applicable", "unsupported", "as-text", "error", "not-a-number", "negative-infinity", "positive-infinity", "not-performed", "not-permitted"] | str] | None = Field(None, alias="dataAbsentReason", serialization_alias="dataAbsentReason") - derivedFrom: PyList[Reference] | None = Field(None, alias="derivedFrom", serialization_alias="derivedFrom") - device: Reference | None = Field(None, alias="device", serialization_alias="device") + derivedFrom: PyList[Reference[Literal["DocumentReference", "ImagingStudy", "Media", "MolecularSequence", "Observation", "QuestionnaireResponse"]]] | None = Field(None, alias="derivedFrom", serialization_alias="derivedFrom") + device: Reference[Literal["Device", "DeviceMetric"]] | None = Field(None, alias="device", serialization_alias="device") effectiveDateTime: str | None = Field(None, alias="effectiveDateTime", serialization_alias="effectiveDateTime") effectiveDateTimeExtension: Element | None = Field(None, alias="_effectiveDateTime", serialization_alias="_effectiveDateTime") effectiveInstant: str | None = Field(None, alias="effectiveInstant", serialization_alias="effectiveInstant") effectiveInstantExtension: Element | None = Field(None, alias="_effectiveInstant", serialization_alias="_effectiveInstant") effectivePeriod: Period | None = Field(None, alias="effectivePeriod", serialization_alias="effectivePeriod") effectiveTiming: Timing | None = Field(None, alias="effectiveTiming", serialization_alias="effectiveTiming") - encounter: Reference | None = Field(None, alias="encounter", serialization_alias="encounter") + encounter: Reference[Literal["Encounter"]] | None = Field(None, alias="encounter", serialization_alias="encounter") focus: PyList[Reference] | None = Field(None, alias="focus", serialization_alias="focus") - hasMember: PyList[Reference] | None = Field(None, alias="hasMember", serialization_alias="hasMember") + hasMember: PyList[Reference[Literal["MolecularSequence", "Observation", "QuestionnaireResponse"]]] | None = Field(None, alias="hasMember", serialization_alias="hasMember") identifier: PyList[Identifier] | None = Field(None, alias="identifier", serialization_alias="identifier") interpretation: PyList[CodeableConcept[Literal["_GeneticObservationInterpretation", "CAR", "Carrier", "_ObservationInterpretationChange", "B", "D", "U", "W", "_ObservationInterpretationExceptions", "<", ">", "AC", "IE", "QCF", "TOX", "_ObservationInterpretationNormality", "A", "AA", "HH", "LL", "H", "H>", "HU", "L", "L<", "LU", "N", "_ObservationInterpretationSusceptibility", "I", "MS", "NCL", "NS", "R", "SYN-R", "S", "SDD", "SYN-S", "VS", "EX", "HX", "LX", "HM", "ObservationInterpretationDetection", "IND", "E", "NEG", "ND", "POS", "DET", "ObservationInterpretationExpectation", "EXP", "UNE", "OBX", "ReactivityObservationInterpretation", "NR", "RR", "WR"] | str]] | None = Field(None, alias="interpretation", serialization_alias="interpretation") issued: str | None = Field(None, alias="issued", serialization_alias="issued") issuedExtension: Element | None = Field(None, alias="_issued", serialization_alias="_issued") method: CodeableConcept | None = Field(None, alias="method", serialization_alias="method") note: PyList[Annotation] | None = Field(None, alias="note", serialization_alias="note") - partOf: PyList[Reference] | None = Field(None, alias="partOf", serialization_alias="partOf") - performer: PyList[Reference] | None = Field(None, alias="performer", serialization_alias="performer") + partOf: PyList[Reference[Literal["ImagingStudy", "Immunization", "MedicationAdministration", "MedicationDispense", "MedicationStatement", "Procedure"]]] | None = Field(None, alias="partOf", serialization_alias="partOf") + performer: PyList[Reference[Literal["CareTeam", "Organization", "Patient", "Practitioner", "PractitionerRole", "RelatedPerson"]]] | None = Field(None, alias="performer", serialization_alias="performer") referenceRange: PyList[ObservationReferenceRange] | None = Field(None, alias="referenceRange", serialization_alias="referenceRange") - specimen: Reference | None = Field(None, alias="specimen", serialization_alias="specimen") + specimen: Reference[Literal["Specimen"]] | None = Field(None, alias="specimen", serialization_alias="specimen") status: Literal["registered", "preliminary", "final", "amended", "corrected", "cancelled", "entered-in-error", "unknown"] = Field(alias="status", serialization_alias="status") statusExtension: Element | None = Field(None, alias="_status", serialization_alias="_status") - subject: Reference | None = Field(None, alias="subject", serialization_alias="subject") + subject: Reference[Literal["Device", "Group", "Location", "Patient"]] | None = Field(None, alias="subject", serialization_alias="subject") valueBoolean: bool | None = Field(None, alias="valueBoolean", serialization_alias="valueBoolean") valueBooleanExtension: Element | None = Field(None, alias="_valueBoolean", serialization_alias="_valueBoolean") valueCodeableConcept: CodeableConcept | None = Field(None, alias="valueCodeableConcept", serialization_alias="valueCodeableConcept") diff --git a/examples/python-r4-us-core/fhir_types/hl7_fhir_r4_core/organization.py b/examples/python-r4-us-core/fhir_types/hl7_fhir_r4_core/organization.py index cebea2a4..70c7b6f9 100644 --- a/examples/python-r4-us-core/fhir_types/hl7_fhir_r4_core/organization.py +++ b/examples/python-r4-us-core/fhir_types/hl7_fhir_r4_core/organization.py @@ -37,11 +37,11 @@ class Organization(DomainResource): alias: PyList[str] | None = Field(None, alias="alias", serialization_alias="alias") aliasExtension: PyList[Element | None] | None = Field(None, alias="_alias", serialization_alias="_alias") contact: PyList[OrganizationContact] | None = Field(None, alias="contact", serialization_alias="contact") - endpoint: PyList[Reference] | None = Field(None, alias="endpoint", serialization_alias="endpoint") + endpoint: PyList[Reference[Literal["Endpoint"]]] | None = Field(None, alias="endpoint", serialization_alias="endpoint") identifier: PyList[Identifier] | None = Field(None, alias="identifier", serialization_alias="identifier") name: str | None = Field(None, alias="name", serialization_alias="name") nameExtension: Element | None = Field(None, alias="_name", serialization_alias="_name") - partOf: Reference | None = Field(None, alias="partOf", serialization_alias="partOf") + partOf: Reference[Literal["Organization"]] | None = Field(None, alias="partOf", serialization_alias="partOf") telecom: PyList[ContactPoint] | None = Field(None, alias="telecom", serialization_alias="telecom") type: PyList[CodeableConcept] | None = Field(None, alias="type", serialization_alias="type") diff --git a/examples/python-r4-us-core/fhir_types/hl7_fhir_r4_core/patient.py b/examples/python-r4-us-core/fhir_types/hl7_fhir_r4_core/patient.py index d9691092..5e1ae42d 100644 --- a/examples/python-r4-us-core/fhir_types/hl7_fhir_r4_core/patient.py +++ b/examples/python-r4-us-core/fhir_types/hl7_fhir_r4_core/patient.py @@ -25,14 +25,14 @@ class PatientContact(BackboneElement): address: Address | None = Field(None, alias="address", serialization_alias="address") gender: Literal["male", "female", "other", "unknown"] | None = Field(None, alias="gender", serialization_alias="gender") name: HumanName | None = Field(None, alias="name", serialization_alias="name") - organization: Reference | None = Field(None, alias="organization", serialization_alias="organization") + organization: Reference[Literal["Organization"]] | None = Field(None, alias="organization", serialization_alias="organization") period: Period | None = Field(None, alias="period", serialization_alias="period") relationship: PyList[CodeableConcept] | None = Field(None, alias="relationship", serialization_alias="relationship") telecom: PyList[ContactPoint] | None = Field(None, alias="telecom", serialization_alias="telecom") class PatientLink(BackboneElement): model_config = ConfigDict(validate_by_name=True, serialize_by_alias=True, extra="forbid") - other: Reference = Field(alias="other", serialization_alias="other") + other: Reference[Literal["Patient", "RelatedPerson"]] = Field(alias="other", serialization_alias="other") type: Literal["replaced-by", "replaces", "refer", "seealso"] = Field(alias="type", serialization_alias="type") @@ -57,10 +57,10 @@ class Patient(DomainResource): deceasedDateTimeExtension: Element | None = Field(None, alias="_deceasedDateTime", serialization_alias="_deceasedDateTime") gender: Literal["male", "female", "other", "unknown"] | None = Field(None, alias="gender", serialization_alias="gender") genderExtension: Element | None = Field(None, alias="_gender", serialization_alias="_gender") - generalPractitioner: PyList[Reference] | None = Field(None, alias="generalPractitioner", serialization_alias="generalPractitioner") + generalPractitioner: PyList[Reference[Literal["Organization", "Practitioner", "PractitionerRole"]]] | None = Field(None, alias="generalPractitioner", serialization_alias="generalPractitioner") identifier: PyList[Identifier] | None = Field(None, alias="identifier", serialization_alias="identifier") link: PyList[PatientLink] | None = Field(None, alias="link", serialization_alias="link") - managingOrganization: Reference | None = Field(None, alias="managingOrganization", serialization_alias="managingOrganization") + managingOrganization: Reference[Literal["Organization"]] | None = Field(None, alias="managingOrganization", serialization_alias="managingOrganization") maritalStatus: CodeableConcept[Literal["A", "D", "I", "L", "M", "P", "S", "T", "U", "W", "UNK"] | str] | None = Field(None, alias="maritalStatus", serialization_alias="maritalStatus") multipleBirthBoolean: bool | None = Field(None, alias="multipleBirthBoolean", serialization_alias="multipleBirthBoolean") multipleBirthBooleanExtension: Element | None = Field(None, alias="_multipleBirthBoolean", serialization_alias="_multipleBirthBoolean") diff --git a/examples/python-r4-us-core/fhir_types/hl7_fhir_r4_core/profiles/observation_observation_bodyweight.py b/examples/python-r4-us-core/fhir_types/hl7_fhir_r4_core/profiles/observation_observation_bodyweight.py index af9a3042..5a8b04d0 100644 --- a/examples/python-r4-us-core/fhir_types/hl7_fhir_r4_core/profiles/observation_observation_bodyweight.py +++ b/examples/python-r4-us-core/fhir_types/hl7_fhir_r4_core/profiles/observation_observation_bodyweight.py @@ -46,7 +46,7 @@ def apply(cls, resource: Observation) -> "ObservationBodyweightProfile": return cls(resource) @classmethod - def create_resource(cls, *, category: list[CodeableConcept] | None = None, status: Literal["registered", "preliminary", "final", "amended", "corrected", "cancelled", "entered-in-error", "unknown"], subject: Reference) -> Observation: + def create_resource(cls, *, category: list[CodeableConcept] | None = None, status: Literal["registered", "preliminary", "final", "amended", "corrected", "cancelled", "entered-in-error", "unknown"], subject: Reference[Literal["Patient"]]) -> Observation: category_with_defaults = ensure_slice_defaults(list(category or []), cls._vscat_slice_match) return build_resource( @@ -60,7 +60,7 @@ def create_resource(cls, *, category: list[CodeableConcept] | None = None, statu ) @classmethod - def create(cls, *, category: list[CodeableConcept] | None = None, status: Literal["registered", "preliminary", "final", "amended", "corrected", "cancelled", "entered-in-error", "unknown"], subject: Reference) -> "ObservationBodyweightProfile": + def create(cls, *, category: list[CodeableConcept] | None = None, status: Literal["registered", "preliminary", "final", "amended", "corrected", "cancelled", "entered-in-error", "unknown"], subject: Reference[Literal["Patient"]]) -> "ObservationBodyweightProfile": return cls.apply(cls.create_resource(category=category, status=status, subject=subject)) def to_resource(self) -> Observation: @@ -73,10 +73,10 @@ def set_status(self, value: Literal["registered", "preliminary", "final", "amend setattr(self._resource, "status", value) return self - def get_subject(self) -> Reference | None: # Reference[Patient] - return cast('Reference | None', getattr(self._resource, "subject", None)) + def get_subject(self) -> Reference[Literal["Patient"]] | None: + return cast('Reference[Literal["Patient"]] | None', getattr(self._resource, "subject", None)) - def set_subject(self, value: Reference) -> "ObservationBodyweightProfile": # Reference[Patient] + def set_subject(self, value: Reference[Literal["Patient"]]) -> "ObservationBodyweightProfile": setattr(self._resource, "subject", value) return self diff --git a/examples/python-r4-us-core/fhir_types/hl7_fhir_r4_core/profiles/observation_observation_vitalsigns.py b/examples/python-r4-us-core/fhir_types/hl7_fhir_r4_core/profiles/observation_observation_vitalsigns.py index 85852811..12dbd1b6 100644 --- a/examples/python-r4-us-core/fhir_types/hl7_fhir_r4_core/profiles/observation_observation_vitalsigns.py +++ b/examples/python-r4-us-core/fhir_types/hl7_fhir_r4_core/profiles/observation_observation_vitalsigns.py @@ -46,7 +46,7 @@ def apply(cls, resource: Observation) -> "ObservationVitalsignsProfile": return cls(resource) @classmethod - def create_resource(cls, *, category: list[CodeableConcept] | None = None, status: Literal["registered", "preliminary", "final", "amended", "corrected", "cancelled", "entered-in-error", "unknown"], code: CodeableConcept, subject: Reference) -> Observation: + def create_resource(cls, *, category: list[CodeableConcept] | None = None, status: Literal["registered", "preliminary", "final", "amended", "corrected", "cancelled", "entered-in-error", "unknown"], code: CodeableConcept, subject: Reference[Literal["Patient"]]) -> Observation: category_with_defaults = ensure_slice_defaults(list(category or []), cls._vscat_slice_match) return build_resource( @@ -60,7 +60,7 @@ def create_resource(cls, *, category: list[CodeableConcept] | None = None, statu ) @classmethod - def create(cls, *, category: list[CodeableConcept] | None = None, status: Literal["registered", "preliminary", "final", "amended", "corrected", "cancelled", "entered-in-error", "unknown"], code: CodeableConcept, subject: Reference) -> "ObservationVitalsignsProfile": + def create(cls, *, category: list[CodeableConcept] | None = None, status: Literal["registered", "preliminary", "final", "amended", "corrected", "cancelled", "entered-in-error", "unknown"], code: CodeableConcept, subject: Reference[Literal["Patient"]]) -> "ObservationVitalsignsProfile": return cls.apply(cls.create_resource(category=category, status=status, code=code, subject=subject)) def to_resource(self) -> Observation: @@ -80,10 +80,10 @@ def set_code(self, value: CodeableConcept) -> "ObservationVitalsignsProfile": setattr(self._resource, "code", value) return self - def get_subject(self) -> Reference | None: # Reference[Patient] - return cast('Reference | None', getattr(self._resource, "subject", None)) + def get_subject(self) -> Reference[Literal["Patient"]] | None: + return cast('Reference[Literal["Patient"]] | None', getattr(self._resource, "subject", None)) - def set_subject(self, value: Reference) -> "ObservationVitalsignsProfile": # Reference[Patient] + def set_subject(self, value: Reference[Literal["Patient"]]) -> "ObservationVitalsignsProfile": setattr(self._resource, "subject", value) return self diff --git a/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/observation_uscore_blood_pressure_profile.py b/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/observation_uscore_blood_pressure_profile.py index d30a79e1..36bb4253 100644 --- a/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/observation_uscore_blood_pressure_profile.py +++ b/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/observation_uscore_blood_pressure_profile.py @@ -52,7 +52,7 @@ def apply(cls, resource: Observation) -> "UscoreBloodPressureProfile": return cls(resource) @classmethod - def create_resource(cls, *, category: list[CodeableConcept] | None = None, component: list[BackboneElement] | None = None, status: Literal["registered", "preliminary", "final", "amended", "corrected", "cancelled", "entered-in-error", "unknown"], subject: Reference) -> Observation: + def create_resource(cls, *, category: list[CodeableConcept] | None = None, component: list[BackboneElement] | None = None, status: Literal["registered", "preliminary", "final", "amended", "corrected", "cancelled", "entered-in-error", "unknown"], subject: Reference[Literal["Patient"]]) -> Observation: category_with_defaults = ensure_slice_defaults(list(category or []), cls._vscat_slice_match) component_with_defaults = ensure_slice_defaults( list(component or []), @@ -72,7 +72,7 @@ def create_resource(cls, *, category: list[CodeableConcept] | None = None, compo ) @classmethod - def create(cls, *, category: list[CodeableConcept] | None = None, component: list[BackboneElement] | None = None, status: Literal["registered", "preliminary", "final", "amended", "corrected", "cancelled", "entered-in-error", "unknown"], subject: Reference) -> "UscoreBloodPressureProfile": + def create(cls, *, category: list[CodeableConcept] | None = None, component: list[BackboneElement] | None = None, status: Literal["registered", "preliminary", "final", "amended", "corrected", "cancelled", "entered-in-error", "unknown"], subject: Reference[Literal["Patient"]]) -> "UscoreBloodPressureProfile": return cls.apply(cls.create_resource(category=category, component=component, status=status, subject=subject)) def to_resource(self) -> Observation: @@ -85,10 +85,10 @@ def set_status(self, value: Literal["registered", "preliminary", "final", "amend setattr(self._resource, "status", value) return self - def get_subject(self) -> Reference | None: # Reference[Patient(http://hl7.org/fhir/us/core/StructureDefinition/us-core-patient)] - return cast('Reference | None', getattr(self._resource, "subject", None)) + def get_subject(self) -> Reference[Literal["Patient"]] | None: # http://hl7.org/fhir/us/core/StructureDefinition/us-core-patient + return cast('Reference[Literal["Patient"]] | None', getattr(self._resource, "subject", None)) - def set_subject(self, value: Reference) -> "UscoreBloodPressureProfile": # Reference[Patient(http://hl7.org/fhir/us/core/StructureDefinition/us-core-patient)] + def set_subject(self, value: Reference[Literal["Patient"]]) -> "UscoreBloodPressureProfile": # http://hl7.org/fhir/us/core/StructureDefinition/us-core-patient setattr(self._resource, "subject", value) return self diff --git a/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/observation_uscore_body_weight_profile.py b/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/observation_uscore_body_weight_profile.py index 60995cdb..eaf48475 100644 --- a/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/observation_uscore_body_weight_profile.py +++ b/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/observation_uscore_body_weight_profile.py @@ -48,7 +48,7 @@ def apply(cls, resource: Observation) -> "UscoreBodyWeightProfile": return cls(resource) @classmethod - def create_resource(cls, *, category: list[CodeableConcept] | None = None, status: Literal["registered", "preliminary", "final", "amended", "corrected", "cancelled", "entered-in-error", "unknown"], subject: Reference) -> Observation: + def create_resource(cls, *, category: list[CodeableConcept] | None = None, status: Literal["registered", "preliminary", "final", "amended", "corrected", "cancelled", "entered-in-error", "unknown"], subject: Reference[Literal["Patient"]]) -> Observation: category_with_defaults = ensure_slice_defaults(list(category or []), cls._vscat_slice_match) return build_resource( @@ -62,7 +62,7 @@ def create_resource(cls, *, category: list[CodeableConcept] | None = None, statu ) @classmethod - def create(cls, *, category: list[CodeableConcept] | None = None, status: Literal["registered", "preliminary", "final", "amended", "corrected", "cancelled", "entered-in-error", "unknown"], subject: Reference) -> "UscoreBodyWeightProfile": + def create(cls, *, category: list[CodeableConcept] | None = None, status: Literal["registered", "preliminary", "final", "amended", "corrected", "cancelled", "entered-in-error", "unknown"], subject: Reference[Literal["Patient"]]) -> "UscoreBodyWeightProfile": return cls.apply(cls.create_resource(category=category, status=status, subject=subject)) def to_resource(self) -> Observation: @@ -75,10 +75,10 @@ def set_status(self, value: Literal["registered", "preliminary", "final", "amend setattr(self._resource, "status", value) return self - def get_subject(self) -> Reference | None: # Reference[Patient(http://hl7.org/fhir/us/core/StructureDefinition/us-core-patient)] - return cast('Reference | None', getattr(self._resource, "subject", None)) + def get_subject(self) -> Reference[Literal["Patient"]] | None: # http://hl7.org/fhir/us/core/StructureDefinition/us-core-patient + return cast('Reference[Literal["Patient"]] | None', getattr(self._resource, "subject", None)) - def set_subject(self, value: Reference) -> "UscoreBodyWeightProfile": # Reference[Patient(http://hl7.org/fhir/us/core/StructureDefinition/us-core-patient)] + def set_subject(self, value: Reference[Literal["Patient"]]) -> "UscoreBodyWeightProfile": # http://hl7.org/fhir/us/core/StructureDefinition/us-core-patient setattr(self._resource, "subject", value) return self diff --git a/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/observation_uscore_vital_signs_profile.py b/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/observation_uscore_vital_signs_profile.py index d0687722..952d1347 100644 --- a/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/observation_uscore_vital_signs_profile.py +++ b/examples/python-r4-us-core/fhir_types/hl7_fhir_us_core/profiles/observation_uscore_vital_signs_profile.py @@ -48,7 +48,7 @@ def apply(cls, resource: Observation) -> "UscoreVitalSignsProfile": return cls(resource) @classmethod - def create_resource(cls, *, category: list[CodeableConcept] | None = None, status: Literal["registered", "preliminary", "final", "amended", "corrected", "cancelled", "entered-in-error", "unknown"], code: CodeableConcept, subject: Reference) -> Observation: + def create_resource(cls, *, category: list[CodeableConcept] | None = None, status: Literal["registered", "preliminary", "final", "amended", "corrected", "cancelled", "entered-in-error", "unknown"], code: CodeableConcept, subject: Reference[Literal["Patient"]]) -> Observation: category_with_defaults = ensure_slice_defaults(list(category or []), cls._vscat_slice_match) return build_resource( @@ -62,7 +62,7 @@ def create_resource(cls, *, category: list[CodeableConcept] | None = None, statu ) @classmethod - def create(cls, *, category: list[CodeableConcept] | None = None, status: Literal["registered", "preliminary", "final", "amended", "corrected", "cancelled", "entered-in-error", "unknown"], code: CodeableConcept, subject: Reference) -> "UscoreVitalSignsProfile": + def create(cls, *, category: list[CodeableConcept] | None = None, status: Literal["registered", "preliminary", "final", "amended", "corrected", "cancelled", "entered-in-error", "unknown"], code: CodeableConcept, subject: Reference[Literal["Patient"]]) -> "UscoreVitalSignsProfile": return cls.apply(cls.create_resource(category=category, status=status, code=code, subject=subject)) def to_resource(self) -> Observation: @@ -82,10 +82,10 @@ def set_code(self, value: CodeableConcept) -> "UscoreVitalSignsProfile": setattr(self._resource, "code", value) return self - def get_subject(self) -> Reference | None: # Reference[Patient(http://hl7.org/fhir/us/core/StructureDefinition/us-core-patient)] - return cast('Reference | None', getattr(self._resource, "subject", None)) + def get_subject(self) -> Reference[Literal["Patient"]] | None: # http://hl7.org/fhir/us/core/StructureDefinition/us-core-patient + return cast('Reference[Literal["Patient"]] | None', getattr(self._resource, "subject", None)) - def set_subject(self, value: Reference) -> "UscoreVitalSignsProfile": # Reference[Patient(http://hl7.org/fhir/us/core/StructureDefinition/us-core-patient)] + def set_subject(self, value: Reference[Literal["Patient"]]) -> "UscoreVitalSignsProfile": # http://hl7.org/fhir/us/core/StructureDefinition/us-core-patient setattr(self._resource, "subject", value) return self