airbyte_cdk.sources.declarative.models.base_model_with_deprecations

  1# Copyright (c) 2025 Airbyte, Inc., all rights reserved.
  2
  3# THIS IS A STATIC CLASS MODEL USED TO DISPLAY DEPRECATION WARNINGS
  4# WHEN DEPRECATED FIELDS ARE ACCESSED
  5
  6import warnings
  7
  8# ignore the SyntaxWarning in the Airbyte log messages, during the string evaluation
  9warnings.filterwarnings("ignore", category=SyntaxWarning)
 10
 11from typing import Any, List
 12
 13from pydantic.v1 import BaseModel
 14
 15from airbyte_cdk.connector_builder.models import LogMessage as ConnectorBuilderLogMessage
 16
 17# format the warning message
 18warnings.formatwarning = (
 19    lambda message, category, *args, **kwargs: f"{category.__name__}: {message}\n"
 20)
 21
 22
 23FIELDS_TAG = "__fields__"
 24DEPRECATED = "deprecated"
 25DEPRECATION_MESSAGE = "deprecation_message"
 26DEPRECATION_LOGS_TAG = "_deprecation_logs"
 27
 28
 29class BaseModelWithDeprecations(BaseModel):
 30    """
 31    Pydantic BaseModel that warns when deprecated fields are accessed.
 32    The deprecation message is stored in the field's extra attributes.
 33    This class is used to create models that can have deprecated fields
 34    and show warnings when those fields are accessed or initialized.
 35
 36    The `_deprecation_logs` attribute is stored in the model itself.
 37    The collected deprecation warnings are further propagated to the Airbyte log messages,
 38    during the component creation process, in `model_to_component._collect_model_deprecations()`.
 39
 40    The component implementation is not responsible for handling the deprecation warnings,
 41    since the deprecation warnings are already handled in the model itself.
 42    """
 43
 44    class Config:
 45        """
 46        Allow extra fields in the model. In case the model restricts extra fields.
 47        """
 48
 49        extra = "allow"
 50
 51    def __init__(self, **model_fields: Any) -> None:
 52        """
 53        Show warnings for deprecated fields during component initialization.
 54        """
 55        # call the parent constructor first to initialize Pydantic internals
 56        super().__init__(**model_fields)
 57        # set the placeholder for the default deprecation messages
 58        self._default_deprecation_messages: List[str] = []
 59        # set the placeholder for the deprecation logs
 60        self._deprecation_logs: List[ConnectorBuilderLogMessage] = []
 61        # process deprecated fields, if present
 62        self._process_fields(model_fields)
 63        # emit default deprecation messages
 64        self._emit_default_deprecation_messages()
 65        # set the deprecation logs attribute to the model
 66        self._set_deprecation_logs_attr_to_model()
 67
 68    def _is_deprecated_field(self, field_name: str) -> bool:
 69        return (
 70            self.__fields__[field_name].field_info.extra.get(DEPRECATED, False)
 71            if field_name in self.__fields__.keys()
 72            else False
 73        )
 74
 75    def _get_deprecation_message(self, field_name: str) -> str:
 76        return (
 77            self.__fields__[field_name].field_info.extra.get(
 78                DEPRECATION_MESSAGE, "<missing_deprecation_message>"
 79            )
 80            if field_name in self.__fields__.keys()
 81            else "<missing_deprecation_message>"
 82        )
 83
 84    def _process_fields(self, model_fields: Any) -> None:
 85        """
 86        Processes the fields in the provided model data, checking for deprecated fields.
 87
 88        For each field in the input `model_fields`, this method checks if the field exists in the model's defined fields.
 89        If the field is marked as deprecated (using the `DEPRECATED` flag in its metadata), it triggers a deprecation warning
 90        by calling the `_create_warning` method with the field name and an optional deprecation message.
 91
 92        Args:
 93            model_fields (Any): The data containing fields to be processed.
 94
 95        Returns:
 96            None
 97        """
 98
 99        if hasattr(self, FIELDS_TAG):
100            for field_name in model_fields.keys():
101                if self._is_deprecated_field(field_name):
102                    self._create_warning(
103                        field_name,
104                        self._get_deprecation_message(field_name),
105                    )
106
107    def _set_deprecation_logs_attr_to_model(self) -> None:
108        """
109        Sets the deprecation logs attribute on the model instance.
110
111        This method attaches the current instance's deprecation logs to the model by setting
112        an attribute named by `DEPRECATION_LOGS_TAG` to the value of `self._deprecation_logs`.
113        This is typically used to track or log deprecated features or configurations within the model.
114
115        Returns:
116            None
117        """
118        setattr(self, DEPRECATION_LOGS_TAG, self._deprecation_logs)
119
120    def _create_warning(self, field_name: str, message: str) -> None:
121        """
122        Show a warning message for deprecated fields (to stdout).
123        Args:
124            field_name (str): Name of the deprecated field.
125            message (str): Warning message to be displayed.
126        """
127
128        deprecated_message = f"Component type: `{self.__class__.__name__}`. Field '{field_name}' is deprecated. {message}"
129
130        if deprecated_message not in self._default_deprecation_messages:
131            # Avoid duplicates in the default deprecation messages
132            self._default_deprecation_messages.append(deprecated_message)
133
134        # Create an Airbyte deprecation log message
135        deprecation_log_message = ConnectorBuilderLogMessage(
136            level="WARN", message=deprecated_message
137        )
138        # Add the deprecation message to the Airbyte log messages,
139        # this logs are displayed in the Connector Builder.
140        if deprecation_log_message not in self._deprecation_logs:
141            # Avoid duplicates in the deprecation logs
142            self._deprecation_logs.append(deprecation_log_message)
143
144    def _emit_default_deprecation_messages(self) -> None:
145        """
146        Emit default deprecation messages for deprecated fields to STDOUT.
147        """
148        for message in self._default_deprecation_messages:
149            warnings.warn(message, DeprecationWarning)
FIELDS_TAG = '__fields__'
DEPRECATED = 'deprecated'
DEPRECATION_MESSAGE = 'deprecation_message'
DEPRECATION_LOGS_TAG = '_deprecation_logs'
class BaseModelWithDeprecations(pydantic.v1.main.BaseModel):
 30class BaseModelWithDeprecations(BaseModel):
 31    """
 32    Pydantic BaseModel that warns when deprecated fields are accessed.
 33    The deprecation message is stored in the field's extra attributes.
 34    This class is used to create models that can have deprecated fields
 35    and show warnings when those fields are accessed or initialized.
 36
 37    The `_deprecation_logs` attribute is stored in the model itself.
 38    The collected deprecation warnings are further propagated to the Airbyte log messages,
 39    during the component creation process, in `model_to_component._collect_model_deprecations()`.
 40
 41    The component implementation is not responsible for handling the deprecation warnings,
 42    since the deprecation warnings are already handled in the model itself.
 43    """
 44
 45    class Config:
 46        """
 47        Allow extra fields in the model. In case the model restricts extra fields.
 48        """
 49
 50        extra = "allow"
 51
 52    def __init__(self, **model_fields: Any) -> None:
 53        """
 54        Show warnings for deprecated fields during component initialization.
 55        """
 56        # call the parent constructor first to initialize Pydantic internals
 57        super().__init__(**model_fields)
 58        # set the placeholder for the default deprecation messages
 59        self._default_deprecation_messages: List[str] = []
 60        # set the placeholder for the deprecation logs
 61        self._deprecation_logs: List[ConnectorBuilderLogMessage] = []
 62        # process deprecated fields, if present
 63        self._process_fields(model_fields)
 64        # emit default deprecation messages
 65        self._emit_default_deprecation_messages()
 66        # set the deprecation logs attribute to the model
 67        self._set_deprecation_logs_attr_to_model()
 68
 69    def _is_deprecated_field(self, field_name: str) -> bool:
 70        return (
 71            self.__fields__[field_name].field_info.extra.get(DEPRECATED, False)
 72            if field_name in self.__fields__.keys()
 73            else False
 74        )
 75
 76    def _get_deprecation_message(self, field_name: str) -> str:
 77        return (
 78            self.__fields__[field_name].field_info.extra.get(
 79                DEPRECATION_MESSAGE, "<missing_deprecation_message>"
 80            )
 81            if field_name in self.__fields__.keys()
 82            else "<missing_deprecation_message>"
 83        )
 84
 85    def _process_fields(self, model_fields: Any) -> None:
 86        """
 87        Processes the fields in the provided model data, checking for deprecated fields.
 88
 89        For each field in the input `model_fields`, this method checks if the field exists in the model's defined fields.
 90        If the field is marked as deprecated (using the `DEPRECATED` flag in its metadata), it triggers a deprecation warning
 91        by calling the `_create_warning` method with the field name and an optional deprecation message.
 92
 93        Args:
 94            model_fields (Any): The data containing fields to be processed.
 95
 96        Returns:
 97            None
 98        """
 99
100        if hasattr(self, FIELDS_TAG):
101            for field_name in model_fields.keys():
102                if self._is_deprecated_field(field_name):
103                    self._create_warning(
104                        field_name,
105                        self._get_deprecation_message(field_name),
106                    )
107
108    def _set_deprecation_logs_attr_to_model(self) -> None:
109        """
110        Sets the deprecation logs attribute on the model instance.
111
112        This method attaches the current instance's deprecation logs to the model by setting
113        an attribute named by `DEPRECATION_LOGS_TAG` to the value of `self._deprecation_logs`.
114        This is typically used to track or log deprecated features or configurations within the model.
115
116        Returns:
117            None
118        """
119        setattr(self, DEPRECATION_LOGS_TAG, self._deprecation_logs)
120
121    def _create_warning(self, field_name: str, message: str) -> None:
122        """
123        Show a warning message for deprecated fields (to stdout).
124        Args:
125            field_name (str): Name of the deprecated field.
126            message (str): Warning message to be displayed.
127        """
128
129        deprecated_message = f"Component type: `{self.__class__.__name__}`. Field '{field_name}' is deprecated. {message}"
130
131        if deprecated_message not in self._default_deprecation_messages:
132            # Avoid duplicates in the default deprecation messages
133            self._default_deprecation_messages.append(deprecated_message)
134
135        # Create an Airbyte deprecation log message
136        deprecation_log_message = ConnectorBuilderLogMessage(
137            level="WARN", message=deprecated_message
138        )
139        # Add the deprecation message to the Airbyte log messages,
140        # this logs are displayed in the Connector Builder.
141        if deprecation_log_message not in self._deprecation_logs:
142            # Avoid duplicates in the deprecation logs
143            self._deprecation_logs.append(deprecation_log_message)
144
145    def _emit_default_deprecation_messages(self) -> None:
146        """
147        Emit default deprecation messages for deprecated fields to STDOUT.
148        """
149        for message in self._default_deprecation_messages:
150            warnings.warn(message, DeprecationWarning)

Pydantic BaseModel that warns when deprecated fields are accessed. The deprecation message is stored in the field's extra attributes. This class is used to create models that can have deprecated fields and show warnings when those fields are accessed or initialized.

The _deprecation_logs attribute is stored in the model itself. The collected deprecation warnings are further propagated to the Airbyte log messages, during the component creation process, in model_to_component._collect_model_deprecations().

The component implementation is not responsible for handling the deprecation warnings, since the deprecation warnings are already handled in the model itself.

BaseModelWithDeprecations(**model_fields: Any)
52    def __init__(self, **model_fields: Any) -> None:
53        """
54        Show warnings for deprecated fields during component initialization.
55        """
56        # call the parent constructor first to initialize Pydantic internals
57        super().__init__(**model_fields)
58        # set the placeholder for the default deprecation messages
59        self._default_deprecation_messages: List[str] = []
60        # set the placeholder for the deprecation logs
61        self._deprecation_logs: List[ConnectorBuilderLogMessage] = []
62        # process deprecated fields, if present
63        self._process_fields(model_fields)
64        # emit default deprecation messages
65        self._emit_default_deprecation_messages()
66        # set the deprecation logs attribute to the model
67        self._set_deprecation_logs_attr_to_model()

Show warnings for deprecated fields during component initialization.

class BaseModelWithDeprecations.Config:
45    class Config:
46        """
47        Allow extra fields in the model. In case the model restricts extra fields.
48        """
49
50        extra = "allow"

Allow extra fields in the model. In case the model restricts extra fields.

extra = 'allow'