|
8 | 8 | from dlt.common.destination import Destination, DestinationReference |
9 | 9 | from dlt.common.destination.client import DestinationClientDwhConfiguration, WithStagingDataset |
10 | 10 | from dlt.common.destination import DestinationCapabilitiesContext |
11 | | -from dlt.common.destination.exceptions import UnknownDestinationModule |
| 11 | +from dlt.common.destination.exceptions import ( |
| 12 | + UnknownDestinationModule, |
| 13 | + DestinationTypeResolutionException, |
| 14 | +) |
12 | 15 | from dlt.common.schema import Schema |
13 | 16 | from dlt.common.typing import is_subclass |
14 | 17 | from dlt.common.normalizers.naming import sql_ci_v1, sql_cs_v1 |
@@ -316,39 +319,66 @@ def test_import_destination_config() -> None: |
316 | 319 | def test_import_destination_type_config( |
317 | 320 | environment: Dict[str, str], |
318 | 321 | destination_type: str, |
319 | | - destination_name: str = "my_destination", |
320 | 322 | ) -> None: |
321 | | - environment[f"DESTINATION__{destination_name.upper()}__DESTINATION_TYPE"] = destination_type |
322 | | - msg_from_fallback = "configure a valid dlt destination type" |
| 323 | + """Test destination resolution behavior with both valid and invalid destination types. |
| 324 | +
|
| 325 | + This test covers the resolution strategy where dlt first tries to resolve |
| 326 | + a destination as a named destination with configured type, and if that fails, |
| 327 | + falls back to resolving it as a direct destination type reference. |
| 328 | + """ |
| 329 | + environment["DESTINATION__MY_DESTINATION__DESTINATION_TYPE"] = destination_type |
| 330 | + |
323 | 331 | if destination_type == "wrong_type": |
324 | | - with pytest.raises(UnknownDestinationModule) as py_exc: |
325 | | - Destination.from_reference(ref=destination_name) |
326 | | - test = py_exc.value |
327 | | - assert msg_from_fallback in str(py_exc.value) |
328 | | - |
329 | | - # if destination_name is provided, ref should be a valid destination type |
330 | | - with pytest.raises(UnknownDestinationModule) as py_exc: |
331 | | - Destination.from_reference( |
332 | | - ref=f"dlt.destinations.{destination_type}", destination_name=destination_name |
333 | | - ) |
334 | | - assert msg_from_fallback not in str(py_exc.value) |
335 | | - |
336 | | - # if ref contains dots, it's a module path and should be valid |
337 | | - # names with dots will not resolve correctly from configs anyway |
338 | | - with pytest.raises(UnknownDestinationModule): |
| 332 | + # Case 1: Fully qualified ref with dots |
| 333 | + # Skips named destination resolution and only attempts direct type resolution |
| 334 | + with pytest.raises(UnknownDestinationModule) as module_ex: |
339 | 335 | Destination.from_reference(ref=f"dlt.destinations.{destination_type}") |
340 | | - assert msg_from_fallback not in str(py_exc.value) |
| 336 | + assert "`dlt.destinations.wrong_type` is not registered." in str(module_ex.value) |
| 337 | + |
| 338 | + # Case 2: Explicit destination_name provided |
| 339 | + # Same as Case 1 |
| 340 | + with pytest.raises(UnknownDestinationModule) as module_ex: |
| 341 | + Destination.from_reference(ref=destination_type, destination_name="my_destination") |
| 342 | + assert "`wrong_type` is not one of the standard dlt destinations." in str(module_ex.value) |
| 343 | + |
| 344 | + # Case 3: Named destination with invalid configured type |
| 345 | + # First tries named destination "my_destination" with configured type "wrong_type" |
| 346 | + # Then tries "my_destination" as destination type |
| 347 | + with pytest.raises(DestinationTypeResolutionException) as resolution_exc: |
| 348 | + Destination.from_reference(ref="my_destination") |
| 349 | + assert resolution_exc.value.named_dest_error |
| 350 | + assert "`wrong_type` is not one of the standard dlt destination types." in str( |
| 351 | + resolution_exc.value |
| 352 | + ) |
| 353 | + assert "`my_destination` is not one of the standard dlt destinations." in str( |
| 354 | + resolution_exc.value |
| 355 | + ) |
| 356 | + |
| 357 | + # Case 4: Named destination with missing type configuration |
| 358 | + # First tries named destination "my_destination" but no type configured (config error) |
| 359 | + # Then tries "my_destination" as direct destination type |
| 360 | + environment.clear() |
| 361 | + with pytest.raises(DestinationTypeResolutionException) as resolution_exc: |
| 362 | + Destination.from_reference(ref="my_destination") |
| 363 | + assert resolution_exc.value.named_dest_error |
| 364 | + assert ( |
| 365 | + "Missing 1 field(s) in configuration `DestinationTypeConfiguration`: `destination_type`" |
| 366 | + in str(resolution_exc.value) |
| 367 | + ) |
| 368 | + assert "`my_destination` is not one of the standard dlt destinations." in str( |
| 369 | + resolution_exc.value |
| 370 | + ) |
341 | 371 |
|
342 | 372 | else: |
343 | | - dest = Destination.from_reference(ref=destination_name) |
| 373 | + dest = Destination.from_reference(ref="my_destination") |
344 | 374 | assert dest.destination_type == "dlt.destinations.duckdb" |
345 | | - assert dest.destination_name == destination_name |
| 375 | + assert dest.destination_name == "my_destination" |
346 | 376 |
|
347 | 377 | dest = Destination.from_reference( |
348 | | - ref=f"dlt.destinations.{destination_type}", destination_name=destination_name |
| 378 | + ref=f"dlt.destinations.{destination_type}", destination_name="my_destination" |
349 | 379 | ) |
350 | 380 | assert dest.destination_type == "dlt.destinations.duckdb" |
351 | | - assert dest.destination_name == destination_name |
| 381 | + assert dest.destination_name == "my_destination" |
352 | 382 |
|
353 | 383 | dest = Destination.from_reference(ref=f"dlt.destinations.{destination_type}") |
354 | 384 | assert dest.destination_type == "dlt.destinations.duckdb" |
|
0 commit comments