diff --git a/scripts/naming.py b/scripts/naming.py index 6f02f31..1331bdb 100644 --- a/scripts/naming.py +++ b/scripts/naming.py @@ -26,12 +26,13 @@ def class_name(operation_id: str) -> str: def python_name(wire: str) -> str: """A query parameter's wire name as a keyword argument. - A leading `_` is dropped, `-` and `:` become `_`, and camelCase becomes snake_case: + A leading `_` is dropped, `-`, `:` and `.` become `_`, and camelCase becomes snake_case: `_count` is `count`, `name:contains` is `name_contains`, `address-city` is `address_city`, - `serviceTypeCode` is `service_type_code`. + `serviceTypeCode` is `service_type_code`, and a FHIR chained search such as + `location.address-state` is `location_address_state`. """ name = wire[1:] if wire.startswith("_") else wire - name = re.sub(r"[-:]", "_", name) + name = re.sub(r"[-:.]", "_", name) name = _CAMEL.sub("_", name).lower() if not name.isidentifier() or keyword.iskeyword(name): raise ValueError(f"the query parameter {wire!r} has no Python name: {name!r}") diff --git a/tests/test_encode.py b/tests/test_encode.py index ffa0303..e4764da 100644 --- a/tests/test_encode.py +++ b/tests/test_encode.py @@ -98,6 +98,9 @@ def test_a_url_on_another_host_is_refused() -> None: ("displayLanguage", "display_language"), ("isVirtual", "is_virtual"), ("new-patient-from-network", "new_patient_from_network"), + # FHIR's chained search parameters, sent under their own names. + ("location.address-state", "location_address_state"), + ("organization.identifier", "organization_identifier"), ], ) def test_wire_names_map_to_python_names(wire: str, python: str) -> None: @@ -108,7 +111,7 @@ def test_a_name_python_cannot_take_is_refused() -> None: with pytest.raises(ValueError, match="no Python name"): naming.python_name("class") with pytest.raises(ValueError, match="no Python name"): - naming.python_name("a.b") + naming.python_name("a/b") def test_operation_ids_and_docs_slugs() -> None: