openlineage-python 1.32.1__tar.gz → 1.34.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 (116) hide show
  1. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/PKG-INFO +3 -1
  2. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/openlineage/client/client.py +20 -21
  3. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/openlineage/client/constants.py +1 -1
  4. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/openlineage/client/facet_v2.py +2 -0
  5. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/openlineage/client/facets.py +2 -2
  6. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/openlineage/client/filter.py +4 -4
  7. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/openlineage/client/generated/base.py +1 -1
  8. openlineage_python-1.34.0/openlineage/client/generated/catalog_dataset.py +32 -0
  9. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/openlineage/client/generated/column_lineage_dataset.py +3 -3
  10. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/openlineage/client/generated/documentation_dataset.py +4 -1
  11. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/openlineage/client/generated/documentation_job.py +4 -1
  12. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/openlineage/client/generator/templates/dataclass.jinja2 +1 -1
  13. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/openlineage/client/tags.py +3 -3
  14. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/openlineage/client/transport/__init__.py +18 -5
  15. openlineage_python-1.34.0/openlineage/client/transport/amazon_datazone.py +77 -0
  16. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/openlineage/client/transport/composite.py +4 -3
  17. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/openlineage/client/transport/http.py +11 -11
  18. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/openlineage/client/transport/kafka.py +5 -5
  19. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/openlineage/client/transport/msk_iam.py +5 -5
  20. openlineage_python-1.34.0/openlineage/client/transport/transform/__init__.py +19 -0
  21. openlineage_python-1.34.0/openlineage/client/transport/transform/transform.py +144 -0
  22. openlineage_python-1.34.0/openlineage/client/transport/transform/transformers/job_namespace_replace_transformer.py +74 -0
  23. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/openlineage/client/transport/transport.py +1 -1
  24. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/pyproject.toml +4 -1
  25. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/redact_fields.yml +4 -0
  26. openlineage_python-1.34.0/tests/generator/__init__.py +2 -0
  27. openlineage_python-1.34.0/tests/test_amazon_datazone.py +123 -0
  28. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/tests/test_events.py +9 -9
  29. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/tests/test_facet.py +18 -0
  30. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/tests/test_facet_v2.py +48 -3
  31. openlineage_python-1.34.0/tests/test_uuid.py +102 -0
  32. openlineage_python-1.34.0/tests/transform/__init__.py +2 -0
  33. openlineage_python-1.34.0/tests/transform/test_transform.py +471 -0
  34. openlineage_python-1.34.0/tests/transform/transformers/__init__.py +2 -0
  35. openlineage_python-1.34.0/tests/transform/transformers/test_job_namespace_replace_transformer.py +184 -0
  36. openlineage_python-1.32.1/tests/test_uuid.py +0 -54
  37. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/.gitignore +0 -0
  38. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/README.md +0 -0
  39. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/docs/Makefile +0 -0
  40. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/docs/conf.py +0 -0
  41. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/docs/convert.py +0 -0
  42. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/docs/index.rst +0 -0
  43. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/docs/make.bat +0 -0
  44. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/docs/source/openlineage.client.rst +0 -0
  45. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/openlineage/client/__init__.py +0 -0
  46. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/openlineage/client/event_v2.py +0 -0
  47. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/openlineage/client/facet.py +0 -0
  48. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/openlineage/client/generated/data_quality_assertions_dataset.py +0 -0
  49. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/openlineage/client/generated/data_quality_metrics_input_dataset.py +0 -0
  50. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/openlineage/client/generated/dataset_type_dataset.py +0 -0
  51. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/openlineage/client/generated/dataset_version_dataset.py +0 -0
  52. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/openlineage/client/generated/datasource_dataset.py +0 -0
  53. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/openlineage/client/generated/environment_variables_run.py +0 -0
  54. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/openlineage/client/generated/error_message_run.py +0 -0
  55. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/openlineage/client/generated/external_query_run.py +0 -0
  56. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/openlineage/client/generated/extraction_error_run.py +0 -0
  57. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/openlineage/client/generated/input_statistics_input_dataset.py +0 -0
  58. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/openlineage/client/generated/job_type_job.py +0 -0
  59. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/openlineage/client/generated/lifecycle_state_change_dataset.py +0 -0
  60. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/openlineage/client/generated/nominal_time_run.py +0 -0
  61. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/openlineage/client/generated/output_statistics_output_dataset.py +0 -0
  62. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/openlineage/client/generated/ownership_dataset.py +0 -0
  63. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/openlineage/client/generated/ownership_job.py +0 -0
  64. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/openlineage/client/generated/parent_run.py +0 -0
  65. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/openlineage/client/generated/processing_engine_run.py +0 -0
  66. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/openlineage/client/generated/schema_dataset.py +0 -0
  67. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/openlineage/client/generated/source_code_job.py +0 -0
  68. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/openlineage/client/generated/source_code_location_job.py +0 -0
  69. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/openlineage/client/generated/sql_job.py +0 -0
  70. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/openlineage/client/generated/storage_dataset.py +0 -0
  71. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/openlineage/client/generated/symlinks_dataset.py +0 -0
  72. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/openlineage/client/generated/tags_dataset.py +0 -0
  73. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/openlineage/client/generated/tags_job.py +0 -0
  74. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/openlineage/client/generated/tags_run.py +0 -0
  75. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/openlineage/client/generator/base.py +0 -0
  76. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/openlineage/client/generator/cli.py +0 -0
  77. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/openlineage/client/generator/generate.py +0 -0
  78. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/openlineage/client/generator/header.py +0 -0
  79. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/openlineage/client/generator/templates/Enum.jinja2 +0 -0
  80. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/openlineage/client/generator/templates/facet_v2.jinja2 +0 -0
  81. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/openlineage/client/generator/templates/root.jinja2 +0 -0
  82. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/openlineage/client/generator/templates/validators.jinja2 +0 -0
  83. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/openlineage/client/py.typed +0 -0
  84. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/openlineage/client/run.py +0 -0
  85. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/openlineage/client/serde.py +0 -0
  86. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/openlineage/client/transport/console.py +0 -0
  87. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/openlineage/client/transport/factory.py +0 -0
  88. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/openlineage/client/transport/file.py +0 -0
  89. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/openlineage/client/transport/noop.py +0 -0
  90. {openlineage_python-1.32.1/tests → openlineage_python-1.34.0/openlineage/client/transport/transform/transformers}/__init__.py +0 -0
  91. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/openlineage/client/utils.py +0 -0
  92. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/openlineage/client/uuid.py +0 -0
  93. {openlineage_python-1.32.1/tests/generator → openlineage_python-1.34.0/tests}/__init__.py +0 -0
  94. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/tests/config/config.yml +0 -0
  95. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/tests/config/exact_filter.yml +0 -0
  96. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/tests/config/http.yml +0 -0
  97. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/tests/config/openlineage.yml +0 -0
  98. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/tests/config/regex_filter.yml +0 -0
  99. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/tests/conftest.py +0 -0
  100. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/tests/example_full_event.json +0 -0
  101. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/tests/generator/test_base.py +0 -0
  102. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/tests/generator/test_cli.py +0 -0
  103. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/tests/nominal_time_without_end.json +0 -0
  104. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/tests/serde_example_dataset_event.json +0 -0
  105. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/tests/serde_example_job_event.json +0 -0
  106. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/tests/serde_example_run_event.json +0 -0
  107. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/tests/test_client.py +0 -0
  108. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/tests/test_composite.py +0 -0
  109. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/tests/test_factory.py +0 -0
  110. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/tests/test_file.py +0 -0
  111. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/tests/test_http.py +0 -0
  112. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/tests/test_kafka.py +0 -0
  113. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/tests/test_msk_iam.py +0 -0
  114. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/tests/test_utils.py +0 -0
  115. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/tests/transport.py +0 -0
  116. {openlineage_python-1.32.1 → openlineage_python-1.34.0}/tox.ini +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: openlineage-python
3
- Version: 1.32.1
3
+ Version: 1.34.0
4
4
  Summary: OpenLineage Python Client
5
5
  Author-email: OpenLineage <info@openlineage.io>
6
6
  Keywords: openlineage
@@ -18,6 +18,8 @@ Requires-Dist: packaging>=21.0
18
18
  Requires-Dist: python-dateutil>=2.8.2
19
19
  Requires-Dist: pyyaml>=5.4
20
20
  Requires-Dist: requests>=2.32.3
21
+ Provides-Extra: datazone
22
+ Requires-Dist: boto3>=1.34.134; extra == 'datazone'
21
23
  Provides-Extra: docs
22
24
  Requires-Dist: beautifulsoup4>=4.12.0; extra == 'docs'
23
25
  Requires-Dist: pydata-sphinx-theme>=0.13; extra == 'docs'
@@ -2,6 +2,7 @@
2
2
  # SPDX-License-Identifier: Apache-2.0
3
3
  from __future__ import annotations
4
4
 
5
+ import contextlib
5
6
  import json
6
7
  import logging
7
8
  import os
@@ -10,19 +11,9 @@ from typing import TYPE_CHECKING, Any, TypeVar, Union, cast
10
11
 
11
12
  import attr
12
13
  import yaml
13
- from openlineage.client.filter import Filter, FilterConfig, create_filter
14
- from openlineage.client.serde import Serde
15
- from openlineage.client.tags import TagsConfig
16
- from openlineage.client.utils import deep_merge_dicts
17
-
18
- if TYPE_CHECKING:
19
- from requests import Session
20
- from requests.adapters import HTTPAdapter
21
-
22
- import contextlib
23
-
24
14
  from openlineage.client import event_v2
25
15
  from openlineage.client.facets import FacetsConfig
16
+ from openlineage.client.filter import Filter, FilterConfig, create_filter
26
17
  from openlineage.client.generated.environment_variables_run import (
27
18
  EnvironmentVariable,
28
19
  EnvironmentVariablesRunFacet,
@@ -30,6 +21,8 @@ from openlineage.client.generated.environment_variables_run import (
30
21
  from openlineage.client.generated.tags_job import TagsJobFacet, TagsJobFacetFields
31
22
  from openlineage.client.generated.tags_run import TagsRunFacet, TagsRunFacetFields
32
23
  from openlineage.client.run import DatasetEvent, JobEvent, RunEvent
24
+ from openlineage.client.serde import Serde
25
+ from openlineage.client.tags import TagsConfig
33
26
  from openlineage.client.transport import (
34
27
  Transport,
35
28
  TransportFactory,
@@ -37,26 +30,32 @@ from openlineage.client.transport import (
37
30
  )
38
31
  from openlineage.client.transport.http import HttpConfig, HttpTransport, create_token_provider
39
32
  from openlineage.client.transport.noop import NoopConfig, NoopTransport
33
+ from openlineage.client.utils import deep_merge_dicts
34
+
35
+ if TYPE_CHECKING:
36
+ from requests import Session
37
+ from requests.adapters import HTTPAdapter
38
+
40
39
 
41
40
  Event_v1 = Union[RunEvent, DatasetEvent, JobEvent]
42
41
  Event_v2 = Union[event_v2.RunEvent, event_v2.DatasetEvent, event_v2.JobEvent]
43
42
  Event = Union[Event_v1, Event_v2]
44
43
 
45
44
 
46
- @attr.s
45
+ @attr.define
47
46
  class OpenLineageClientOptions:
48
- timeout: float = attr.ib(default=5.0)
49
- verify: bool = attr.ib(default=True)
50
- api_key: str = attr.ib(default=None)
51
- adapter: HTTPAdapter = attr.ib(default=None)
47
+ timeout: float = 5.0
48
+ verify: bool = True
49
+ api_key: str | None = None
50
+ adapter: HTTPAdapter | None = None
52
51
 
53
52
 
54
- @attr.s
53
+ @attr.define
55
54
  class OpenLineageConfig:
56
- transport: dict[str, Any] | None = attr.ib(factory=dict)
57
- facets: FacetsConfig = attr.ib(factory=FacetsConfig)
58
- filters: list[FilterConfig] = attr.ib(factory=list)
59
- tags: TagsConfig = attr.ib(factory=TagsConfig)
55
+ transport: dict[str, Any] | None = attr.field(factory=dict)
56
+ facets: FacetsConfig = attr.field(factory=FacetsConfig)
57
+ filters: list[FilterConfig] = attr.field(factory=list)
58
+ tags: TagsConfig = attr.field(factory=TagsConfig)
60
59
 
61
60
  @classmethod
62
61
  def from_dict(cls, params: dict[str, Any]) -> OpenLineageConfig:
@@ -2,7 +2,7 @@
2
2
  # SPDX-License-Identifier: Apache-2.0
3
3
  from __future__ import annotations
4
4
 
5
- __version__ = "1.32.1"
5
+ __version__ = "1.34.0"
6
6
 
7
7
  DEFAULT_TIMEOUT_MS = 5000
8
8
  DEFAULT_NAMESPACE_NAME = "default"
@@ -2,6 +2,7 @@
2
2
  # SPDX-License-Identifier: Apache-2.0
3
3
 
4
4
  from openlineage.client.generated import (
5
+ catalog_dataset,
5
6
  column_lineage_dataset,
6
7
  data_quality_assertions_dataset,
7
8
  data_quality_metrics_input_dataset,
@@ -53,6 +54,7 @@ __all__ = [
53
54
  "OutputDatasetFacet",
54
55
  "RunFacet",
55
56
  "set_producer",
57
+ "catalog_dataset",
56
58
  "column_lineage_dataset",
57
59
  "data_quality_assertions_dataset",
58
60
  "data_quality_metrics_input_dataset",
@@ -5,6 +5,6 @@ from __future__ import annotations
5
5
  import attr
6
6
 
7
7
 
8
- @attr.s
8
+ @attr.define
9
9
  class FacetsConfig:
10
- environment_variables: list[str] = attr.ib(factory=list)
10
+ environment_variables: list[str] = attr.field(factory=list)
@@ -14,11 +14,11 @@ log = logging.getLogger(__name__)
14
14
  RunEventType = typing.Union[RunEvent, RunEvent_v2]
15
15
 
16
16
 
17
- @attr.s
17
+ @attr.define
18
18
  class FilterConfig:
19
- type: str | None = attr.ib(default=None)
20
- match: str | None = attr.ib(default=None)
21
- regex: str | None = attr.ib(default=None)
19
+ type: str | None = None
20
+ match: str | None = None
21
+ regex: str | None = None
22
22
 
23
23
 
24
24
  class Filter:
@@ -92,7 +92,7 @@ class BaseFacet(RedactMixin):
92
92
 
93
93
  new_class = attr.make_class(
94
94
  self.__class__.__name__,
95
- {k: attr.field() for k in kwargs if k not in current_attrs},
95
+ {k: attr.field(default=None) for k in kwargs if k not in current_attrs},
96
96
  bases=(self.__class__,),
97
97
  )
98
98
  new_class.__module__ = self.__class__.__module__
@@ -0,0 +1,32 @@
1
+ # Copyright 2018-2025 contributors to the OpenLineage project
2
+ # SPDX-License-Identifier: Apache-2.0
3
+
4
+ from __future__ import annotations
5
+
6
+ import attr
7
+ from openlineage.client.generated.base import DatasetFacet
8
+
9
+
10
+ @attr.define
11
+ class CatalogDatasetFacet(DatasetFacet):
12
+ framework: str
13
+ """The storage framework for which the catalog is configured"""
14
+
15
+ type: str
16
+ """Type of the catalog."""
17
+
18
+ name: str
19
+ """Name of the catalog, as configured in the source system."""
20
+
21
+ metadataUri: str | None = attr.field(default=None) # noqa: N815
22
+ """URI or connection string to the catalog, if applicable."""
23
+
24
+ warehouseUri: str | None = attr.field(default=None) # noqa: N815
25
+ """URI or connection string to the physical location of the data that the catalog describes."""
26
+
27
+ source: str | None = attr.field(default=None)
28
+ """Source system where the catalog is configured."""
29
+
30
+ @staticmethod
31
+ def _get_schema() -> str:
32
+ return "https://openlineage.io/spec/facets/1-0-0/CatalogDatasetFacet.json#/$defs/CatalogDatasetFacet"
@@ -44,7 +44,7 @@ class Fields(RedactMixin):
44
44
 
45
45
  new_class = attr.make_class(
46
46
  self.__class__.__name__,
47
- {k: attr.field() for k in kwargs if k not in current_attrs},
47
+ {k: attr.field(default=None) for k in kwargs if k not in current_attrs},
48
48
  bases=(self.__class__,),
49
49
  )
50
50
  new_class.__module__ = self.__class__.__module__
@@ -81,7 +81,7 @@ class InputField(RedactMixin):
81
81
 
82
82
  new_class = attr.make_class(
83
83
  self.__class__.__name__,
84
- {k: attr.field() for k in kwargs if k not in current_attrs},
84
+ {k: attr.field(default=None) for k in kwargs if k not in current_attrs},
85
85
  bases=(self.__class__,),
86
86
  )
87
87
  new_class.__module__ = self.__class__.__module__
@@ -122,7 +122,7 @@ class Transformation(RedactMixin):
122
122
 
123
123
  new_class = attr.make_class(
124
124
  self.__class__.__name__,
125
- {k: attr.field() for k in kwargs if k not in current_attrs},
125
+ {k: attr.field(default=None) for k in kwargs if k not in current_attrs},
126
126
  bases=(self.__class__,),
127
127
  )
128
128
  new_class.__module__ = self.__class__.__module__
@@ -12,6 +12,9 @@ class DocumentationDatasetFacet(DatasetFacet):
12
12
  description: str
13
13
  """The description of the dataset."""
14
14
 
15
+ contentType: str | None = attr.field(default=None) # noqa: N815
16
+ """MIME type of the description field content."""
17
+
15
18
  @staticmethod
16
19
  def _get_schema() -> str:
17
- return "https://openlineage.io/spec/facets/1-0-1/DocumentationDatasetFacet.json#/$defs/DocumentationDatasetFacet"
20
+ return "https://openlineage.io/spec/facets/1-1-0/DocumentationDatasetFacet.json#/$defs/DocumentationDatasetFacet"
@@ -12,8 +12,11 @@ class DocumentationJobFacet(JobFacet):
12
12
  description: str
13
13
  """The description of the job."""
14
14
 
15
+ contentType: str | None = attr.field(default=None) # noqa: N815
16
+ """MIME type of the description field content."""
17
+
15
18
  @staticmethod
16
19
  def _get_schema() -> str:
17
20
  return (
18
- "https://openlineage.io/spec/facets/1-0-1/DocumentationJobFacet.json#/$defs/DocumentationJobFacet"
21
+ "https://openlineage.io/spec/facets/1-1-0/DocumentationJobFacet.json#/$defs/DocumentationJobFacet"
19
22
  )
@@ -157,7 +157,7 @@ class {{ class_name }}:
157
157
 
158
158
  new_class = attr.make_class(
159
159
  self.__class__.__name__,
160
- {k: attr.field() for k in kwargs if k not in current_attrs},
160
+ {k: attr.field(default=None) for k in kwargs if k not in current_attrs},
161
161
  bases=(self.__class__,),
162
162
  )
163
163
  new_class.__module__ = self.__class__.__module__
@@ -11,7 +11,7 @@ if TYPE_CHECKING:
11
11
  from openlineage.client.generated.tags_run import TagsRunFacetFields
12
12
 
13
13
 
14
- @attr.s
14
+ @attr.define
15
15
  class TagsConfig:
16
- job: list[TagsJobFacetFields] = attr.ib(factory=list)
17
- run: list[TagsRunFacetFields] = attr.ib(factory=list)
16
+ job: list[TagsJobFacetFields] = attr.field(factory=list)
17
+ run: list[TagsRunFacetFields] = attr.field(factory=list)
@@ -2,6 +2,7 @@
2
2
  # SPDX-License-Identifier: Apache-2.0
3
3
  from __future__ import annotations
4
4
 
5
+ from openlineage.client.transport.amazon_datazone import AmazonDataZoneConfig, AmazonDataZoneTransport
5
6
  from openlineage.client.transport.composite import CompositeTransport
6
7
  from openlineage.client.transport.console import ConsoleTransport
7
8
  from openlineage.client.transport.factory import DefaultTransportFactory
@@ -10,6 +11,10 @@ from openlineage.client.transport.http import HttpConfig, HttpTransport
10
11
  from openlineage.client.transport.kafka import KafkaConfig, KafkaTransport
11
12
  from openlineage.client.transport.msk_iam import MSKIAMConfig, MSKIAMTransport
12
13
  from openlineage.client.transport.noop import NoopTransport
14
+ from openlineage.client.transport.transform.transform import (
15
+ TransformConfig,
16
+ TransformTransport,
17
+ )
13
18
  from openlineage.client.transport.transport import Config, Transport, TransportFactory
14
19
 
15
20
  _factory = DefaultTransportFactory()
@@ -20,6 +25,8 @@ _factory.register_transport(MSKIAMTransport.kind, MSKIAMTransport)
20
25
  _factory.register_transport(ConsoleTransport.kind, ConsoleTransport)
21
26
  _factory.register_transport(NoopTransport.kind, NoopTransport)
22
27
  _factory.register_transport(FileTransport.kind, FileTransport)
28
+ _factory.register_transport(TransformTransport.kind, TransformTransport)
29
+ _factory.register_transport(AmazonDataZoneTransport.kind, AmazonDataZoneTransport)
23
30
 
24
31
 
25
32
  def get_default_factory() -> DefaultTransportFactory:
@@ -34,17 +41,23 @@ def register_transport(clazz: type[Transport]) -> type[Transport]:
34
41
 
35
42
 
36
43
  __all__ = [
44
+ "register_transport",
45
+ "get_default_factory",
37
46
  "Config",
47
+ "Transport",
38
48
  "TransportFactory",
49
+ "AmazonDataZoneConfig",
50
+ "AmazonDataZoneTransport",
51
+ "CompositeTransport",
52
+ "ConsoleTransport",
53
+ "FileTransport",
39
54
  "HttpConfig",
40
55
  "HttpTransport",
41
56
  "KafkaConfig",
42
57
  "KafkaTransport",
43
- "MSKIAMTransport",
44
58
  "MSKIAMConfig",
45
- "ConsoleTransport",
59
+ "MSKIAMTransport",
46
60
  "NoopTransport",
47
- "Transport",
48
- "register_transport",
49
- "get_default_factory",
61
+ "TransformConfig",
62
+ "TransformTransport",
50
63
  ]
@@ -0,0 +1,77 @@
1
+ # Copyright 2018-2025 contributors to the OpenLineage project
2
+ # SPDX-License-Identifier: Apache-2.0
3
+
4
+ from __future__ import annotations
5
+
6
+ import logging
7
+ from dataclasses import dataclass
8
+ from typing import TYPE_CHECKING, Any
9
+
10
+ from openlineage.client import event_v2
11
+ from openlineage.client.run import RunEvent
12
+ from openlineage.client.serde import Serde
13
+ from openlineage.client.transport.transport import Config, Transport
14
+
15
+ if TYPE_CHECKING:
16
+ from openlineage.client.client import Event
17
+
18
+ log = logging.getLogger(__name__)
19
+
20
+
21
+ @dataclass
22
+ class AmazonDataZoneConfig(Config):
23
+ domain_id: str
24
+ endpoint_override: str | None = None
25
+
26
+ @classmethod
27
+ def from_dict(cls, params: dict[str, Any]) -> AmazonDataZoneConfig:
28
+ if "domainId" not in params:
29
+ msg = "`domainId` key not passed to AmazonDataZoneConfig"
30
+ raise RuntimeError(msg)
31
+ return cls(domain_id=params["domainId"], endpoint_override=params.get("endpointOverride"))
32
+
33
+
34
+ class AmazonDataZoneTransport(Transport):
35
+ kind = "amazon_datazone_api"
36
+ config_class = AmazonDataZoneConfig
37
+
38
+ def __init__(self, config: AmazonDataZoneConfig) -> None:
39
+ self.config = config
40
+ self.datazone = None
41
+
42
+ self._setup_datazone(self.config.endpoint_override)
43
+ log.debug(
44
+ "Constructing OpenLineage transport that will send events to Amazon DataZone domain `%s`.",
45
+ config.domain_id,
46
+ )
47
+
48
+ def emit(self, event: Event) -> None:
49
+ if not isinstance(event, (RunEvent, event_v2.RunEvent)):
50
+ # DataZone only supports RunEvent
51
+ log.warning("DataZone only supports RunEvent")
52
+ return
53
+ try:
54
+ response = self.datazone.post_lineage_event( # type: ignore[attr-defined]
55
+ domainIdentifier=self.config.domain_id, event=Serde.to_json(event).encode("utf-8")
56
+ )
57
+ log.info(
58
+ "Successfully posted a LineageEvent: %s in Domain: %s", response["id"], response["domainId"]
59
+ )
60
+ except Exception as error: # noqa: BLE001
61
+ msg = f"Failed to send lineage event to DataZone Domain {self.config.domain_id}: {event}"
62
+ raise RuntimeError(msg) from error
63
+
64
+ def _setup_datazone(self, endpoint_url: str | None = None) -> None:
65
+ try:
66
+ import boto3 # type: ignore[import-untyped]
67
+
68
+ self.datazone = boto3.client("datazone", endpoint_url=endpoint_url)
69
+ except (ImportError, ModuleNotFoundError):
70
+ log.exception(
71
+ "OpenLineage client could not import the boto3 module. "
72
+ "This could be due to boto3 not being installed or being corrupted. "
73
+ "DataZoneTransport requires boto3 to function properly. "
74
+ "Please ensure boto3 is installed correctly. "
75
+ "You can install or reinstall it via `pip install boto3`"
76
+ )
77
+ raise
@@ -17,7 +17,7 @@ if TYPE_CHECKING:
17
17
  log = logging.getLogger(__name__)
18
18
 
19
19
 
20
- @attr.s
20
+ @attr.define
21
21
  class CompositeConfig(Config):
22
22
  """
23
23
  CompositeConfig is a configuration class for CompositeTransport.
@@ -36,8 +36,8 @@ class CompositeConfig(Config):
36
36
  transport will halt the emission process for subsequent transports.
37
37
  """
38
38
 
39
- transports: list[dict[str, Any]] | dict[str, dict[str, Any]] = attr.ib()
40
- continue_on_failure: bool = attr.ib(default=True)
39
+ transports: list[dict[str, Any]] | dict[str, dict[str, Any]]
40
+ continue_on_failure: bool = True
41
41
 
42
42
  @classmethod
43
43
  def from_dict(cls, params: dict[str, Any]) -> CompositeConfig:
@@ -86,6 +86,7 @@ class CompositeTransport(Transport):
86
86
  except Exception as e: # noqa: BLE001
87
87
  if self.config.continue_on_failure:
88
88
  log.warning("Transport %s failed to emit event with error: %s", transport, e)
89
+ log.debug("OpenLineage emission failure details:", exc_info=True)
89
90
  else:
90
91
  msg = f"Transport {transport} failed to emit event"
91
92
  raise RuntimeError(msg) from e
@@ -76,23 +76,23 @@ def get_session() -> Session:
76
76
  return Session()
77
77
 
78
78
 
79
- @attr.s
79
+ @attr.define
80
80
  class HttpConfig(Config):
81
- url: str = attr.ib()
82
- endpoint: str = attr.ib(default="api/v1/lineage")
83
- timeout: float = attr.ib(default=5.0)
81
+ url: str
82
+ endpoint: str = "api/v1/lineage"
83
+ timeout: float = 5.0
84
84
  # check TLS certificates
85
- verify: bool = attr.ib(default=True)
86
- auth: TokenProvider = attr.ib(factory=lambda: TokenProvider({}))
87
- compression: HttpCompression | None = attr.ib(default=None)
85
+ verify: bool = True
86
+ auth: TokenProvider = attr.field(factory=lambda: TokenProvider({}))
87
+ compression: HttpCompression | None = None
88
88
  # not set by TransportFactory
89
- session: Session | None = attr.ib(default=None)
89
+ session: Session | None = None
90
90
  # not set by TransportFactory
91
- adapter: HTTPAdapter | None = attr.ib(default=None)
91
+ adapter: HTTPAdapter | None = None
92
92
  # custom headers support
93
- custom_headers: dict[str, str] = attr.ib(factory=dict)
93
+ custom_headers: dict[str, str] = attr.field(factory=dict)
94
94
  # retry settings
95
- retry: dict[str, Any] = attr.ib(
95
+ retry: dict[str, Any] = attr.field(
96
96
  default={
97
97
  "total": 5,
98
98
  "read": 5,
@@ -24,21 +24,21 @@ log = logging.getLogger(__name__)
24
24
  _T = TypeVar("_T", bound="KafkaConfig")
25
25
 
26
26
 
27
- @attr.s
27
+ @attr.define
28
28
  class KafkaConfig(Config):
29
29
  # Kafka producer config
30
30
  # https://docs.confluent.io/platform/current/clients/confluent-kafka-python/html/index.html#kafka-client-configuration
31
- config: dict[str, str] = attr.ib()
31
+ config: dict[str, str]
32
32
 
33
33
  # Topic on which we should send messages
34
- topic: str = attr.ib()
34
+ topic: str
35
35
 
36
36
  # Explicit key for Kafka producer
37
- messageKey: str | None = attr.ib(default=None) # noqa: N815
37
+ messageKey: str | None = None # noqa: N815
38
38
 
39
39
  # Set to true if Kafka should flush after each event. The process that emits can be killed in
40
40
  # some cases - for example in Airflow integration, so flushing is desirable there.
41
- flush: bool = attr.ib(default=True)
41
+ flush: bool = True
42
42
 
43
43
  @classmethod
44
44
  def from_dict(cls: type[_T], params: dict[str, Any]) -> _T:
@@ -32,15 +32,15 @@ def _detect_running_region() -> None | str:
32
32
  return None
33
33
 
34
34
 
35
- @attr.s
35
+ @attr.define
36
36
  class MSKIAMConfig(KafkaConfig):
37
37
  # MSK producer config
38
38
  # https://github.com/aws/aws-msk-iam-sasl-signer-python
39
39
 
40
- region: str = attr.ib(default=None)
41
- aws_profile: None | str = attr.ib(default=None)
42
- role_arn: None | str = attr.ib(default=None)
43
- aws_debug_creds: bool = attr.ib(default=False)
40
+ region: str | None = None
41
+ aws_profile: None | str = None
42
+ role_arn: None | str = None
43
+ aws_debug_creds: bool = False
44
44
 
45
45
 
46
46
  def _oauth_cb(config: MSKIAMConfig, *_: Any) -> tuple[str, float]:
@@ -0,0 +1,19 @@
1
+ # Copyright 2018-2025 contributors to the OpenLineage project
2
+ # SPDX-License-Identifier: Apache-2.0
3
+ from __future__ import annotations
4
+
5
+ from openlineage.client.transport.transform.transform import (
6
+ EventTransformer,
7
+ TransformConfig,
8
+ TransformTransport,
9
+ )
10
+ from openlineage.client.transport.transform.transformers.job_namespace_replace_transformer import (
11
+ JobNamespaceReplaceTransformer,
12
+ )
13
+
14
+ __all__ = [
15
+ "EventTransformer",
16
+ "TransformConfig",
17
+ "TransformTransport",
18
+ "JobNamespaceReplaceTransformer",
19
+ ]