diff --git a/dataconnect/service/default.py b/dataconnect/service/default.py index a034de5..51a2845 100644 --- a/dataconnect/service/default.py +++ b/dataconnect/service/default.py @@ -46,10 +46,6 @@ _ACTION_LIST_DATASETS = "datasets.list" _ACTION_LIST_DATASET_VERSIONS = "dataset_versions.list" -# Accepted values for the ``format_type`` filter passed to -# :meth:`DefaultDataConnectService.get_datetime_formats`. -_VALID_DATETIME_FORMAT_TYPES: frozenset[str] = frozenset({"all", "date", "datetime"}) - def _coerce_int_field(field: str, field_value: int | None) -> int | None: if field_value is None: @@ -325,13 +321,8 @@ def get_datetime_formats( ) -> DatetimeFormatsResult: """Return the supported datetime formats filtered by ``format_type``. - The ``format_type`` argument is normalised (stripped + lower-cased) and - validated client-side against the accepted set ``{"all", "date", - "datetime"}``. Invalid values raise :class:`ValidationError` *before* - any transport call is made. - - The server filters the list according to ``format_type``; the service - then classifies each returned format as ``"date"`` or ``"datetime"`` + The server validates and filters the list according to ``format_type``; + the service then classifies each returned format as ``"date"`` or ``"datetime"`` (based on whether the format contains a time component ``"HH:mm"``) and wraps everything in a :class:`DatetimeFormatsResult` that exposes the :meth:`~DatetimeFormatsResult.all`, @@ -349,22 +340,11 @@ def get_datetime_formats( A :class:`DatetimeFormatsResult` containing the classified formats. Raises: - ValidationError: When ``format_type`` is not one of the accepted - values. DataConnectError: Any :class:`TransportError` from the transport layer is translated by :func:`translate_error` into the public API's :class:`DataConnectError` hierarchy. """ - normalized = (format_type or "all").strip().lower() - - if normalized not in _VALID_DATETIME_FORMAT_TYPES: - raise ValidationError( - error_code="VAL_001", - message=(f"Invalid format_type: {format_type!r}. Accepted values: all, date, datetime."), - timestamp=datetime.now(UTC).strftime("%Y-%m-%dT%H:%M:%SZ"), - ) - - request = DatetimeFormatsRequest(project_token=project_token, format_type=normalized) + request = DatetimeFormatsRequest(project_token=project_token, format_type=format_type) try: raw_formats = self._transport.get_datetime_formats(request) diff --git a/dataconnect/transport/arrow_flight/transport.py b/dataconnect/transport/arrow_flight/transport.py index 55e69be..7dfe1ff 100644 --- a/dataconnect/transport/arrow_flight/transport.py +++ b/dataconnect/transport/arrow_flight/transport.py @@ -365,7 +365,7 @@ def get_datetime_formats(self, request: DatetimeFormatsRequest) -> list[str]: Args: request: A :class:`DatetimeFormatsRequest` carrying the project - token and the (already-validated) ``format_type`` filter. + token and the ``format_type`` filter for server validation. Returns: A list of supported format strings. Returns an empty list if the diff --git a/tests/test_get_datetime_formats.py b/tests/test_get_datetime_formats.py index eb0c318..5a754c2 100644 --- a/tests/test_get_datetime_formats.py +++ b/tests/test_get_datetime_formats.py @@ -163,9 +163,8 @@ def test_default_formats_is_empty_list_and_not_shared(self) -> None: class TestServiceGetDatetimeFormats: - """``DefaultDataConnectService.get_datetime_formats`` must validate the - ``format_type`` filter, forward the request to the transport, and classify - each returned format. + """``DefaultDataConnectService.get_datetime_formats`` must forward the + ``format_type`` filter to the transport and classify each returned format. """ def test_returns_datetime_formats_result_instance(self) -> None: @@ -197,23 +196,13 @@ def test_format_type_datetime_forwarded_to_transport(self) -> None: assert transport.last_request is not None assert transport.last_request.format_type == "datetime" - def test_format_type_is_normalised_case_insensitively(self) -> None: + @pytest.mark.parametrize("format_type", ["DATE", " Datetime ", "", "invalid"]) + def test_format_type_is_forwarded_unchanged(self, format_type: str) -> None: service, transport = _make_service() - service.get_datetime_formats(project_token="tok", format_type="DATE") + result = service.get_datetime_formats(project_token="tok", format_type=format_type) assert transport.last_request is not None - assert transport.last_request.format_type == "date" - - def test_format_type_is_normalised_with_whitespace(self) -> None: - service, transport = _make_service() - service.get_datetime_formats(project_token="tok", format_type=" Datetime ") - assert transport.last_request is not None - assert transport.last_request.format_type == "datetime" - - def test_empty_string_format_type_is_treated_as_all(self) -> None: - service, transport = _make_service() - service.get_datetime_formats(project_token="tok", format_type="") - assert transport.last_request is not None - assert transport.last_request.format_type == "all" + assert transport.last_request.format_type == format_type + assert [item.format for item in result.all()] == _SAMPLE_FORMATS # --- response classification --- @@ -260,27 +249,18 @@ def test_empty_server_response_yields_empty_result(self) -> None: assert result.dates() == [] assert result.datetimes() == [] - # --- invalid input --- - - @pytest.mark.parametrize("bad_type", ["NA", "invalid", "datetimes", "DATETIMEZ", "1"]) - def test_invalid_format_type_raises_validation_error(self, bad_type: str) -> None: - service, transport = _make_service() - with pytest.raises(ValidationError): - service.get_datetime_formats(project_token="tok", format_type=bad_type) - # Transport must not be invoked when validation fails up-front. - assert transport.last_request is None - # --- error translation --- def test_transport_validation_error_is_translated_to_service_error(self) -> None: err = TransportValidationError( error_code="VAL_008", - message="invalid project token", + message="invalid format type", timestamp="2024-01-01T00:00:00Z", ) - service, _ = _make_service(raise_error=err) - with pytest.raises(ValidationError): - service.get_datetime_formats(project_token="bad", format_type="all") + service, transport = _make_service(raise_error=err) + with pytest.raises(ValidationError, match="invalid format type"): + service.get_datetime_formats(project_token="tok", format_type="invalid") + assert transport.last_request == DatetimeFormatsRequest(project_token="tok", format_type="invalid") # ---------------------------------------------------------------------------