airbyte-cdk 6.60.0.post14.dev16483785754__py3-none-any.whl → 6.60.0.post16.dev16484674380__py3-none-any.whl
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.
- airbyte_cdk/models/airbyte_protocol.py +0 -84
- airbyte_cdk/models/airbyte_protocol_serializers.py +85 -23
- airbyte_cdk/test/entrypoint_wrapper.py +8 -6
- {airbyte_cdk-6.60.0.post14.dev16483785754.dist-info → airbyte_cdk-6.60.0.post16.dev16484674380.dist-info}/METADATA +1 -1
- {airbyte_cdk-6.60.0.post14.dev16483785754.dist-info → airbyte_cdk-6.60.0.post16.dev16484674380.dist-info}/RECORD +9 -9
- {airbyte_cdk-6.60.0.post14.dev16483785754.dist-info → airbyte_cdk-6.60.0.post16.dev16484674380.dist-info}/LICENSE.txt +0 -0
- {airbyte_cdk-6.60.0.post14.dev16483785754.dist-info → airbyte_cdk-6.60.0.post16.dev16484674380.dist-info}/LICENSE_SHORT +0 -0
- {airbyte_cdk-6.60.0.post14.dev16483785754.dist-info → airbyte_cdk-6.60.0.post16.dev16484674380.dist-info}/WHEEL +0 -0
- {airbyte_cdk-6.60.0.post14.dev16483785754.dist-info → airbyte_cdk-6.60.0.post16.dev16484674380.dist-info}/entry_points.txt +0 -0
@@ -7,87 +7,3 @@ from dataclasses import InitVar, dataclass
|
|
7
7
|
from typing import Annotated, Any, Dict, List, Mapping, Optional, Union
|
8
8
|
|
9
9
|
from airbyte_protocol_dataclasses.models import * # noqa: F403 # Allow '*'
|
10
|
-
|
11
|
-
if sys.platform == 'emscripten':
|
12
|
-
from serpyco.metadata import Alias
|
13
|
-
else:
|
14
|
-
from serpyco_rs.metadata import Alias
|
15
|
-
|
16
|
-
# ruff: noqa: F405 # ignore fuzzy import issues with 'import *'
|
17
|
-
|
18
|
-
|
19
|
-
@dataclass
|
20
|
-
class AirbyteStateBlob:
|
21
|
-
"""
|
22
|
-
A dataclass that dynamically sets attributes based on provided keyword arguments and positional arguments.
|
23
|
-
Used to "mimic" pydantic Basemodel with ConfigDict(extra='allow') option.
|
24
|
-
|
25
|
-
The `AirbyteStateBlob` class allows for flexible instantiation by accepting any number of keyword arguments
|
26
|
-
and positional arguments. These are used to dynamically update the instance's attributes. This class is useful
|
27
|
-
in scenarios where the attributes of an object are not known until runtime and need to be set dynamically.
|
28
|
-
|
29
|
-
Attributes:
|
30
|
-
kwargs (InitVar[Mapping[str, Any]]): A dictionary of keyword arguments used to set attributes dynamically.
|
31
|
-
|
32
|
-
Methods:
|
33
|
-
__init__(*args: Any, **kwargs: Any) -> None:
|
34
|
-
Initializes the `AirbyteStateBlob` by setting attributes from the provided arguments.
|
35
|
-
|
36
|
-
__eq__(other: object) -> bool:
|
37
|
-
Checks equality between two `AirbyteStateBlob` instances based on their internal dictionaries.
|
38
|
-
Returns `False` if the other object is not an instance of `AirbyteStateBlob`.
|
39
|
-
"""
|
40
|
-
|
41
|
-
kwargs: InitVar[Mapping[str, Any]]
|
42
|
-
|
43
|
-
def __init__(self, *args: Any, **kwargs: Any) -> None:
|
44
|
-
# Set any attribute passed in through kwargs
|
45
|
-
for arg in args:
|
46
|
-
self.__dict__.update(arg)
|
47
|
-
for key, value in kwargs.items():
|
48
|
-
setattr(self, key, value)
|
49
|
-
|
50
|
-
def __eq__(self, other: object) -> bool:
|
51
|
-
return (
|
52
|
-
False
|
53
|
-
if not isinstance(other, AirbyteStateBlob)
|
54
|
-
else bool(self.__dict__ == other.__dict__)
|
55
|
-
)
|
56
|
-
|
57
|
-
|
58
|
-
# The following dataclasses have been redeclared to include the new version of AirbyteStateBlob
|
59
|
-
@dataclass
|
60
|
-
class AirbyteStreamState:
|
61
|
-
stream_descriptor: StreamDescriptor # type: ignore [name-defined]
|
62
|
-
stream_state: Optional[AirbyteStateBlob] = None
|
63
|
-
|
64
|
-
|
65
|
-
@dataclass
|
66
|
-
class AirbyteGlobalState:
|
67
|
-
stream_states: List[AirbyteStreamState]
|
68
|
-
shared_state: Optional[AirbyteStateBlob] = None
|
69
|
-
|
70
|
-
|
71
|
-
@dataclass
|
72
|
-
class AirbyteStateMessage:
|
73
|
-
type: Optional[AirbyteStateType] = None # type: ignore [name-defined]
|
74
|
-
stream: Optional[AirbyteStreamState] = None
|
75
|
-
global_: Annotated[AirbyteGlobalState | None, Alias("global")] = (
|
76
|
-
None # "global" is a reserved keyword in python ⇒ Alias is used for (de-)serialization
|
77
|
-
)
|
78
|
-
data: Optional[Dict[str, Any]] = None
|
79
|
-
sourceStats: Optional[AirbyteStateStats] = None # type: ignore [name-defined]
|
80
|
-
destinationStats: Optional[AirbyteStateStats] = None # type: ignore [name-defined]
|
81
|
-
|
82
|
-
|
83
|
-
@dataclass
|
84
|
-
class AirbyteMessage:
|
85
|
-
type: Type # type: ignore [name-defined]
|
86
|
-
log: Optional[AirbyteLogMessage] = None # type: ignore [name-defined]
|
87
|
-
spec: Optional[ConnectorSpecification] = None # type: ignore [name-defined]
|
88
|
-
connectionStatus: Optional[AirbyteConnectionStatus] = None # type: ignore [name-defined]
|
89
|
-
catalog: Optional[AirbyteCatalog] = None # type: ignore [name-defined]
|
90
|
-
record: Optional[AirbyteRecordMessage] = None # type: ignore [name-defined]
|
91
|
-
state: Optional[AirbyteStateMessage] = None
|
92
|
-
trace: Optional[AirbyteTraceMessage] = None # type: ignore [name-defined]
|
93
|
-
control: Optional[AirbyteControlMessage] = None # type: ignore [name-defined]
|
@@ -1,6 +1,9 @@
|
|
1
1
|
# Copyright (c) 2024 Airbyte, Inc., all rights reserved.
|
2
2
|
import sys
|
3
|
-
from typing import Any, Dict
|
3
|
+
from typing import Any, Dict, Type, TypeVar
|
4
|
+
|
5
|
+
import orjson
|
6
|
+
from pydantic import ValidationError
|
4
7
|
|
5
8
|
from .airbyte_protocol import ( # type: ignore[attr-defined] # all classes are imported to airbyte_protocol via *
|
6
9
|
AirbyteCatalog,
|
@@ -17,39 +20,98 @@ from .airbyte_protocol import ( # type: ignore[attr-defined] # all classes are
|
|
17
20
|
USE_RUST_BACKEND = sys.platform != "emscripten"
|
18
21
|
"""When run in WASM, use the pure Python backend for serpyco."""
|
19
22
|
|
20
|
-
if USE_RUST_BACKEND:
|
21
|
-
from serpyco_rs import CustomType, Serializer
|
22
|
-
else:
|
23
|
-
from serpyco import CustomType, Serializer
|
24
23
|
|
24
|
+
T = TypeVar("T")
|
25
|
+
|
26
|
+
class CustomSerializer:
|
27
|
+
"""Custom serializer that mimics serpyco-rs Serializer API"""
|
28
|
+
|
29
|
+
def __init__(
|
30
|
+
self,
|
31
|
+
model_class: Type[T],
|
32
|
+
omit_none: bool = False,
|
33
|
+
custom_type_resolver: Callable | None = None,
|
34
|
+
):
|
35
|
+
self.model_class = model_class
|
36
|
+
self.omit_none = omit_none
|
37
|
+
self.custom_type_resolver = custom_type_resolver
|
38
|
+
|
39
|
+
def dump(self, obj: T) -> Dict[str, Any]:
|
40
|
+
"""Convert dataclass to dictionary, omitting None values if configured"""
|
41
|
+
if hasattr(obj, "__dict__"):
|
42
|
+
result = {}
|
43
|
+
for key, value in obj.__dict__.items():
|
44
|
+
if self.omit_none and value is None:
|
45
|
+
continue
|
46
|
+
# Handle custom types like AirbyteStateBlob
|
47
|
+
if self.custom_type_resolver and hasattr(value, "__class__"):
|
48
|
+
custom_handler = self.custom_type_resolver(value.__class__)
|
49
|
+
if custom_handler:
|
50
|
+
value = custom_handler.serialize(value)
|
51
|
+
# Recursively handle nested objects
|
52
|
+
if hasattr(value, "__dict__"):
|
53
|
+
value = self._serialize_nested(value)
|
54
|
+
elif isinstance(value, list):
|
55
|
+
value = [
|
56
|
+
self._serialize_nested(item) if hasattr(item, "__dict__") else item
|
57
|
+
for item in value
|
58
|
+
]
|
59
|
+
result[key] = value
|
60
|
+
return result
|
61
|
+
return obj.__dict__ if hasattr(obj, "__dict__") else {}
|
25
62
|
|
26
|
-
|
27
|
-
|
28
|
-
#
|
29
|
-
return
|
63
|
+
def load(self, data: Dict[str, Any]) -> T:
|
64
|
+
"""Convert dictionary to dataclass instance"""
|
65
|
+
# Handle custom types
|
66
|
+
return self.model_class(**data)
|
67
|
+
|
68
|
+
def _serialize_nested(self, obj: Any) -> Any:
|
69
|
+
"""Helper to serialize nested objects"""
|
70
|
+
if hasattr(obj, "__dict__"):
|
71
|
+
result = {}
|
72
|
+
for key, value in obj.__dict__.items():
|
73
|
+
if self.omit_none and value is None:
|
74
|
+
continue
|
75
|
+
result[key] = value
|
76
|
+
return result
|
77
|
+
return obj
|
78
|
+
|
79
|
+
|
80
|
+
if USE_RUST_BACKEND:
|
81
|
+
from serpyco_rs import CustomType, Serializer # type: ignore[import]
|
30
82
|
|
31
|
-
|
32
|
-
return AirbyteStateBlob(value)
|
83
|
+
SERIALIZER = Serializer if USE_RUST_BACKEND else CustomSerializer
|
33
84
|
|
34
|
-
|
35
|
-
|
85
|
+
# Making this a no-op for now:
|
86
|
+
custom_type_resolver = None
|
36
87
|
|
88
|
+
# No idea why this is here. Commenting out for now.
|
89
|
+
# def custom_type_resolver(t: type) -> AirbyteStateBlobType | None:
|
90
|
+
# return AirbyteStateBlobType() if t is AirbyteStateBlob else None
|
91
|
+
#
|
92
|
+
# class AirbyteStateBlobType(CustomType[AirbyteStateBlob, Dict[str, Any]]):
|
93
|
+
# def serialize(self, value: AirbyteStateBlob) -> Dict[str, Any]:
|
94
|
+
# # cant use orjson.dumps() directly because private attributes are excluded, e.g. "__ab_full_refresh_sync_complete"
|
95
|
+
# return {k: v for k, v in value.__dict__.items()}
|
37
96
|
|
38
|
-
def
|
39
|
-
|
97
|
+
# def deserialize(self, value: Dict[str, Any]) -> AirbyteStateBlob:
|
98
|
+
# return AirbyteStateBlob(value)
|
40
99
|
|
100
|
+
# def get_json_schema(self) -> Dict[str, Any]:
|
101
|
+
# return {"type": "object"}
|
41
102
|
|
42
|
-
|
43
|
-
|
44
|
-
|
103
|
+
# Create serializer instances maintaining the same API
|
104
|
+
AirbyteCatalogSerializer = SERIALIZER(AirbyteCatalog, omit_none=True)
|
105
|
+
AirbyteStreamSerializer = SERIALIZER(AirbyteStream, omit_none=True)
|
106
|
+
AirbyteStreamStateSerializer = SERIALIZER(
|
45
107
|
AirbyteStreamState, omit_none=True, custom_type_resolver=custom_type_resolver
|
46
108
|
)
|
47
|
-
AirbyteStateMessageSerializer =
|
109
|
+
AirbyteStateMessageSerializer = SERIALIZER(
|
48
110
|
AirbyteStateMessage, omit_none=True, custom_type_resolver=custom_type_resolver
|
49
111
|
)
|
50
|
-
AirbyteMessageSerializer =
|
112
|
+
AirbyteMessageSerializer = SERIALIZER(
|
51
113
|
AirbyteMessage, omit_none=True, custom_type_resolver=custom_type_resolver
|
52
114
|
)
|
53
|
-
ConfiguredAirbyteCatalogSerializer =
|
54
|
-
ConfiguredAirbyteStreamSerializer =
|
55
|
-
ConnectorSpecificationSerializer =
|
115
|
+
ConfiguredAirbyteCatalogSerializer = SERIALIZER(ConfiguredAirbyteCatalog, omit_none=True)
|
116
|
+
ConfiguredAirbyteStreamSerializer = SERIALIZER(ConfiguredAirbyteStream, omit_none=True)
|
117
|
+
ConnectorSpecificationSerializer = SERIALIZER(ConnectorSpecification, omit_none=True)
|
@@ -30,11 +30,6 @@ from typing import Any, List, Literal, Optional, Union, final, overload
|
|
30
30
|
import orjson
|
31
31
|
from pydantic import ValidationError as V2ValidationError
|
32
32
|
|
33
|
-
if sys.platform == 'emscripten':
|
34
|
-
from serpyco import SchemaValidationError
|
35
|
-
else:
|
36
|
-
from serpyco_rs import SchemaValidationError
|
37
|
-
|
38
33
|
from airbyte_cdk.entrypoint import AirbyteEntrypoint
|
39
34
|
from airbyte_cdk.exception_handler import assemble_uncaught_exception
|
40
35
|
from airbyte_cdk.logger import AirbyteLogFormatter
|
@@ -55,6 +50,13 @@ from airbyte_cdk.models import (
|
|
55
50
|
from airbyte_cdk.sources import Source
|
56
51
|
from airbyte_cdk.test.models.scenario import ExpectedOutcome
|
57
52
|
|
53
|
+
JsonValidationErrors: tuple[type[Exception], ...] = (orjson.JSONDecodeError,)
|
54
|
+
# Conditionally import and create a union type for exception handling
|
55
|
+
if sys.platform != "emscripten":
|
56
|
+
from serpyco_rs import SchemaValidationError
|
57
|
+
|
58
|
+
JsonValidationErrors = (orjson.JSONDecodeError, SchemaValidationError)
|
59
|
+
|
58
60
|
|
59
61
|
class AirbyteEntrypointException(Exception):
|
60
62
|
"""Exception raised for errors in the AirbyteEntrypoint execution.
|
@@ -123,7 +125,7 @@ class EntrypointOutput:
|
|
123
125
|
def _parse_message(message: str) -> AirbyteMessage:
|
124
126
|
try:
|
125
127
|
return AirbyteMessageSerializer.load(orjson.loads(message))
|
126
|
-
except
|
128
|
+
except JsonValidationErrors:
|
127
129
|
# The platform assumes that logs that are not of AirbyteMessage format are log messages
|
128
130
|
return AirbyteMessage(
|
129
131
|
type=Type.LOG, log=AirbyteLogMessage(level=Level.INFO, message=message)
|
@@ -49,8 +49,8 @@ airbyte_cdk/manifest_migrations/migrations/http_requester_url_base_to_url.py,sha
|
|
49
49
|
airbyte_cdk/manifest_migrations/migrations/registry.yaml,sha256=F-hdapvl_vZnsI7CQsV00Rb7g7j4Nt2zaM83-Tbwgbg,956
|
50
50
|
airbyte_cdk/manifest_migrations/migrations_registry.py,sha256=zly2fwaOxDukqC7eowzrDlvhA2v71FjW74kDzvRXhSY,2619
|
51
51
|
airbyte_cdk/models/__init__.py,sha256=Et9wJWs5VOWynGbb-3aJRhsdAHAiLkNNLxdwqJAuqkw,2114
|
52
|
-
airbyte_cdk/models/airbyte_protocol.py,sha256=
|
53
|
-
airbyte_cdk/models/airbyte_protocol_serializers.py,sha256=
|
52
|
+
airbyte_cdk/models/airbyte_protocol.py,sha256=R1G1lvnBDRCZDa9_9Mgy5OEeyMXbvGWsDOnwQkImRKA,266
|
53
|
+
airbyte_cdk/models/airbyte_protocol_serializers.py,sha256=4lJUZrnoLypM3BFagf4R64XyhRbsMfUffZ_1nHCDNKQ,4503
|
54
54
|
airbyte_cdk/models/connector_metadata.py,sha256=BD6CO8c3mHavxRJAcwP29sHtNNVLVSNFNQLgHOVxrwA,3229
|
55
55
|
airbyte_cdk/models/well_known_types.py,sha256=EquepbisGPuCSrs_D7YVVnMR9-ShhUr21wnFz3COiJs,156
|
56
56
|
airbyte_cdk/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -380,7 +380,7 @@ airbyte_cdk/sql/shared/sql_processor.py,sha256=jR-hdLZsPf2sNBa_wvWKLvys8ZJ-SQCIi
|
|
380
380
|
airbyte_cdk/sql/types.py,sha256=XEIhRAo_ASd0kVLBkdLf5bHiRhNple-IJrC9TibcDdY,5880
|
381
381
|
airbyte_cdk/test/__init__.py,sha256=f_XdkOg4_63QT2k3BbKY34209lppwgw-svzfZstQEq4,199
|
382
382
|
airbyte_cdk/test/catalog_builder.py,sha256=-y05Cz1x0Dlk6oE9LSKhCozssV2gYBNtMdV5YYOPOtk,3015
|
383
|
-
airbyte_cdk/test/entrypoint_wrapper.py,sha256=
|
383
|
+
airbyte_cdk/test/entrypoint_wrapper.py,sha256=Ha1yhuKRpjlC_hRcHB_3y5dtnhygkl-VIX4_WtpNKnU,18235
|
384
384
|
airbyte_cdk/test/mock_http/__init__.py,sha256=jE5kC6CQ0OXkTqKhciDnNVZHesBFVIA2YvkdFGwva7k,322
|
385
385
|
airbyte_cdk/test/mock_http/matcher.py,sha256=4Qj8UnJKZIs-eodshryce3SN1Ayc8GZpBETmP6hTEyc,1446
|
386
386
|
airbyte_cdk/test/mock_http/mocker.py,sha256=XgsjMtVoeMpRELPyALgrkHFauH9H5irxrz1Kcxh2yFY,8013
|
@@ -424,9 +424,9 @@ airbyte_cdk/utils/slice_hasher.py,sha256=EDxgROHDbfG-QKQb59m7h_7crN1tRiawdf5uU7G
|
|
424
424
|
airbyte_cdk/utils/spec_schema_transformations.py,sha256=-5HTuNsnDBAhj-oLeQXwpTGA0HdcjFOf2zTEMUTTg_Y,816
|
425
425
|
airbyte_cdk/utils/stream_status_utils.py,sha256=ZmBoiy5HVbUEHAMrUONxZvxnvfV9CesmQJLDTAIWnWw,1171
|
426
426
|
airbyte_cdk/utils/traced_exception.py,sha256=C8uIBuCL_E4WnBAOPSxBicD06JAldoN9fGsQDp463OY,6292
|
427
|
-
airbyte_cdk-6.60.0.
|
428
|
-
airbyte_cdk-6.60.0.
|
429
|
-
airbyte_cdk-6.60.0.
|
430
|
-
airbyte_cdk-6.60.0.
|
431
|
-
airbyte_cdk-6.60.0.
|
432
|
-
airbyte_cdk-6.60.0.
|
427
|
+
airbyte_cdk-6.60.0.post16.dev16484674380.dist-info/LICENSE.txt,sha256=Wfe61S4BaGPj404v8lrAbvhjYR68SHlkzeYrg3_bbuM,1051
|
428
|
+
airbyte_cdk-6.60.0.post16.dev16484674380.dist-info/LICENSE_SHORT,sha256=aqF6D1NcESmpn-cqsxBtszTEnHKnlsp8L4x9wAh3Nxg,55
|
429
|
+
airbyte_cdk-6.60.0.post16.dev16484674380.dist-info/METADATA,sha256=GDM0HugwhrNDrv8RkxuytvPw9-hRyp2tROFfiSJEvog,6512
|
430
|
+
airbyte_cdk-6.60.0.post16.dev16484674380.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
|
431
|
+
airbyte_cdk-6.60.0.post16.dev16484674380.dist-info/entry_points.txt,sha256=AKWbEkHfpzzk9nF9tqBUaw1MbvTM4mGtEzmZQm0ZWvM,139
|
432
|
+
airbyte_cdk-6.60.0.post16.dev16484674380.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|