phlo-testing 0.2.3__tar.gz → 0.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. {phlo_testing-0.2.3 → phlo_testing-0.3.0}/PKG-INFO +2 -1
  2. {phlo_testing-0.2.3 → phlo_testing-0.3.0}/pyproject.toml +2 -1
  3. {phlo_testing-0.2.3 → phlo_testing-0.3.0}/src/phlo_testing/__init__.py +1 -1
  4. phlo_testing-0.3.0/src/phlo_testing/conftest_template.py +95 -0
  5. {phlo_testing-0.2.3 → phlo_testing-0.3.0}/src/phlo_testing/execution.py +103 -71
  6. {phlo_testing-0.2.3 → phlo_testing-0.3.0}/src/phlo_testing/fixtures.py +21 -0
  7. phlo_testing-0.3.0/src/phlo_testing/hooks.py +284 -0
  8. {phlo_testing-0.2.3 → phlo_testing-0.3.0}/src/phlo_testing/local_mode.py +111 -63
  9. {phlo_testing-0.2.3 → phlo_testing-0.3.0}/src/phlo_testing/mock_dlt.py +99 -48
  10. {phlo_testing-0.2.3 → phlo_testing-0.3.0}/src/phlo_testing/mock_iceberg.py +146 -72
  11. {phlo_testing-0.2.3 → phlo_testing-0.3.0}/src/phlo_testing/mock_trino.py +161 -118
  12. {phlo_testing-0.2.3 → phlo_testing-0.3.0}/src/phlo_testing/non_versioned_profile_harness.py +110 -8
  13. phlo_testing-0.3.0/src/phlo_testing/placeholders.py +523 -0
  14. {phlo_testing-0.2.3 → phlo_testing-0.3.0}/src/phlo_testing/profile_harness.py +656 -21
  15. phlo_testing-0.3.0/src/phlo_testing/utils.py +68 -0
  16. {phlo_testing-0.2.3 → phlo_testing-0.3.0}/src/phlo_testing.egg-info/PKG-INFO +2 -1
  17. {phlo_testing-0.2.3 → phlo_testing-0.3.0}/src/phlo_testing.egg-info/requires.txt +1 -0
  18. {phlo_testing-0.2.3 → phlo_testing-0.3.0}/tests/test_profile_harness.py +3 -1
  19. {phlo_testing-0.2.3 → phlo_testing-0.3.0}/tests/test_testing_infrastructure.py +38 -0
  20. phlo_testing-0.2.3/src/phlo_testing/conftest_template.py +0 -65
  21. phlo_testing-0.2.3/src/phlo_testing/hooks.py +0 -135
  22. phlo_testing-0.2.3/src/phlo_testing/placeholders.py +0 -846
  23. phlo_testing-0.2.3/src/phlo_testing/utils.py +0 -20
  24. {phlo_testing-0.2.3 → phlo_testing-0.3.0}/README.md +0 -0
  25. {phlo_testing-0.2.3 → phlo_testing-0.3.0}/setup.cfg +0 -0
  26. {phlo_testing-0.2.3 → phlo_testing-0.3.0}/src/phlo_testing.egg-info/SOURCES.txt +0 -0
  27. {phlo_testing-0.2.3 → phlo_testing-0.3.0}/src/phlo_testing.egg-info/dependency_links.txt +0 -0
  28. {phlo_testing-0.2.3 → phlo_testing-0.3.0}/src/phlo_testing.egg-info/top_level.txt +0 -0
  29. {phlo_testing-0.2.3 → phlo_testing-0.3.0}/tests/test_integration_testing.py +0 -0
  30. {phlo_testing-0.2.3 → phlo_testing-0.3.0}/tests/test_non_versioned_profile_harness.py +0 -0
@@ -1,12 +1,13 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: phlo-testing
3
- Version: 0.2.3
3
+ Version: 0.3.0
4
4
  Summary: Testing utilities for Phlo
5
5
  Author-email: Phlo Team <team@phlo.dev>
6
6
  License: MIT
7
7
  Requires-Python: >=3.11
8
8
  Description-Content-Type: text/plain
9
9
  Requires-Dist: phlo>=0.1.0
10
+ Requires-Dist: phlo-postgres>=0.1.0
10
11
  Requires-Dist: duckdb>=0.9.0
11
12
  Requires-Dist: pyarrow>=21.0.0
12
13
  Requires-Dist: pyiceberg>=0.10.0
@@ -8,6 +8,7 @@ requires = [
8
8
  [project]
9
9
  dependencies = [
10
10
  "phlo>=0.1.0",
11
+ "phlo-postgres>=0.1.0",
11
12
  "duckdb>=0.9.0",
12
13
  "pyarrow>=21.0.0",
13
14
  "pyiceberg>=0.10.0",
@@ -18,7 +19,7 @@ dependencies = [
18
19
  description = "Testing utilities for Phlo"
19
20
  name = "phlo-testing"
20
21
  requires-python = ">=3.11"
21
- version = "0.2.3"
22
+ version = "0.3.0"
22
23
 
23
24
  [[project.authors]]
24
25
  email = "team@phlo.dev"
@@ -341,4 +341,4 @@ __all__ = [
341
341
  if _FIXTURES_AVAILABLE:
342
342
  __all__.extend(_FIXTURE_EXPORTS)
343
343
 
344
- __version__ = "0.2.3"
344
+ __version__ = "0.3.0"
@@ -0,0 +1,95 @@
1
+ """Conftest template for user projects.
2
+
3
+ This module provides a ready-to-use conftest.py template that users can copy
4
+ to their tests/ directory to get all phlo_testing fixtures automatically.
5
+
6
+ The template includes:
7
+ - All standard phlo_testing fixtures (mock resources, test data, etc.)
8
+ - Environment reset fixture for test isolation
9
+ - Project root fixture for path resolution
10
+
11
+ Usage:
12
+ >>> from phlo_testing.conftest_template import CONFTEST_TEMPLATE, get_conftest_template
13
+ >>> from pathlib import Path
14
+ >>> # Write template to tests/conftest.py
15
+ >>> Path("tests/conftest.py").write_text(get_conftest_template())
16
+ >>> # Or use the constant directly
17
+ >>> print(CONFTEST_TEMPLATE)
18
+
19
+ The fixtures included in the template:
20
+ - mock_iceberg_catalog: Fresh MockIcebergCatalog for each test
21
+ - mock_trino: Fresh MockTrinoResource for each test
22
+ - mock_asset_context: MockAssetContext with logging capture
23
+ - sample_partition_date: Standard test partition date
24
+ - sample_dlt_data: Sample DLT source data
25
+ - temp_staging_dir: Temporary directory for test files
26
+ - And more...
27
+ """
28
+
29
+ CONFTEST_TEMPLATE = '''"""
30
+ Pytest configuration and shared fixtures.
31
+
32
+ Place this file in tests/ directory to make fixtures available to all tests.
33
+ """
34
+
35
+ import pytest
36
+ from pathlib import Path
37
+
38
+ # Import fixtures from phlo_testing
39
+ from phlo_testing.fixtures import (
40
+ mock_iceberg_catalog,
41
+ mock_trino,
42
+ mock_asset_context,
43
+ mock_resources,
44
+ sample_partition_date,
45
+ sample_partition_range,
46
+ sample_dlt_data,
47
+ sample_dataframe,
48
+ mock_dlt_source_fixture,
49
+ temp_staging_dir,
50
+ test_data_dir,
51
+ setup_test_catalog,
52
+ setup_test_trino,
53
+ load_json_fixture,
54
+ load_csv_fixture,
55
+ test_config,
56
+ )
57
+
58
+
59
+ @pytest.fixture(autouse=True)
60
+ def reset_test_env(monkeypatch):
61
+ """Reset environment variables before each test.
62
+
63
+ Ensures test isolation by setting PHLO_ENV and PHLO_LOG_LEVEL
64
+ before each test execution.
65
+
66
+ Args:
67
+ monkeypatch: pytest monkeypatch fixture.
68
+ """
69
+ monkeypatch.setenv("PHLO_ENV", "test")
70
+ monkeypatch.setenv("PHLO_LOG_LEVEL", "DEBUG")
71
+
72
+
73
+ @pytest.fixture
74
+ def project_root() -> Path:
75
+ """Return path to project root.
76
+
77
+ Returns:
78
+ Path to the project root directory (where pyproject.toml is located).
79
+ """
80
+ return Path(__file__).parent.parent
81
+ '''
82
+
83
+
84
+ def get_conftest_template() -> str:
85
+ """Get the conftest.py template content.
86
+
87
+ Returns:
88
+ String content for conftest.py that can be written to a file.
89
+
90
+ Example:
91
+ >>> template = get_conftest_template()
92
+ >>> Path("tests/conftest.py").write_text(template)
93
+
94
+ """
95
+ return CONFTEST_TEMPLATE
@@ -1,5 +1,4 @@
1
- """
2
- Helper to execute assets with mocked dependencies and capture results.
1
+ """Helper to execute assets with mocked dependencies and capture results.
3
2
 
4
3
  Provides `test_asset_execution()` for running `@phlo_ingestion` assets in tests
5
4
  with mocked Iceberg, Trino, and DLT dependencies.
@@ -12,6 +11,7 @@ Example:
12
11
  ... )
13
12
  >>> assert result.success
14
13
  >>> assert len(result.data) == 1
14
+
15
15
  """
16
16
 
17
17
  from __future__ import annotations
@@ -30,17 +30,20 @@ from phlo_testing.mock_trino import MockTrinoResource
30
30
 
31
31
  @dataclass
32
32
  class AssetTestResult:
33
- """
34
- Result of executing an asset in test mode.
33
+ """Result of executing an asset in test mode.
34
+
35
+ Encapsulates all information about an asset test execution including
36
+ success status, resulting data, metadata, logs, timing, and errors.
35
37
 
36
38
  Attributes:
37
- success: Whether asset execution succeeded
38
- data: Resulting DataFrame (if available)
39
- metadata: Metadata from MaterializeResult
40
- logs: Captured log messages
41
- duration: Execution time in seconds
42
- error: Exception if execution failed
43
- raw_result: Raw Dagster ExecuteInProcessResult (advanced use)
39
+ success: Whether asset execution succeeded.
40
+ data: Resulting DataFrame (if available).
41
+ metadata: Metadata from MaterializeResult.
42
+ logs: Captured log messages.
43
+ duration: Execution time in seconds.
44
+ error: Exception if execution failed.
45
+ raw_result: Raw Dagster ExecuteInProcessResult (advanced use).
46
+
44
47
  """
45
48
 
46
49
  success: bool
@@ -53,10 +56,21 @@ class AssetTestResult:
53
56
 
54
57
 
55
58
  class MockAssetContext:
56
- """
57
- Mock Dagster context for asset execution.
59
+ """Mock Dagster context for asset execution.
60
+
61
+ Provides mocked resources (Iceberg, Trino, DLT) and logging capabilities
62
+ for testing assets without requiring a full Dagster environment.
63
+
64
+ Attributes:
65
+ partition_key: Partition identifier (e.g., "2024-01-01").
66
+ iceberg: MockIcebergCatalog instance for table operations.
67
+ trino: MockTrinoResource instance for SQL execution.
68
+
69
+ Example:
70
+ >>> context = MockAssetContext(partition_key="2024-01-01")
71
+ >>> context.log("Processing partition")
72
+ >>> table_store = context.get_resource("table_store")
58
73
 
59
- Provides mocked resources (Iceberg, Trino, DLT) and logging.
60
74
  """
61
75
 
62
76
  def __init__(
@@ -65,13 +79,13 @@ class MockAssetContext:
65
79
  mock_iceberg: Optional[MockIcebergCatalog] = None,
66
80
  mock_trino: Optional[MockTrinoResource] = None,
67
81
  ) -> None:
68
- """
69
- Initialize mock context.
82
+ """Initialize mock context.
70
83
 
71
84
  Args:
72
- partition_key: Partition identifier (e.g., "2024-01-01")
73
- mock_iceberg: MockIcebergCatalog instance (creates new if None)
74
- mock_trino: MockTrinoResource instance (creates new if None)
85
+ partition_key: Partition identifier (e.g., "2024-01-01").
86
+ mock_iceberg: MockIcebergCatalog instance (creates new if None).
87
+ mock_trino: MockTrinoResource instance (creates new if None).
88
+
75
89
  """
76
90
  self.partition_key = partition_key or "2024-01-01"
77
91
  self.iceberg = mock_iceberg or MockIcebergCatalog()
@@ -81,7 +95,12 @@ class MockAssetContext:
81
95
  self._logger = self._create_logger()
82
96
 
83
97
  def _create_logger(self) -> Any:
84
- """Create logger that captures to self._logs."""
98
+ """Create logger that captures to self._logs.
99
+
100
+ Returns:
101
+ Logger instance with capture handler attached.
102
+
103
+ """
85
104
  name = f"asset_test_{id(self)}"
86
105
  logger = get_logger(name)
87
106
 
@@ -99,6 +118,7 @@ class MockAssetContext:
99
118
 
100
119
  Args:
101
120
  logs_list: Destination list for formatted log messages.
121
+
102
122
  """
103
123
  super().__init__()
104
124
  self.logs = logs_list
@@ -108,6 +128,7 @@ class MockAssetContext:
108
128
 
109
129
  Args:
110
130
  record: Log record emitted by the logger.
131
+
111
132
  """
112
133
  self.logs.append(self.format(record))
113
134
 
@@ -121,12 +142,12 @@ class MockAssetContext:
121
142
  return logger
122
143
 
123
144
  def log(self, message: str, level: str = "INFO") -> None:
124
- """
125
- Log a message.
145
+ """Log a message.
126
146
 
127
147
  Args:
128
- message: Message to log
129
- level: Log level (DEBUG, INFO, WARNING, ERROR)
148
+ message: Message to log.
149
+ level: Log level (DEBUG, INFO, WARNING, ERROR).
150
+
130
151
  """
131
152
  resolved_level = level.lower()
132
153
  if resolved_level == "warn":
@@ -135,21 +156,26 @@ class MockAssetContext:
135
156
 
136
157
  @property
137
158
  def logs(self) -> list[str]:
138
- """Get all captured logs."""
159
+ """Get all captured logs.
160
+
161
+ Returns:
162
+ List of formatted log messages.
163
+
164
+ """
139
165
  return self._logs.copy()
140
166
 
141
167
  def get_resource(self, name: str) -> Any:
142
- """
143
- Get a mock resource by name.
168
+ """Get a mock resource by name.
144
169
 
145
170
  Args:
146
- name: Resource name (table_store, trino, etc.)
171
+ name: Resource name (table_store, trino, etc.).
147
172
 
148
173
  Returns:
149
- Mock resource instance
174
+ Mock resource instance.
150
175
 
151
176
  Raises:
152
- ValueError: If resource doesn't exist
177
+ ValueError: If resource doesn't exist.
178
+
153
179
  """
154
180
  resources = {
155
181
  "table_store": self.iceberg,
@@ -172,26 +198,26 @@ def test_asset_execution(
172
198
  materialize_kwargs: Optional[dict[str, Any]] = None,
173
199
  _pytest_skip: bool = True, # Flag to prevent pytest collection
174
200
  ) -> AssetTestResult:
175
- """
176
- Execute an asset with mocked dependencies.
201
+ """Execute an asset with mocked dependencies.
177
202
 
178
203
  Runs a `@phlo_ingestion` asset in isolation with mocked Iceberg,
179
204
  Trino, and DLT services. Captures results and logs for inspection.
180
205
 
181
206
  Args:
182
- asset_fn: Asset function to test
183
- partition: Partition key (e.g., "2024-01-01")
184
- mock_data: Mock data to return from DLT source
185
- mock_iceberg: Pre-configured MockIcebergCatalog (uses new if None)
186
- mock_trino: Pre-configured MockTrinoResource (uses new if None)
187
- expected_schema: Pandera schema to validate results
188
- materialize_kwargs: Extra kwargs to pass to materialize
207
+ asset_fn: Asset function to test.
208
+ partition: Partition key (e.g., "2024-01-01").
209
+ mock_data: Mock data to return from DLT source.
210
+ mock_iceberg: Pre-configured MockIcebergCatalog (uses new if None).
211
+ mock_trino: Pre-configured MockTrinoResource (uses new if None).
212
+ expected_schema: Pandera schema to validate results.
213
+ materialize_kwargs: Extra kwargs to pass to materialize.
214
+ _pytest_skip: Flag to prevent pytest from collecting as test.
189
215
 
190
216
  Returns:
191
- AssetTestResult with execution details
217
+ AssetTestResult with execution details.
192
218
 
193
219
  Raises:
194
- ValueError: If asset execution fails (and success=False in result)
220
+ ValueError: If asset execution fails (and success=False in result).
195
221
 
196
222
  Example:
197
223
  >>> @phlo_ingestion(
@@ -207,6 +233,7 @@ def test_asset_execution(
207
233
  ... )
208
234
  >>> assert result.success
209
235
  >>> assert len(result.data) == 1
236
+
210
237
  """
211
238
  if mock_data is None:
212
239
  mock_data = []
@@ -274,27 +301,27 @@ def test_asset_with_catalog(
274
301
  partition: str = "2024-01-01",
275
302
  catalog: Optional[MockIcebergCatalog] = None,
276
303
  ) -> AssetTestResult:
277
- """
278
- Execute an asset with access to mock Iceberg catalog.
304
+ """Execute an asset with access to mock Iceberg catalog.
279
305
 
280
306
  Useful for testing assets that read from or write to Iceberg tables.
281
307
 
282
308
  Args:
283
- asset_fn: Asset function to test
284
- partition: Partition key
285
- catalog: Pre-configured MockIcebergCatalog
309
+ asset_fn: Asset function to test.
310
+ partition: Partition key.
311
+ catalog: Pre-configured MockIcebergCatalog.
286
312
 
287
313
  Returns:
288
- AssetTestResult with catalog access
314
+ AssetTestResult with catalog access.
289
315
 
290
316
  Example:
291
317
  >>> catalog = MockIcebergCatalog()
292
- >>> # ... set up tables in catalog ...
318
+ >>> # Set up tables in catalog
293
319
  >>> result = test_asset_with_catalog(
294
320
  ... my_transform_asset,
295
321
  ... partition="2024-01-01",
296
322
  ... catalog=catalog,
297
323
  ... )
324
+
298
325
  """
299
326
  if catalog is None:
300
327
  catalog = MockIcebergCatalog()
@@ -311,26 +338,26 @@ def test_asset_with_trino(
311
338
  partition: str = "2024-01-01",
312
339
  trino: Optional[MockTrinoResource] = None,
313
340
  ) -> AssetTestResult:
314
- """
315
- Execute an asset with access to mock Trino resource.
341
+ """Execute an asset with access to mock Trino resource.
316
342
 
317
343
  Useful for testing quality checks and transform assets.
318
344
 
319
345
  Args:
320
- asset_fn: Asset function to test
321
- partition: Partition key
322
- trino: Pre-configured MockTrinoResource
346
+ asset_fn: Asset function to test.
347
+ partition: Partition key.
348
+ trino: Pre-configured MockTrinoResource.
323
349
 
324
350
  Returns:
325
- AssetTestResult with Trino access
351
+ AssetTestResult with Trino access.
326
352
 
327
353
  Example:
328
354
  >>> trino = MockTrinoResource()
329
- >>> # ... set up tables ...
355
+ >>> # Set up tables in Trino
330
356
  >>> result = test_asset_with_trino(
331
357
  ... my_quality_check,
332
358
  ... trino=trino,
333
359
  ... )
360
+
334
361
  """
335
362
  if trino is None:
336
363
  trino = MockTrinoResource()
@@ -343,16 +370,21 @@ def test_asset_with_trino(
343
370
 
344
371
 
345
372
  class TestAssetExecutor:
346
- """
347
- Reusable executor for testing multiple asset runs.
373
+ """Reusable executor for testing multiple asset runs.
348
374
 
349
375
  Maintains catalog state across multiple executions for integration testing.
350
376
 
377
+ Attributes:
378
+ catalog: Shared MockIcebergCatalog instance.
379
+ trino: Shared MockTrinoResource instance.
380
+ results: List of all AssetTestResult instances from executions.
381
+
351
382
  Example:
352
383
  >>> executor = TestAssetExecutor()
353
384
  >>> result1 = executor.execute(asset1, partition="2024-01-01")
354
385
  >>> result2 = executor.execute(asset2, partition="2024-01-01")
355
386
  >>> # Both use same catalog instance
387
+
356
388
  """
357
389
 
358
390
  def __init__(
@@ -360,12 +392,12 @@ class TestAssetExecutor:
360
392
  catalog: Optional[MockIcebergCatalog] = None,
361
393
  trino: Optional[MockTrinoResource] = None,
362
394
  ) -> None:
363
- """
364
- Initialize executor.
395
+ """Initialize executor.
365
396
 
366
397
  Args:
367
- catalog: Shared MockIcebergCatalog
368
- trino: Shared MockTrinoResource
398
+ catalog: Shared MockIcebergCatalog.
399
+ trino: Shared MockTrinoResource.
400
+
369
401
  """
370
402
  self.catalog = catalog or MockIcebergCatalog()
371
403
  self.trino = trino or MockTrinoResource()
@@ -377,16 +409,16 @@ class TestAssetExecutor:
377
409
  partition: str = "2024-01-01",
378
410
  mock_data: Optional[list[dict[str, Any]]] = None,
379
411
  ) -> AssetTestResult:
380
- """
381
- Execute an asset with shared resources.
412
+ """Execute an asset with shared resources.
382
413
 
383
414
  Args:
384
- asset_fn: Asset function to test
385
- partition: Partition key
386
- mock_data: Mock data (not used in executor mode)
415
+ asset_fn: Asset function to test.
416
+ partition: Partition key.
417
+ mock_data: Mock data (not used in executor mode).
387
418
 
388
419
  Returns:
389
- AssetTestResult
420
+ AssetTestResult with execution details.
421
+
390
422
  """
391
423
  result = test_asset_execution(
392
424
  asset_fn,
@@ -399,14 +431,14 @@ class TestAssetExecutor:
399
431
  return result
400
432
 
401
433
  def get_results(self, asset_fn: Callable) -> list[AssetTestResult]:
402
- """
403
- Get results for a specific asset.
434
+ """Get results for a specific asset.
404
435
 
405
436
  Args:
406
- asset_fn: Asset function to filter by
437
+ asset_fn: Asset function to filter by.
407
438
 
408
439
  Returns:
409
- List of results for that asset
440
+ List of results for that asset.
441
+
410
442
  """
411
443
  # This is a simplified implementation
412
444
  # In practice, you'd track asset names
@@ -8,6 +8,7 @@ Example:
8
8
  >>> def test_my_asset(mock_iceberg_catalog, sample_partition_date):
9
9
  ... # Use fixtures automatically
10
10
  ... pass
11
+
11
12
  """
12
13
 
13
14
  from __future__ import annotations
@@ -44,6 +45,7 @@ def mock_iceberg_catalog() -> Iterator[MockIcebergCatalog]:
44
45
  ... "raw.users",
45
46
  ... schema=get_schema(),
46
47
  ... )
48
+
47
49
  """
48
50
  catalog = MockIcebergCatalog()
49
51
  yield catalog
@@ -61,6 +63,7 @@ def mock_trino() -> Iterator[MockTrinoResource]:
61
63
  >>> def test_with_trino(mock_trino):
62
64
  ... cursor = mock_trino.cursor()
63
65
  ... cursor.execute("SELECT 1 as id")
66
+
64
67
  """
65
68
  trino = MockTrinoResource()
66
69
  yield trino
@@ -78,6 +81,7 @@ def mock_asset_context() -> Iterator[MockAssetContext]:
78
81
  >>> def test_with_context(mock_asset_context):
79
82
  ... context.log("test message")
80
83
  ... assert "test message" in context.logs
84
+
81
85
  """
82
86
  context = MockAssetContext()
83
87
  yield context
@@ -103,6 +107,7 @@ def mock_resources(
103
107
  >>> def test_with_resources(mock_resources):
104
108
  ... table_store = mock_resources["table_store"]
105
109
  ... trino = mock_resources["trino"]
110
+
106
111
  """
107
112
  return {
108
113
  "table_store": mock_iceberg_catalog,
@@ -123,6 +128,7 @@ def sample_partition_date() -> str:
123
128
  Example:
124
129
  >>> def test_asset(sample_partition_date):
125
130
  ... assert sample_partition_date == "2024-01-15"
131
+
126
132
  """
127
133
  return "2024-01-15"
128
134
 
@@ -139,6 +145,7 @@ def sample_partition_range() -> tuple[str, str]:
139
145
  ... start, end = sample_partition_range
140
146
  ... # start = "2024-01-01"
141
147
  ... # end = "2024-01-31"
148
+
142
149
  """
143
150
  start = "2024-01-01"
144
151
  end = "2024-01-31"
@@ -155,6 +162,7 @@ def sample_dlt_data() -> list[dict[str, Any]]:
155
162
  Example:
156
163
  >>> def test_ingestion(sample_dlt_data):
157
164
  ... source = mock_dlt_source(sample_dlt_data)
165
+
158
166
  """
159
167
  return [
160
168
  {
@@ -186,6 +194,7 @@ def sample_dataframe() -> pd.DataFrame:
186
194
  Example:
187
195
  >>> def test_transform(sample_dataframe):
188
196
  ... assert len(sample_dataframe) == 3
197
+
189
198
  """
190
199
  return pd.DataFrame(
191
200
  {
@@ -206,6 +215,7 @@ def mock_dlt_source_fixture(sample_dlt_data: list[dict]) -> MockDLTResource:
206
215
  >>> def test_with_source(mock_dlt_source_fixture):
207
216
  ... for record in mock_dlt_source_fixture:
208
217
  ... # Process record
218
+
209
219
  """
210
220
  return mock_dlt_source(sample_dlt_data, resource_name="test_data")
211
221
 
@@ -224,6 +234,7 @@ def temp_staging_dir() -> Iterator[Path]:
224
234
  >>> def test_with_temp_dir(temp_staging_dir):
225
235
  ... parquet_file = temp_staging_dir / "data.parquet"
226
236
  ... df.to_parquet(parquet_file)
237
+
227
238
  """
228
239
  with tempfile.TemporaryDirectory() as tmpdir:
229
240
  yield Path(tmpdir)
@@ -239,6 +250,7 @@ def test_data_dir() -> Path:
239
250
  Example:
240
251
  >>> def test_with_data_dir(test_data_dir):
241
252
  ... data_file = test_data_dir / "users.json"
253
+
242
254
  """
243
255
  # Find project root by looking for pyproject.toml
244
256
  current = Path(__file__).parent
@@ -267,6 +279,7 @@ def setup_test_catalog(
267
279
  Example:
268
280
  >>> def test_with_setup_catalog(setup_test_catalog):
269
281
  ... table = setup_test_catalog.load_table("raw.users")
282
+
270
283
  """
271
284
  from pyiceberg.schema import Schema
272
285
  from pyiceberg.types import DoubleType, IntegerType, NestedField, StringType
@@ -298,6 +311,7 @@ def setup_test_trino(
298
311
  >>> def test_with_setup_trino(setup_test_trino):
299
312
  ... cursor = setup_test_trino.cursor()
300
313
  ... cursor.execute("SELECT * FROM test.sample_data")
314
+
301
315
  """
302
316
  mock_trino.load_table("test.sample_data", sample_dataframe)
303
317
  return mock_trino
@@ -314,6 +328,7 @@ def load_json_fixture(test_data_dir: Path) -> Callable[[str], Any]:
314
328
  Example:
315
329
  >>> def test_with_json(load_json_fixture):
316
330
  ... data = load_json_fixture("users.json")
331
+
317
332
  """
318
333
 
319
334
  def _load_json(filename: str) -> Any:
@@ -335,6 +350,7 @@ def load_csv_fixture(test_data_dir: Path) -> Callable[[str], pd.DataFrame]:
335
350
  Example:
336
351
  >>> def test_with_csv(load_csv_fixture):
337
352
  ... df = load_csv_fixture("users.csv")
353
+
338
354
  """
339
355
 
340
356
  def _load_csv(filename: str) -> pd.DataFrame:
@@ -360,6 +376,7 @@ def test_config() -> dict[str, Any]:
360
376
  Example:
361
377
  >>> def test_with_config(test_config, monkeypatch):
362
378
  ... monkeypatch.setenv("PHLO_ENV", "test")
379
+
363
380
  """
364
381
  return {
365
382
  "environment": "test",
@@ -381,6 +398,7 @@ def session_temp_dir() -> Iterator[Path]:
381
398
  Example:
382
399
  >>> def test_with_session_dir(session_temp_dir):
383
400
  ... # Shared across all tests in session
401
+
384
402
  """
385
403
  with tempfile.TemporaryDirectory() as tmpdir:
386
404
  yield Path(tmpdir)
@@ -396,6 +414,7 @@ def session_catalog() -> Iterator[MockIcebergCatalog]:
396
414
  Example:
397
415
  >>> def test_with_session_catalog(session_catalog):
398
416
  ... # Shared across all tests
417
+
399
418
  """
400
419
  catalog = MockIcebergCatalog()
401
420
  yield catalog
@@ -420,6 +439,7 @@ def create_partition_dates(start: str, end: str, step_days: int = 1) -> list[str
420
439
  Example:
421
440
  >>> dates = create_partition_dates("2024-01-01", "2024-01-31", step_days=7)
422
441
  >>> # ["2024-01-01", "2024-01-08", "2024-01-15", ...]
442
+
423
443
  """
424
444
  start_dt = datetime.fromisoformat(start)
425
445
  end_dt = datetime.fromisoformat(end)
@@ -443,5 +463,6 @@ def conftest_template() -> str:
443
463
 
444
464
  Returns:
445
465
  String content for conftest.py
466
+
446
467
  """
447
468
  return get_conftest_template()