openlineage-python 1.28.0__tar.gz → 1.30.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.
- {openlineage_python-1.28.0 → openlineage_python-1.30.0}/PKG-INFO +1 -1
- {openlineage_python-1.28.0 → openlineage_python-1.30.0}/openlineage/client/client.py +59 -1
- {openlineage_python-1.28.0 → openlineage_python-1.30.0}/openlineage/client/constants.py +1 -1
- openlineage_python-1.30.0/openlineage/client/tags.py +17 -0
- {openlineage_python-1.28.0 → openlineage_python-1.30.0}/pyproject.toml +1 -1
- openlineage_python-1.30.0/tests/conftest.py +54 -0
- {openlineage_python-1.28.0 → openlineage_python-1.30.0}/tests/test_client.py +202 -1
- openlineage_python-1.28.0/tests/conftest.py +0 -18
- {openlineage_python-1.28.0 → openlineage_python-1.30.0}/.gitignore +0 -0
- {openlineage_python-1.28.0 → openlineage_python-1.30.0}/README.md +0 -0
- {openlineage_python-1.28.0 → openlineage_python-1.30.0}/docs/Makefile +0 -0
- {openlineage_python-1.28.0 → openlineage_python-1.30.0}/docs/conf.py +0 -0
- {openlineage_python-1.28.0 → openlineage_python-1.30.0}/docs/convert.py +0 -0
- {openlineage_python-1.28.0 → openlineage_python-1.30.0}/docs/index.rst +0 -0
- {openlineage_python-1.28.0 → openlineage_python-1.30.0}/docs/make.bat +0 -0
- {openlineage_python-1.28.0 → openlineage_python-1.30.0}/docs/source/openlineage.client.rst +0 -0
- {openlineage_python-1.28.0 → openlineage_python-1.30.0}/openlineage/client/__init__.py +0 -0
- {openlineage_python-1.28.0 → openlineage_python-1.30.0}/openlineage/client/event_v2.py +0 -0
- {openlineage_python-1.28.0 → openlineage_python-1.30.0}/openlineage/client/facet.py +0 -0
- {openlineage_python-1.28.0 → openlineage_python-1.30.0}/openlineage/client/facet_v2.py +0 -0
- {openlineage_python-1.28.0 → openlineage_python-1.30.0}/openlineage/client/facets.py +0 -0
- {openlineage_python-1.28.0 → openlineage_python-1.30.0}/openlineage/client/filter.py +0 -0
- {openlineage_python-1.28.0 → openlineage_python-1.30.0}/openlineage/client/generated/base.py +0 -0
- {openlineage_python-1.28.0 → openlineage_python-1.30.0}/openlineage/client/generated/column_lineage_dataset.py +0 -0
- {openlineage_python-1.28.0 → openlineage_python-1.30.0}/openlineage/client/generated/data_quality_assertions_dataset.py +0 -0
- {openlineage_python-1.28.0 → openlineage_python-1.30.0}/openlineage/client/generated/data_quality_metrics_input_dataset.py +0 -0
- {openlineage_python-1.28.0 → openlineage_python-1.30.0}/openlineage/client/generated/dataset_type_dataset.py +0 -0
- {openlineage_python-1.28.0 → openlineage_python-1.30.0}/openlineage/client/generated/dataset_version_dataset.py +0 -0
- {openlineage_python-1.28.0 → openlineage_python-1.30.0}/openlineage/client/generated/datasource_dataset.py +0 -0
- {openlineage_python-1.28.0 → openlineage_python-1.30.0}/openlineage/client/generated/documentation_dataset.py +0 -0
- {openlineage_python-1.28.0 → openlineage_python-1.30.0}/openlineage/client/generated/documentation_job.py +0 -0
- {openlineage_python-1.28.0 → openlineage_python-1.30.0}/openlineage/client/generated/environment_variables_run.py +0 -0
- {openlineage_python-1.28.0 → openlineage_python-1.30.0}/openlineage/client/generated/error_message_run.py +0 -0
- {openlineage_python-1.28.0 → openlineage_python-1.30.0}/openlineage/client/generated/external_query_run.py +0 -0
- {openlineage_python-1.28.0 → openlineage_python-1.30.0}/openlineage/client/generated/extraction_error_run.py +0 -0
- {openlineage_python-1.28.0 → openlineage_python-1.30.0}/openlineage/client/generated/input_statistics_input_dataset.py +0 -0
- {openlineage_python-1.28.0 → openlineage_python-1.30.0}/openlineage/client/generated/job_type_job.py +0 -0
- {openlineage_python-1.28.0 → openlineage_python-1.30.0}/openlineage/client/generated/lifecycle_state_change_dataset.py +0 -0
- {openlineage_python-1.28.0 → openlineage_python-1.30.0}/openlineage/client/generated/nominal_time_run.py +0 -0
- {openlineage_python-1.28.0 → openlineage_python-1.30.0}/openlineage/client/generated/output_statistics_output_dataset.py +0 -0
- {openlineage_python-1.28.0 → openlineage_python-1.30.0}/openlineage/client/generated/ownership_dataset.py +0 -0
- {openlineage_python-1.28.0 → openlineage_python-1.30.0}/openlineage/client/generated/ownership_job.py +0 -0
- {openlineage_python-1.28.0 → openlineage_python-1.30.0}/openlineage/client/generated/parent_run.py +0 -0
- {openlineage_python-1.28.0 → openlineage_python-1.30.0}/openlineage/client/generated/processing_engine_run.py +0 -0
- {openlineage_python-1.28.0 → openlineage_python-1.30.0}/openlineage/client/generated/schema_dataset.py +0 -0
- {openlineage_python-1.28.0 → openlineage_python-1.30.0}/openlineage/client/generated/source_code_job.py +0 -0
- {openlineage_python-1.28.0 → openlineage_python-1.30.0}/openlineage/client/generated/source_code_location_job.py +0 -0
- {openlineage_python-1.28.0 → openlineage_python-1.30.0}/openlineage/client/generated/sql_job.py +0 -0
- {openlineage_python-1.28.0 → openlineage_python-1.30.0}/openlineage/client/generated/storage_dataset.py +0 -0
- {openlineage_python-1.28.0 → openlineage_python-1.30.0}/openlineage/client/generated/symlinks_dataset.py +0 -0
- {openlineage_python-1.28.0 → openlineage_python-1.30.0}/openlineage/client/generated/tags_dataset.py +0 -0
- {openlineage_python-1.28.0 → openlineage_python-1.30.0}/openlineage/client/generated/tags_job.py +0 -0
- {openlineage_python-1.28.0 → openlineage_python-1.30.0}/openlineage/client/generated/tags_run.py +0 -0
- {openlineage_python-1.28.0 → openlineage_python-1.30.0}/openlineage/client/py.typed +0 -0
- {openlineage_python-1.28.0 → openlineage_python-1.30.0}/openlineage/client/run.py +0 -0
- {openlineage_python-1.28.0 → openlineage_python-1.30.0}/openlineage/client/serde.py +0 -0
- {openlineage_python-1.28.0 → openlineage_python-1.30.0}/openlineage/client/transport/__init__.py +0 -0
- {openlineage_python-1.28.0 → openlineage_python-1.30.0}/openlineage/client/transport/composite.py +0 -0
- {openlineage_python-1.28.0 → openlineage_python-1.30.0}/openlineage/client/transport/console.py +0 -0
- {openlineage_python-1.28.0 → openlineage_python-1.30.0}/openlineage/client/transport/factory.py +0 -0
- {openlineage_python-1.28.0 → openlineage_python-1.30.0}/openlineage/client/transport/file.py +0 -0
- {openlineage_python-1.28.0 → openlineage_python-1.30.0}/openlineage/client/transport/http.py +0 -0
- {openlineage_python-1.28.0 → openlineage_python-1.30.0}/openlineage/client/transport/kafka.py +0 -0
- {openlineage_python-1.28.0 → openlineage_python-1.30.0}/openlineage/client/transport/msk_iam.py +0 -0
- {openlineage_python-1.28.0 → openlineage_python-1.30.0}/openlineage/client/transport/noop.py +0 -0
- {openlineage_python-1.28.0 → openlineage_python-1.30.0}/openlineage/client/transport/transport.py +0 -0
- {openlineage_python-1.28.0 → openlineage_python-1.30.0}/openlineage/client/utils.py +0 -0
- {openlineage_python-1.28.0 → openlineage_python-1.30.0}/openlineage/client/uuid.py +0 -0
- {openlineage_python-1.28.0 → openlineage_python-1.30.0}/redact_fields.yml +0 -0
- {openlineage_python-1.28.0 → openlineage_python-1.30.0}/tests/__init__.py +0 -0
- {openlineage_python-1.28.0 → openlineage_python-1.30.0}/tests/config/config.yml +0 -0
- {openlineage_python-1.28.0 → openlineage_python-1.30.0}/tests/config/exact_filter.yml +0 -0
- {openlineage_python-1.28.0 → openlineage_python-1.30.0}/tests/config/http.yml +0 -0
- {openlineage_python-1.28.0 → openlineage_python-1.30.0}/tests/config/openlineage.yml +0 -0
- {openlineage_python-1.28.0 → openlineage_python-1.30.0}/tests/config/regex_filter.yml +0 -0
- {openlineage_python-1.28.0 → openlineage_python-1.30.0}/tests/example_full_event.json +0 -0
- {openlineage_python-1.28.0 → openlineage_python-1.30.0}/tests/nominal_time_without_end.json +0 -0
- {openlineage_python-1.28.0 → openlineage_python-1.30.0}/tests/serde_example_dataset_event.json +0 -0
- {openlineage_python-1.28.0 → openlineage_python-1.30.0}/tests/serde_example_job_event.json +0 -0
- {openlineage_python-1.28.0 → openlineage_python-1.30.0}/tests/serde_example_run_event.json +0 -0
- {openlineage_python-1.28.0 → openlineage_python-1.30.0}/tests/test_composite.py +0 -0
- {openlineage_python-1.28.0 → openlineage_python-1.30.0}/tests/test_events.py +0 -0
- {openlineage_python-1.28.0 → openlineage_python-1.30.0}/tests/test_facet.py +0 -0
- {openlineage_python-1.28.0 → openlineage_python-1.30.0}/tests/test_facet_v2.py +0 -0
- {openlineage_python-1.28.0 → openlineage_python-1.30.0}/tests/test_factory.py +0 -0
- {openlineage_python-1.28.0 → openlineage_python-1.30.0}/tests/test_file.py +0 -0
- {openlineage_python-1.28.0 → openlineage_python-1.30.0}/tests/test_http.py +0 -0
- {openlineage_python-1.28.0 → openlineage_python-1.30.0}/tests/test_kafka.py +0 -0
- {openlineage_python-1.28.0 → openlineage_python-1.30.0}/tests/test_msk_iam.py +0 -0
- {openlineage_python-1.28.0 → openlineage_python-1.30.0}/tests/test_utils.py +0 -0
- {openlineage_python-1.28.0 → openlineage_python-1.30.0}/tests/test_uuid.py +0 -0
- {openlineage_python-1.28.0 → openlineage_python-1.30.0}/tests/transport.py +0 -0
- {openlineage_python-1.28.0 → openlineage_python-1.30.0}/tox.ini +0 -0
|
@@ -12,6 +12,7 @@ import attr
|
|
|
12
12
|
import yaml
|
|
13
13
|
from openlineage.client.filter import Filter, FilterConfig, create_filter
|
|
14
14
|
from openlineage.client.serde import Serde
|
|
15
|
+
from openlineage.client.tags import TagsConfig
|
|
15
16
|
from openlineage.client.utils import deep_merge_dicts
|
|
16
17
|
|
|
17
18
|
if TYPE_CHECKING:
|
|
@@ -26,6 +27,8 @@ from openlineage.client.generated.environment_variables_run import (
|
|
|
26
27
|
EnvironmentVariable,
|
|
27
28
|
EnvironmentVariablesRunFacet,
|
|
28
29
|
)
|
|
30
|
+
from openlineage.client.generated.tags_job import TagsJobFacet, TagsJobFacetFields
|
|
31
|
+
from openlineage.client.generated.tags_run import TagsRunFacet, TagsRunFacetFields
|
|
29
32
|
from openlineage.client.run import DatasetEvent, JobEvent, RunEvent
|
|
30
33
|
from openlineage.client.transport import (
|
|
31
34
|
Transport,
|
|
@@ -53,6 +56,7 @@ class OpenLineageConfig:
|
|
|
53
56
|
transport: dict[str, Any] | None = attr.ib(factory=dict)
|
|
54
57
|
facets: FacetsConfig = attr.ib(factory=FacetsConfig)
|
|
55
58
|
filters: list[FilterConfig] = attr.ib(factory=list)
|
|
59
|
+
tags: TagsConfig = attr.ib(factory=TagsConfig)
|
|
56
60
|
|
|
57
61
|
@classmethod
|
|
58
62
|
def from_dict(cls, params: dict[str, Any]) -> OpenLineageConfig:
|
|
@@ -63,6 +67,13 @@ class OpenLineageConfig:
|
|
|
63
67
|
config.facets = FacetsConfig(**params["facets"])
|
|
64
68
|
if "filters" in params:
|
|
65
69
|
config.filters = [FilterConfig(**filter_config) for filter_config in params["filters"]]
|
|
70
|
+
if "tags" in params:
|
|
71
|
+
job_tags = params["tags"].get("job", {})
|
|
72
|
+
run_tags = params["tags"].get("run", {})
|
|
73
|
+
config.tags = TagsConfig(
|
|
74
|
+
job=[TagsJobFacetFields(key, value, "USER") for (key, value) in job_tags.items()],
|
|
75
|
+
run=[TagsRunFacetFields(key, value, "USER") for (key, value) in run_tags.items()],
|
|
76
|
+
)
|
|
66
77
|
return config
|
|
67
78
|
|
|
68
79
|
|
|
@@ -163,6 +174,7 @@ class OpenLineageClient:
|
|
|
163
174
|
return
|
|
164
175
|
|
|
165
176
|
event = self.add_environment_facets(event)
|
|
177
|
+
event = self.update_event_tags_facets(event)
|
|
166
178
|
|
|
167
179
|
if log.isEnabledFor(logging.DEBUG):
|
|
168
180
|
val = Serde.to_json(event).encode("utf-8")
|
|
@@ -362,7 +374,6 @@ class OpenLineageClient:
|
|
|
362
374
|
# Parse value (try to parse as JSON, otherwise lowercase the value)
|
|
363
375
|
with contextlib.suppress(json.JSONDecodeError):
|
|
364
376
|
env_value = json.loads(env_value) # noqa: PLW2901
|
|
365
|
-
|
|
366
377
|
cls._insert_into_config(config, keys, env_value)
|
|
367
378
|
|
|
368
379
|
return config
|
|
@@ -404,3 +415,50 @@ class OpenLineageClient:
|
|
|
404
415
|
missing_vars,
|
|
405
416
|
)
|
|
406
417
|
return filtered_vars
|
|
418
|
+
|
|
419
|
+
def update_event_tags_facets(self, event: Event) -> Event:
|
|
420
|
+
"""
|
|
421
|
+
Creates or updates job and run tag facets based on user-supplied environment variables
|
|
422
|
+
"""
|
|
423
|
+
tags_job = self.config.tags.job
|
|
424
|
+
if (isinstance(event, (JobEvent, RunEvent))) and tags_job:
|
|
425
|
+
tags_facet = event.job.facets.get("tags", TagsJobFacet())
|
|
426
|
+
event.job.facets["tags"] = self._update_tag_facet(tags_facet, tags_job) # type: ignore [arg-type]
|
|
427
|
+
|
|
428
|
+
tags_run = self.config.tags.run
|
|
429
|
+
if (isinstance(event, RunEvent)) and tags_run:
|
|
430
|
+
tags_facet = event.run.facets.get("tags", TagsRunFacet())
|
|
431
|
+
event.run.facets["tags"] = self._update_tag_facet(tags_facet, tags_run) # type: ignore [arg-type]
|
|
432
|
+
|
|
433
|
+
return event
|
|
434
|
+
|
|
435
|
+
def _update_tag_facet(
|
|
436
|
+
self,
|
|
437
|
+
tags_facet: TagsJobFacet | TagsRunFacet,
|
|
438
|
+
user_tags: list[TagsJobFacetFields | TagsRunFacetFields],
|
|
439
|
+
) -> TagsJobFacet | TagsRunFacet:
|
|
440
|
+
"""
|
|
441
|
+
Handles updating tags in an existing tag facet
|
|
442
|
+
"""
|
|
443
|
+
|
|
444
|
+
# Get tags from the facet that will not be updated (Do not have the same key as a user tag)
|
|
445
|
+
user_tag_keys = [tag.key for tag in user_tags]
|
|
446
|
+
keep_tags = []
|
|
447
|
+
if tags_facet.tags is not None:
|
|
448
|
+
keep_tags = [tag for tag in tags_facet.tags if tag.key.lower() not in user_tag_keys]
|
|
449
|
+
|
|
450
|
+
# Update tag key for any user tags that should override a facet tag.
|
|
451
|
+
# This preserves case of the facet tag key while updating value and source.
|
|
452
|
+
facet_tag_keys = {}
|
|
453
|
+
if tags_facet.tags is not None:
|
|
454
|
+
facet_tag_keys = {tag.key.lower(): tag.key for tag in tags_facet.tags}
|
|
455
|
+
|
|
456
|
+
for user_tag in user_tags:
|
|
457
|
+
if user_tag.key in facet_tag_keys:
|
|
458
|
+
facet_tag_key = facet_tag_keys[user_tag.key]
|
|
459
|
+
log.info("Overriding integration-supplied tag `%s` with user-supplied tag", facet_tag_key)
|
|
460
|
+
user_tag.key = facet_tag_key
|
|
461
|
+
|
|
462
|
+
all_tags = keep_tags + user_tags
|
|
463
|
+
tags_facet.tags = all_tags # type: ignore [assignment]
|
|
464
|
+
return tags_facet
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Copyright 2018-2025 contributors to the OpenLineage project
|
|
2
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import TYPE_CHECKING
|
|
6
|
+
|
|
7
|
+
import attr
|
|
8
|
+
|
|
9
|
+
if TYPE_CHECKING:
|
|
10
|
+
from openlineage.client.generated.tags_job import TagsJobFacetFields
|
|
11
|
+
from openlineage.client.generated.tags_run import TagsRunFacetFields
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@attr.s
|
|
15
|
+
class TagsConfig:
|
|
16
|
+
job: list[TagsJobFacetFields] = attr.ib(factory=list)
|
|
17
|
+
run: list[TagsRunFacetFields] = attr.ib(factory=list)
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# Copyright 2018-2025 contributors to the OpenLineage project
|
|
2
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import Union
|
|
7
|
+
|
|
8
|
+
import pytest
|
|
9
|
+
from openlineage.client import event_v2, set_producer
|
|
10
|
+
from openlineage.client.run import DatasetEvent, JobEvent, RunEvent
|
|
11
|
+
from openlineage.client.transport.transport import Config, Transport
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@pytest.fixture(scope="session")
|
|
15
|
+
def root() -> Path:
|
|
16
|
+
return Path(__file__).parent
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@pytest.fixture(scope="session", autouse=True)
|
|
20
|
+
def _setup_producer() -> None:
|
|
21
|
+
set_producer("https://github.com/OpenLineage/OpenLineage/tree/0.0.1/client/python")
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
# For testing events emitted by the client
|
|
25
|
+
|
|
26
|
+
Event_v1 = Union[RunEvent, DatasetEvent, JobEvent]
|
|
27
|
+
Event_v2 = Union[event_v2.RunEvent, event_v2.DatasetEvent, event_v2.JobEvent]
|
|
28
|
+
Event = Union[Event_v1, Event_v2]
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class NoOutputConfig(Config):
|
|
32
|
+
...
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class NoOutputTransport(Transport):
|
|
36
|
+
"""Minimal transport that stores the event for assertions"""
|
|
37
|
+
|
|
38
|
+
kind = "no_output"
|
|
39
|
+
config_class = NoOutputConfig
|
|
40
|
+
|
|
41
|
+
def __init__(self, config: NoOutputConfig) -> None: # noqa: ARG002
|
|
42
|
+
self._event = None
|
|
43
|
+
|
|
44
|
+
def emit(self, event: Event) -> None:
|
|
45
|
+
self._event = event
|
|
46
|
+
|
|
47
|
+
@property
|
|
48
|
+
def event(self):
|
|
49
|
+
return self._event
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
@pytest.fixture(scope="session")
|
|
53
|
+
def transport():
|
|
54
|
+
return NoOutputTransport(config=NoOutputConfig())
|
|
@@ -15,6 +15,8 @@ from openlineage.client.generated.environment_variables_run import (
|
|
|
15
15
|
EnvironmentVariable,
|
|
16
16
|
EnvironmentVariablesRunFacet,
|
|
17
17
|
)
|
|
18
|
+
from openlineage.client.generated.tags_job import TagsJobFacet, TagsJobFacetFields
|
|
19
|
+
from openlineage.client.generated.tags_run import TagsRunFacet, TagsRunFacetFields
|
|
18
20
|
from openlineage.client.run import (
|
|
19
21
|
SCHEMA_URL,
|
|
20
22
|
Dataset,
|
|
@@ -82,7 +84,6 @@ def test_client_passes_to_create_with_valid_url(url: str, res: str) -> None:
|
|
|
82
84
|
def test_client_sends_proper_json_with_minimal_run_event() -> None:
|
|
83
85
|
session = MagicMock()
|
|
84
86
|
client = OpenLineageClient(url="http://example.com", session=session)
|
|
85
|
-
|
|
86
87
|
client.emit(
|
|
87
88
|
RunEvent(
|
|
88
89
|
RunState.START,
|
|
@@ -839,6 +840,31 @@ class TestOpenLineageConfigLoader:
|
|
|
839
840
|
},
|
|
840
841
|
{"transport": {"type": "console"}},
|
|
841
842
|
),
|
|
843
|
+
(
|
|
844
|
+
{
|
|
845
|
+
"OPENLINEAGE__TAGS__JOB__ENVIRONMENT": "PRODUCTION",
|
|
846
|
+
"OPENLINEAGE__TAGS__JOB__pipeline": "finance",
|
|
847
|
+
"OPENLINEAGE__TAGS__RUN__environment": "PRODUCTION",
|
|
848
|
+
"OPENLINEAGE__TAGS__RUN__pipeline": "finance",
|
|
849
|
+
},
|
|
850
|
+
{
|
|
851
|
+
"tags": {
|
|
852
|
+
"job": {"environment": "PRODUCTION", "pipeline": "finance"},
|
|
853
|
+
"run": {"environment": "PRODUCTION", "pipeline": "finance"},
|
|
854
|
+
}
|
|
855
|
+
},
|
|
856
|
+
),
|
|
857
|
+
(
|
|
858
|
+
{
|
|
859
|
+
"OPENLINEAGE__TAGS": '{"job": {"a": "b", "c": "d"}, "run": {"a": "b", "c": "d"}}',
|
|
860
|
+
},
|
|
861
|
+
{
|
|
862
|
+
"tags": {
|
|
863
|
+
"job": {"a": "b", "c": "d"},
|
|
864
|
+
"run": {"a": "b", "c": "d"},
|
|
865
|
+
}
|
|
866
|
+
},
|
|
867
|
+
),
|
|
842
868
|
],
|
|
843
869
|
)
|
|
844
870
|
@patch.dict(os.environ, {})
|
|
@@ -846,3 +872,178 @@ class TestOpenLineageConfigLoader:
|
|
|
846
872
|
with patch.dict(os.environ, env_vars):
|
|
847
873
|
config = OpenLineageClient._load_config_from_env_variables() # noqa: SLF001
|
|
848
874
|
assert config == expected_config
|
|
875
|
+
|
|
876
|
+
|
|
877
|
+
def test_update_job_tag_facet_creates_new_facet(transport):
|
|
878
|
+
tag_environment_variables = {
|
|
879
|
+
"OPENLINEAGE__TAGS__JOB__ENVIRONMENT": "PRODUCTION",
|
|
880
|
+
"OPENLINEAGE__TAGS__JOB__pipeline": "SALES",
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
run_event = RunEvent(
|
|
884
|
+
RunState.START,
|
|
885
|
+
"2021-11-03T10:53:52.427343",
|
|
886
|
+
Run("69f4acab-b87d-4fc0-b27b-8ea950370ff3"),
|
|
887
|
+
Job("openlineage", "job"),
|
|
888
|
+
"producer",
|
|
889
|
+
)
|
|
890
|
+
|
|
891
|
+
tags = [
|
|
892
|
+
TagsJobFacetFields("environment", "PRODUCTION", "USER"),
|
|
893
|
+
TagsJobFacetFields("pipeline", "SALES", "USER"),
|
|
894
|
+
]
|
|
895
|
+
|
|
896
|
+
with patch.dict(os.environ, tag_environment_variables):
|
|
897
|
+
client = OpenLineageClient(transport=transport)
|
|
898
|
+
client.emit(run_event)
|
|
899
|
+
assert transport.event.job.facets.get("tags")
|
|
900
|
+
event_tags = sorted(transport.event.job.facets["tags"].tags, key=lambda x: x.key)
|
|
901
|
+
expected_tags = sorted(tags, key=lambda x: x.key)
|
|
902
|
+
assert event_tags == expected_tags
|
|
903
|
+
|
|
904
|
+
|
|
905
|
+
def test_update_job_tag_facet_updates_existing_facet(transport):
|
|
906
|
+
tag_environment_variables = {
|
|
907
|
+
"OPENLINEAGE__TAGS__JOB__ENVIRONMENT": "PRODUCTION",
|
|
908
|
+
"OPENLINEAGE__TAGS__JOB__pipeline": "SALES",
|
|
909
|
+
}
|
|
910
|
+
|
|
911
|
+
run_event = RunEvent(
|
|
912
|
+
RunState.START,
|
|
913
|
+
"2021-11-03T10:53:52.427343",
|
|
914
|
+
Run("69f4acab-b87d-4fc0-b27b-8ea950370ff3"),
|
|
915
|
+
Job(
|
|
916
|
+
namespace="openlineage",
|
|
917
|
+
name="job",
|
|
918
|
+
facets={
|
|
919
|
+
"tags": TagsRunFacet(
|
|
920
|
+
tags=[
|
|
921
|
+
TagsJobFacetFields("environment", "STAGING", "USER"),
|
|
922
|
+
TagsJobFacetFields("foo", "bar", "USER"),
|
|
923
|
+
]
|
|
924
|
+
)
|
|
925
|
+
},
|
|
926
|
+
),
|
|
927
|
+
"producer",
|
|
928
|
+
)
|
|
929
|
+
|
|
930
|
+
# One existing tag (not updated), one existing tag (updated), one new tag from the user
|
|
931
|
+
tags = [
|
|
932
|
+
TagsJobFacetFields("foo", "bar", "USER"),
|
|
933
|
+
TagsJobFacetFields("environment", "PRODUCTION", "USER"),
|
|
934
|
+
TagsJobFacetFields("pipeline", "SALES", "USER"),
|
|
935
|
+
]
|
|
936
|
+
|
|
937
|
+
with patch.dict(os.environ, tag_environment_variables):
|
|
938
|
+
client = OpenLineageClient(transport=transport)
|
|
939
|
+
client.emit(run_event)
|
|
940
|
+
assert transport.event.job.facets.get("tags")
|
|
941
|
+
event_tags = sorted(transport.event.job.facets["tags"].tags, key=lambda x: x.key)
|
|
942
|
+
expected_tags = sorted(tags, key=lambda x: x.key)
|
|
943
|
+
assert event_tags == expected_tags
|
|
944
|
+
|
|
945
|
+
|
|
946
|
+
def test_update_run_tag_facet_creates_new_facet(transport):
|
|
947
|
+
tag_environment_variables = {
|
|
948
|
+
"OPENLINEAGE__TAGS__RUN__ENVIRONMENT": "PRODUCTION",
|
|
949
|
+
"OPENLINEAGE__TAGS__RUN__pipeline": "SALES",
|
|
950
|
+
}
|
|
951
|
+
|
|
952
|
+
run_event = RunEvent(
|
|
953
|
+
RunState.START,
|
|
954
|
+
"2021-11-03T10:53:52.427343",
|
|
955
|
+
Run("69f4acab-b87d-4fc0-b27b-8ea950370ff3"),
|
|
956
|
+
Job("openlineage", "job"),
|
|
957
|
+
"producer",
|
|
958
|
+
)
|
|
959
|
+
|
|
960
|
+
tags = [
|
|
961
|
+
TagsRunFacetFields("environment", "PRODUCTION", "USER"),
|
|
962
|
+
TagsRunFacetFields("pipeline", "SALES", "USER"),
|
|
963
|
+
]
|
|
964
|
+
|
|
965
|
+
with patch.dict(os.environ, tag_environment_variables):
|
|
966
|
+
client = OpenLineageClient(transport=transport)
|
|
967
|
+
client.emit(run_event)
|
|
968
|
+
assert transport.event.run.facets.get("tags")
|
|
969
|
+
event_tags = sorted(transport.event.run.facets["tags"].tags, key=lambda x: x.key)
|
|
970
|
+
expected_tags = sorted(tags, key=lambda x: x.key)
|
|
971
|
+
assert event_tags == expected_tags
|
|
972
|
+
|
|
973
|
+
|
|
974
|
+
def test_update_run_tag_facet_updates_existing_facet(transport):
|
|
975
|
+
tag_environment_variables = {
|
|
976
|
+
"OPENLINEAGE__TAGS__RUN__ENVIRONMENT": "PRODUCTION",
|
|
977
|
+
"OPENLINEAGE__TAGS__RUN__pipeline": "SALES",
|
|
978
|
+
}
|
|
979
|
+
|
|
980
|
+
run_event = RunEvent(
|
|
981
|
+
RunState.START,
|
|
982
|
+
"2021-11-03T10:53:52.427343",
|
|
983
|
+
Run(
|
|
984
|
+
runId="69f4acab-b87d-4fc0-b27b-8ea950370ff3",
|
|
985
|
+
facets={
|
|
986
|
+
"tags": TagsJobFacet(
|
|
987
|
+
tags=[
|
|
988
|
+
TagsRunFacetFields("ENVIRONMENT", "STAGING", "USER"),
|
|
989
|
+
TagsRunFacetFields("foo", "bar", "USER"),
|
|
990
|
+
]
|
|
991
|
+
)
|
|
992
|
+
},
|
|
993
|
+
),
|
|
994
|
+
Job("openlineage", "job"),
|
|
995
|
+
"producer",
|
|
996
|
+
)
|
|
997
|
+
|
|
998
|
+
# One existing tag (not updated), one existing tag (updated), one new tag from the user
|
|
999
|
+
tags = [
|
|
1000
|
+
TagsRunFacetFields("foo", "bar", "USER"),
|
|
1001
|
+
TagsRunFacetFields("ENVIRONMENT", "PRODUCTION", "USER"),
|
|
1002
|
+
TagsRunFacetFields("pipeline", "SALES", "USER"),
|
|
1003
|
+
]
|
|
1004
|
+
|
|
1005
|
+
with patch.dict(os.environ, tag_environment_variables):
|
|
1006
|
+
client = OpenLineageClient(transport=transport)
|
|
1007
|
+
client.emit(run_event)
|
|
1008
|
+
assert transport.event.run.facets.get("tags")
|
|
1009
|
+
event_tags = sorted(transport.event.run.facets["tags"].tags, key=lambda x: x.key)
|
|
1010
|
+
expected_tags = sorted(tags, key=lambda x: x.key)
|
|
1011
|
+
assert event_tags == expected_tags
|
|
1012
|
+
|
|
1013
|
+
|
|
1014
|
+
def test_update_tag_facet_keeps_key_case(transport):
|
|
1015
|
+
tag_environment_variables = {
|
|
1016
|
+
"OPENLINEAGE__TAGS__RUN__ENVIRONMENT": "PRODUCTION",
|
|
1017
|
+
"OPENLINEAGE__TAGS__RUN__pipeline": "SALES",
|
|
1018
|
+
}
|
|
1019
|
+
|
|
1020
|
+
run_event = RunEvent(
|
|
1021
|
+
RunState.START,
|
|
1022
|
+
"2021-11-03T10:53:52.427343",
|
|
1023
|
+
Run(
|
|
1024
|
+
runId="69f4acab-b87d-4fc0-b27b-8ea950370ff3",
|
|
1025
|
+
facets={
|
|
1026
|
+
"tags": TagsJobFacet(
|
|
1027
|
+
tags=[
|
|
1028
|
+
TagsRunFacetFields("environment", "STAGING", "USER"),
|
|
1029
|
+
TagsRunFacetFields("PIPELINE", "FINANCE", "USER"),
|
|
1030
|
+
]
|
|
1031
|
+
)
|
|
1032
|
+
},
|
|
1033
|
+
),
|
|
1034
|
+
Job("openlineage", "job"),
|
|
1035
|
+
"producer",
|
|
1036
|
+
)
|
|
1037
|
+
|
|
1038
|
+
tags = [
|
|
1039
|
+
TagsRunFacetFields("environment", "PRODUCTION", "USER"),
|
|
1040
|
+
TagsRunFacetFields("PIPELINE", "SALES", "USER"),
|
|
1041
|
+
]
|
|
1042
|
+
|
|
1043
|
+
with patch.dict(os.environ, tag_environment_variables):
|
|
1044
|
+
client = OpenLineageClient(transport=transport)
|
|
1045
|
+
client.emit(run_event)
|
|
1046
|
+
assert transport.event.run.facets.get("tags")
|
|
1047
|
+
event_tags = sorted(transport.event.run.facets["tags"].tags, key=lambda x: x.key)
|
|
1048
|
+
expected_tags = sorted(tags, key=lambda x: x.key)
|
|
1049
|
+
assert event_tags == expected_tags
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
# Copyright 2018-2025 contributors to the OpenLineage project
|
|
2
|
-
# SPDX-License-Identifier: Apache-2.0
|
|
3
|
-
from __future__ import annotations
|
|
4
|
-
|
|
5
|
-
from pathlib import Path
|
|
6
|
-
|
|
7
|
-
import pytest
|
|
8
|
-
from openlineage.client import set_producer
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
@pytest.fixture(scope="session")
|
|
12
|
-
def root() -> Path:
|
|
13
|
-
return Path(__file__).parent
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
@pytest.fixture(scope="session", autouse=True)
|
|
17
|
-
def _setup_producer() -> None:
|
|
18
|
-
set_producer("https://github.com/OpenLineage/OpenLineage/tree/0.0.1/client/python")
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{openlineage_python-1.28.0 → openlineage_python-1.30.0}/openlineage/client/generated/base.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{openlineage_python-1.28.0 → openlineage_python-1.30.0}/openlineage/client/generated/job_type_job.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{openlineage_python-1.28.0 → openlineage_python-1.30.0}/openlineage/client/generated/parent_run.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{openlineage_python-1.28.0 → openlineage_python-1.30.0}/openlineage/client/generated/sql_job.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{openlineage_python-1.28.0 → openlineage_python-1.30.0}/openlineage/client/generated/tags_dataset.py
RENAMED
|
File without changes
|
{openlineage_python-1.28.0 → openlineage_python-1.30.0}/openlineage/client/generated/tags_job.py
RENAMED
|
File without changes
|
{openlineage_python-1.28.0 → openlineage_python-1.30.0}/openlineage/client/generated/tags_run.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{openlineage_python-1.28.0 → openlineage_python-1.30.0}/openlineage/client/transport/__init__.py
RENAMED
|
File without changes
|
{openlineage_python-1.28.0 → openlineage_python-1.30.0}/openlineage/client/transport/composite.py
RENAMED
|
File without changes
|
{openlineage_python-1.28.0 → openlineage_python-1.30.0}/openlineage/client/transport/console.py
RENAMED
|
File without changes
|
{openlineage_python-1.28.0 → openlineage_python-1.30.0}/openlineage/client/transport/factory.py
RENAMED
|
File without changes
|
{openlineage_python-1.28.0 → openlineage_python-1.30.0}/openlineage/client/transport/file.py
RENAMED
|
File without changes
|
{openlineage_python-1.28.0 → openlineage_python-1.30.0}/openlineage/client/transport/http.py
RENAMED
|
File without changes
|
{openlineage_python-1.28.0 → openlineage_python-1.30.0}/openlineage/client/transport/kafka.py
RENAMED
|
File without changes
|
{openlineage_python-1.28.0 → openlineage_python-1.30.0}/openlineage/client/transport/msk_iam.py
RENAMED
|
File without changes
|
{openlineage_python-1.28.0 → openlineage_python-1.30.0}/openlineage/client/transport/noop.py
RENAMED
|
File without changes
|
{openlineage_python-1.28.0 → openlineage_python-1.30.0}/openlineage/client/transport/transport.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{openlineage_python-1.28.0 → openlineage_python-1.30.0}/tests/serde_example_dataset_event.json
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|