meerschaum.connectors.Connector

Define the parent Connector class.

  1#! /usr/bin/env python
  2# -*- coding: utf-8 -*-
  3# vim:fenc=utf-8
  4
  5"""
  6Define the parent `Connector` class.
  7"""
  8
  9from __future__ import annotations
 10import abc
 11import copy
 12from meerschaum.utils.typing import Iterable, Optional, Any, Union, List, Dict
 13
 14class InvalidAttributesError(Exception):
 15    """
 16    Raised when the incorrect attributes are set in the Connector.
 17    """
 18
 19class Connector(metaclass=abc.ABCMeta):
 20    """
 21    The base connector class to hold connection attributes.
 22    """
 23    def __init__(
 24            self,
 25            type: Optional[str] = None,
 26            label: Optional[str] = None,
 27            **kw: Any
 28        ):
 29        """
 30        Set the given keyword arguments as attributes.
 31
 32        Parameters
 33        ----------
 34        type: str
 35            The `type` of the connector (e.g. `sql`, `api`, `plugin`).
 36
 37        label: str
 38            The `label` for the connector.
 39
 40
 41        Examples
 42        --------
 43        Run `mrsm edit config` and to edit connectors in the YAML file:
 44
 45        ```yaml
 46        meerschaum:
 47            connections:
 48                {type}:
 49                    {label}:
 50                        ### attributes go here
 51        ```
 52
 53        """
 54        self._original_dict = copy.deepcopy(self.__dict__)
 55        self._set_attributes(type=type, label=label, **kw)
 56        self.verify_attributes(getattr(self, 'REQUIRED_ATTRIBUTES', None))
 57
 58    def _reset_attributes(self):
 59        self.__dict__ = self._original_dict
 60
 61    def _set_attributes(
 62            self,
 63            *args,
 64            inherit_default: bool = True,
 65            **kw: Any
 66        ):
 67        from meerschaum.config.static import STATIC_CONFIG
 68        from meerschaum.utils.warnings import error
 69
 70        self._attributes = {}
 71
 72        default_label = STATIC_CONFIG['connectors']['default_label']
 73
 74        ### NOTE: Support the legacy method of explicitly passing the type.
 75        label = kw.get('label', None)
 76        if label is None:
 77            if len(args) == 2:
 78                label = args[1]
 79            elif len(args) == 0:
 80                label = None
 81            else:
 82                label = args[0]
 83
 84        if label == 'default':
 85            error(
 86                f"Label cannot be 'default'. Did you mean '{default_label}'?",
 87                InvalidAttributesError,
 88            )
 89        self.__dict__['label'] = label
 90
 91        from meerschaum.config import get_config
 92        conn_configs = copy.deepcopy(get_config('meerschaum', 'connectors'))
 93        connector_config = copy.deepcopy(get_config('system', 'connectors'))
 94
 95        ### inherit attributes from 'default' if exists
 96        if inherit_default:
 97            inherit_from = 'default'
 98            if self.type in conn_configs and inherit_from in conn_configs[self.type]:
 99                _inherit_dict = copy.deepcopy(conn_configs[self.type][inherit_from])
100                self._attributes.update(_inherit_dict)
101
102        ### load user config into self._attributes
103        if self.type in conn_configs and self.label in conn_configs[self.type]:
104            self._attributes.update(conn_configs[self.type][self.label])
105
106        ### load system config into self._sys_config
107        ### (deep copy so future Connectors don't inherit changes)
108        if self.type in connector_config:
109            self._sys_config = copy.deepcopy(connector_config[self.type])
110
111        ### add additional arguments or override configuration
112        self._attributes.update(kw)
113
114        ### finally, update __dict__ with _attributes.
115        self.__dict__.update(self._attributes)
116
117
118    def verify_attributes(
119            self,
120            required_attributes: Optional[List[str]] = None,
121            debug: bool = False
122        ) -> None:
123        """
124        Ensure that the required attributes have been met.
125        
126        The Connector base class checks the minimum requirements.
127        Child classes may enforce additional requirements.
128
129        Parameters
130        ----------
131        required_attributes: Optional[List[str]], default None
132            Attributes to be verified. If `None`, default to `['label']`.
133
134        debug: bool, default False
135            Verbosity toggle.
136
137        Returns
138        -------
139        Don't return anything.
140
141        Raises
142        ------
143        An error if any of the required attributes are missing.
144        """
145        from meerschaum.utils.warnings import error, warn
146        from meerschaum.utils.debug import dprint
147        from meerschaum.utils.misc import items_str
148        if required_attributes is None:
149            required_attributes = ['label']
150        missing_attributes = set()
151        for a in required_attributes:
152            if a not in self.__dict__:
153                missing_attributes.add(a)
154        if len(missing_attributes) > 0:
155            error(
156                (
157                    f"Missing {items_str(list(missing_attributes))} "
158                    + f"for connector '{self.type}:{self.label}'."
159                ),
160                InvalidAttributesError,
161                silent = True,
162                stack = False
163            )
164
165
166    def __str__(self):
167        """
168        When cast to a string, return type:label.
169        """
170        return f"{self.type}:{self.label}"
171
172    def __repr__(self):
173        """
174        Represent the connector as type:label.
175        """
176        return str(self)
177
178    @property
179    def meta(self) -> Dict[str, Any]:
180        """
181        Return the keys needed to reconstruct this Connector.
182        """
183        _meta = {
184            key: value
185            for key, value in self.__dict__.items()
186            if not str(key).startswith('_')
187        }
188        _meta.update({
189            'type': self.type,
190            'label': self.label,
191        })
192        return _meta
193
194
195    @property
196    def type(self) -> str:
197        """
198        Return the type for this connector.
199        """
200        _type = self.__dict__.get('type', None)
201        if _type is None:
202            import re
203            _type = re.sub(r'connector$', '', self.__class__.__name__.lower())
204            self.__dict__['type'] = _type
205        return _type
206
207
208    @property
209    def label(self) -> str:
210        """
211        Return the label for this connector.
212        """
213        _label = self.__dict__.get('label', None)
214        if _label is None:
215            from meerschaum.config.static import STATIC_CONFIG
216            _label = STATIC_CONFIG['connectors']['default_label']
217            self.__dict__['label'] = _label
218        return _label
class InvalidAttributesError(builtins.Exception):
15class InvalidAttributesError(Exception):
16    """
17    Raised when the incorrect attributes are set in the Connector.
18    """

Raised when the incorrect attributes are set in the Connector.

Inherited Members
builtins.Exception
Exception
builtins.BaseException
with_traceback
args
class Connector:
 20class Connector(metaclass=abc.ABCMeta):
 21    """
 22    The base connector class to hold connection attributes.
 23    """
 24    def __init__(
 25            self,
 26            type: Optional[str] = None,
 27            label: Optional[str] = None,
 28            **kw: Any
 29        ):
 30        """
 31        Set the given keyword arguments as attributes.
 32
 33        Parameters
 34        ----------
 35        type: str
 36            The `type` of the connector (e.g. `sql`, `api`, `plugin`).
 37
 38        label: str
 39            The `label` for the connector.
 40
 41
 42        Examples
 43        --------
 44        Run `mrsm edit config` and to edit connectors in the YAML file:
 45
 46        ```yaml
 47        meerschaum:
 48            connections:
 49                {type}:
 50                    {label}:
 51                        ### attributes go here
 52        ```
 53
 54        """
 55        self._original_dict = copy.deepcopy(self.__dict__)
 56        self._set_attributes(type=type, label=label, **kw)
 57        self.verify_attributes(getattr(self, 'REQUIRED_ATTRIBUTES', None))
 58
 59    def _reset_attributes(self):
 60        self.__dict__ = self._original_dict
 61
 62    def _set_attributes(
 63            self,
 64            *args,
 65            inherit_default: bool = True,
 66            **kw: Any
 67        ):
 68        from meerschaum.config.static import STATIC_CONFIG
 69        from meerschaum.utils.warnings import error
 70
 71        self._attributes = {}
 72
 73        default_label = STATIC_CONFIG['connectors']['default_label']
 74
 75        ### NOTE: Support the legacy method of explicitly passing the type.
 76        label = kw.get('label', None)
 77        if label is None:
 78            if len(args) == 2:
 79                label = args[1]
 80            elif len(args) == 0:
 81                label = None
 82            else:
 83                label = args[0]
 84
 85        if label == 'default':
 86            error(
 87                f"Label cannot be 'default'. Did you mean '{default_label}'?",
 88                InvalidAttributesError,
 89            )
 90        self.__dict__['label'] = label
 91
 92        from meerschaum.config import get_config
 93        conn_configs = copy.deepcopy(get_config('meerschaum', 'connectors'))
 94        connector_config = copy.deepcopy(get_config('system', 'connectors'))
 95
 96        ### inherit attributes from 'default' if exists
 97        if inherit_default:
 98            inherit_from = 'default'
 99            if self.type in conn_configs and inherit_from in conn_configs[self.type]:
100                _inherit_dict = copy.deepcopy(conn_configs[self.type][inherit_from])
101                self._attributes.update(_inherit_dict)
102
103        ### load user config into self._attributes
104        if self.type in conn_configs and self.label in conn_configs[self.type]:
105            self._attributes.update(conn_configs[self.type][self.label])
106
107        ### load system config into self._sys_config
108        ### (deep copy so future Connectors don't inherit changes)
109        if self.type in connector_config:
110            self._sys_config = copy.deepcopy(connector_config[self.type])
111
112        ### add additional arguments or override configuration
113        self._attributes.update(kw)
114
115        ### finally, update __dict__ with _attributes.
116        self.__dict__.update(self._attributes)
117
118
119    def verify_attributes(
120            self,
121            required_attributes: Optional[List[str]] = None,
122            debug: bool = False
123        ) -> None:
124        """
125        Ensure that the required attributes have been met.
126        
127        The Connector base class checks the minimum requirements.
128        Child classes may enforce additional requirements.
129
130        Parameters
131        ----------
132        required_attributes: Optional[List[str]], default None
133            Attributes to be verified. If `None`, default to `['label']`.
134
135        debug: bool, default False
136            Verbosity toggle.
137
138        Returns
139        -------
140        Don't return anything.
141
142        Raises
143        ------
144        An error if any of the required attributes are missing.
145        """
146        from meerschaum.utils.warnings import error, warn
147        from meerschaum.utils.debug import dprint
148        from meerschaum.utils.misc import items_str
149        if required_attributes is None:
150            required_attributes = ['label']
151        missing_attributes = set()
152        for a in required_attributes:
153            if a not in self.__dict__:
154                missing_attributes.add(a)
155        if len(missing_attributes) > 0:
156            error(
157                (
158                    f"Missing {items_str(list(missing_attributes))} "
159                    + f"for connector '{self.type}:{self.label}'."
160                ),
161                InvalidAttributesError,
162                silent = True,
163                stack = False
164            )
165
166
167    def __str__(self):
168        """
169        When cast to a string, return type:label.
170        """
171        return f"{self.type}:{self.label}"
172
173    def __repr__(self):
174        """
175        Represent the connector as type:label.
176        """
177        return str(self)
178
179    @property
180    def meta(self) -> Dict[str, Any]:
181        """
182        Return the keys needed to reconstruct this Connector.
183        """
184        _meta = {
185            key: value
186            for key, value in self.__dict__.items()
187            if not str(key).startswith('_')
188        }
189        _meta.update({
190            'type': self.type,
191            'label': self.label,
192        })
193        return _meta
194
195
196    @property
197    def type(self) -> str:
198        """
199        Return the type for this connector.
200        """
201        _type = self.__dict__.get('type', None)
202        if _type is None:
203            import re
204            _type = re.sub(r'connector$', '', self.__class__.__name__.lower())
205            self.__dict__['type'] = _type
206        return _type
207
208
209    @property
210    def label(self) -> str:
211        """
212        Return the label for this connector.
213        """
214        _label = self.__dict__.get('label', None)
215        if _label is None:
216            from meerschaum.config.static import STATIC_CONFIG
217            _label = STATIC_CONFIG['connectors']['default_label']
218            self.__dict__['label'] = _label
219        return _label

The base connector class to hold connection attributes.

Connector(type: Optional[str] = None, label: Optional[str] = None, **kw: Any)
24    def __init__(
25            self,
26            type: Optional[str] = None,
27            label: Optional[str] = None,
28            **kw: Any
29        ):
30        """
31        Set the given keyword arguments as attributes.
32
33        Parameters
34        ----------
35        type: str
36            The `type` of the connector (e.g. `sql`, `api`, `plugin`).
37
38        label: str
39            The `label` for the connector.
40
41
42        Examples
43        --------
44        Run `mrsm edit config` and to edit connectors in the YAML file:
45
46        ```yaml
47        meerschaum:
48            connections:
49                {type}:
50                    {label}:
51                        ### attributes go here
52        ```
53
54        """
55        self._original_dict = copy.deepcopy(self.__dict__)
56        self._set_attributes(type=type, label=label, **kw)
57        self.verify_attributes(getattr(self, 'REQUIRED_ATTRIBUTES', None))

Set the given keyword arguments as attributes.

Parameters
  • type (str): The type of the connector (e.g. sql, api, plugin).
  • label (str): The label for the connector.
Examples

Run mrsm edit config and to edit connectors in the YAML file:

meerschaum:
    connections:
        {type}:
            {label}:
                ### attributes go here
def verify_attributes( self, required_attributes: Optional[List[str]] = None, debug: bool = False) -> None:
119    def verify_attributes(
120            self,
121            required_attributes: Optional[List[str]] = None,
122            debug: bool = False
123        ) -> None:
124        """
125        Ensure that the required attributes have been met.
126        
127        The Connector base class checks the minimum requirements.
128        Child classes may enforce additional requirements.
129
130        Parameters
131        ----------
132        required_attributes: Optional[List[str]], default None
133            Attributes to be verified. If `None`, default to `['label']`.
134
135        debug: bool, default False
136            Verbosity toggle.
137
138        Returns
139        -------
140        Don't return anything.
141
142        Raises
143        ------
144        An error if any of the required attributes are missing.
145        """
146        from meerschaum.utils.warnings import error, warn
147        from meerschaum.utils.debug import dprint
148        from meerschaum.utils.misc import items_str
149        if required_attributes is None:
150            required_attributes = ['label']
151        missing_attributes = set()
152        for a in required_attributes:
153            if a not in self.__dict__:
154                missing_attributes.add(a)
155        if len(missing_attributes) > 0:
156            error(
157                (
158                    f"Missing {items_str(list(missing_attributes))} "
159                    + f"for connector '{self.type}:{self.label}'."
160                ),
161                InvalidAttributesError,
162                silent = True,
163                stack = False
164            )

Ensure that the required attributes have been met.

The Connector base class checks the minimum requirements. Child classes may enforce additional requirements.

Parameters
  • required_attributes (Optional[List[str]], default None): Attributes to be verified. If None, default to ['label'].
  • debug (bool, default False): Verbosity toggle.
Returns
  • Don't return anything.
Raises
  • An error if any of the required attributes are missing.
meta: Dict[str, Any]
179    @property
180    def meta(self) -> Dict[str, Any]:
181        """
182        Return the keys needed to reconstruct this Connector.
183        """
184        _meta = {
185            key: value
186            for key, value in self.__dict__.items()
187            if not str(key).startswith('_')
188        }
189        _meta.update({
190            'type': self.type,
191            'label': self.label,
192        })
193        return _meta

Return the keys needed to reconstruct this Connector.

type: str
196    @property
197    def type(self) -> str:
198        """
199        Return the type for this connector.
200        """
201        _type = self.__dict__.get('type', None)
202        if _type is None:
203            import re
204            _type = re.sub(r'connector$', '', self.__class__.__name__.lower())
205            self.__dict__['type'] = _type
206        return _type

Return the type for this connector.

label: str
209    @property
210    def label(self) -> str:
211        """
212        Return the label for this connector.
213        """
214        _label = self.__dict__.get('label', None)
215        if _label is None:
216            from meerschaum.config.static import STATIC_CONFIG
217            _label = STATIC_CONFIG['connectors']['default_label']
218            self.__dict__['label'] = _label
219        return _label

Return the label for this connector.