airless-google-cloud-core 0.0.1.dev1__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 (19) hide show
  1. airless_google_cloud_core-0.0.1.dev1/PKG-INFO +16 -0
  2. airless_google_cloud_core-0.0.1.dev1/README.md +5 -0
  3. airless_google_cloud_core-0.0.1.dev1/airless/google/cloud/__init__.py +0 -0
  4. airless_google_cloud_core-0.0.1.dev1/airless/google/cloud/core/__init__.py +0 -0
  5. airless_google_cloud_core-0.0.1.dev1/airless/google/cloud/core/operator/__init__.py +0 -0
  6. airless_google_cloud_core-0.0.1.dev1/airless/google/cloud/core/operator/base.py +18 -0
  7. airless_google_cloud_core-0.0.1.dev1/airless/google/cloud/core/operator/delay.py +20 -0
  8. airless_google_cloud_core-0.0.1.dev1/airless/google/cloud/core/operator/error.py +95 -0
  9. airless_google_cloud_core-0.0.1.dev1/airless/google/cloud/core/operator/redirect.py +22 -0
  10. airless_google_cloud_core-0.0.1.dev1/airless/google/cloud/pubsub/__init__.py +0 -0
  11. airless_google_cloud_core-0.0.1.dev1/airless/google/cloud/pubsub/hook/__init__.py +0 -0
  12. airless_google_cloud_core-0.0.1.dev1/airless/google/cloud/pubsub/hook/pubsub.py +30 -0
  13. airless_google_cloud_core-0.0.1.dev1/airless_google_cloud_core.egg-info/PKG-INFO +16 -0
  14. airless_google_cloud_core-0.0.1.dev1/airless_google_cloud_core.egg-info/SOURCES.txt +18 -0
  15. airless_google_cloud_core-0.0.1.dev1/airless_google_cloud_core.egg-info/dependency_links.txt +1 -0
  16. airless_google_cloud_core-0.0.1.dev1/airless_google_cloud_core.egg-info/requires.txt +2 -0
  17. airless_google_cloud_core-0.0.1.dev1/airless_google_cloud_core.egg-info/top_level.txt +1 -0
  18. airless_google_cloud_core-0.0.1.dev1/pyproject.toml +19 -0
  19. airless_google_cloud_core-0.0.1.dev1/setup.cfg +32 -0
@@ -0,0 +1,16 @@
1
+ Metadata-Version: 2.1
2
+ Name: airless-google-cloud-core
3
+ Version: 0.0.1.dev1
4
+ Summary: Airless package with the main components to use airless in google cloud
5
+ Project-URL: Homepage, https://github.com/astercapital/airless
6
+ Project-URL: Bug Tracker, https://github.com/astercapital/airless/issues
7
+ Requires-Python: >=3.9
8
+ Description-Content-Type: text/markdown
9
+ Requires-Dist: google-cloud-pubsub==2.13.11
10
+ Requires-Dist: airless-core>=0.1.0.dev1
11
+
12
+ # airless-google-cloud-core
13
+
14
+ [![PyPI version](https://badge.fury.io/py/airless-google-cloud-core.svg)](https://badge.fury.io/py/airless-google-cloud-core)
15
+
16
+ airless-google-cloud-core [Airless](https://github.com/astercapital/airless) package with the main components to use airless in google cloud.
@@ -0,0 +1,5 @@
1
+ # airless-google-cloud-core
2
+
3
+ [![PyPI version](https://badge.fury.io/py/airless-google-cloud-core.svg)](https://badge.fury.io/py/airless-google-cloud-core)
4
+
5
+ airless-google-cloud-core [Airless](https://github.com/astercapital/airless) package with the main components to use airless in google cloud.
@@ -0,0 +1,18 @@
1
+
2
+ from airless.core.operator.base import BaseFileOperator, BaseEventOperator
3
+
4
+ from airless.google.cloud.pubsub.hook import GooglePubsubHook
5
+
6
+
7
+ class BaseGoogleFileOperator(BaseFileOperator):
8
+
9
+ def __init__(self):
10
+ super().__init__()
11
+ self.queue_hook = GooglePubsubHook() # Have to redefine this attribute for each vendor
12
+
13
+
14
+ class BaseGoogleEventOperator(BaseEventOperator):
15
+
16
+ def __init__(self):
17
+ super().__init__()
18
+ self.queue_hook = GooglePubsubHook() # Have to redefine this attribute for each vendor
@@ -0,0 +1,20 @@
1
+
2
+ from time import sleep
3
+
4
+ from airless.core.operator.delay import DelayOperator
5
+ from airless.google.cloud.core.base import BaseGoogleEventOperator
6
+
7
+
8
+
9
+ class GoogleDelayOperator(BaseGoogleEventOperator, DelayOperator):
10
+
11
+ """
12
+ Operator that adds a delay to the pipeline. The maximum delay is 500 due
13
+ to Cloud Functions time constraint of 540 of execution time
14
+
15
+ It can receive 1 parameter:
16
+ seconds: number of seconds to wait
17
+ """
18
+
19
+ def __init__(self):
20
+ super().__init__()
@@ -0,0 +1,95 @@
1
+
2
+ import json
3
+ import time
4
+
5
+ from datetime import datetime
6
+
7
+ from airless.core.config import get_config
8
+ from airless.core.dto.base import BaseDto
9
+ from airless.google.cloud.core.base import BaseGoogleEventOperator
10
+
11
+
12
+ class GoogleErrorReprocessOperator(BaseGoogleEventOperator):
13
+
14
+ def __init__(self):
15
+ super().__init__()
16
+
17
+ def execute(self, data, topic):
18
+
19
+ input_type = data['input_type']
20
+ origin = data.get('origin', 'undefined')
21
+ message_id = data.get('event_id')
22
+ original_data = data['data']
23
+ metadata = original_data.get('metadata', {})
24
+
25
+ retry_interval = metadata.get('retry_interval', 5)
26
+ retries = metadata.get('retries', 0)
27
+ max_retries = metadata.get('max_retries', 2)
28
+ max_interval = metadata.get('max_interval', 480) # Cloud function max execution time is 540s (9 min), so set it to wait max 480s (8 min)
29
+
30
+ if (input_type == 'event') and (retries < max_retries):
31
+ time.sleep(min(retry_interval ** retries, max_interval))
32
+ original_data.setdefault('metadata', {})['retries'] = retries + 1
33
+ self.queue_hook.publish(
34
+ project=get_config('GCP_PROJECT'),
35
+ topic=origin,
36
+ data=original_data)
37
+
38
+ else:
39
+ dto = BaseDto(
40
+ event_id=message_id,
41
+ resource=origin,
42
+ to_project=get_config('GCP_PROJECT'),
43
+ to_dataset=get_config('BIGQUERY_DATASET_ERROR'),
44
+ to_table=get_config('BIGQUERY_TABLE_ERROR'),
45
+ to_schema=None,
46
+ to_partition_column='_created_at',
47
+ to_extract_to_cols=False,
48
+ to_keys_format=None,
49
+ data=data)
50
+ self.queue_hook.publish(
51
+ project=get_config('GCP_PROJECT'),
52
+ topic=get_config('PUBSUB_TOPIC_PUBSUB_TO_BQ'),
53
+ data=dto.as_dict())
54
+
55
+ email_send_topic = get_config('PUBSUB_TOPIC_EMAIL_SEND', False)
56
+ if email_send_topic and (origin != email_send_topic):
57
+ self.notify_email(origin, message_id, data)
58
+
59
+ slack_send_topic = get_config('PUBSUB_TOPIC_SLACK_SEND', False)
60
+ if slack_send_topic and (origin != slack_send_topic):
61
+ self.notify_slack(origin, message_id, data)
62
+
63
+ def notify_email(self, origin, message_id, data):
64
+ email_message = {
65
+ 'sender': get_config('EMAIL_SENDER_ERROR'),
66
+ 'recipients': eval(get_config('EMAIL_RECIPIENTS_ERROR')),
67
+ 'subject': f'{origin} | {message_id}',
68
+ 'content': f'Input Type: {data["input_type"]} Origin: {origin}\nMessage ID: {message_id}\n\n {json.dumps(data["data"])}\n\n{data["error"]}'
69
+ }
70
+ self.queue_hook.publish(
71
+ project=get_config('GCP_PROJECT'),
72
+ topic=get_config('PUBSUB_TOPIC_EMAIL_SEND'),
73
+ data=email_message)
74
+
75
+ def notify_slack(self, origin, message_id, data):
76
+ slack_message = {
77
+ 'channels': eval(get_config('SLACK_CHANNELS_ERROR')),
78
+ 'message': f'{origin} | {message_id}\n\n{json.dumps(data["data"])}\n\n{data["error"]}'
79
+ }
80
+ self.queue_hook.publish(
81
+ project=get_config('GCP_PROJECT'),
82
+ topic=get_config('PUBSUB_TOPIC_SLACK_SEND'),
83
+ data=slack_message)
84
+
85
+ def prepare_row(self, row, message_id, origin):
86
+ return {
87
+ '_event_id': message_id or 1234,
88
+ '_resource': origin or 'local',
89
+ '_json': json.dumps(row),
90
+ '_created_at': str(datetime.now())
91
+ }
92
+
93
+ def prepare_rows(self, data, message_id, origin):
94
+ prepared_rows = data if isinstance(data, list) else [data]
95
+ return [self.prepare_row(row, message_id, origin) for row in prepared_rows]
@@ -0,0 +1,22 @@
1
+
2
+ from airless.core.operator.redirect import RedirectOperator
3
+ from airless.google.cloud.core.base import BaseGoogleEventOperator
4
+
5
+
6
+ class GoogleRedirectOperator(BaseGoogleEventOperator, RedirectOperator):
7
+
8
+ """
9
+ Operator that receives one event from a pubsub topic
10
+ and publish multiple messages to another topic.
11
+
12
+ It can receive 4 parameters:
13
+ project: the project where the destination pubsub is hosted
14
+ topic: the pubsub topic it must publish the newly generated messages
15
+ messages: a list of messages to publish the topic
16
+ params: a list of dicts containing a key and a list of values
17
+
18
+ The output messages will be the product of messages and every param values list
19
+ """
20
+
21
+ def __init__(self):
22
+ super().__init__()
@@ -0,0 +1,30 @@
1
+
2
+ import json
3
+
4
+ from google.cloud import pubsub_v1
5
+
6
+ from airless.core.hook.queue import QueueHook
7
+ from airless.core.config import get_config
8
+
9
+
10
+ class GooglePubsubHook(QueueHook):
11
+
12
+ def __init__(self):
13
+ super().__init__()
14
+ self.publisher = pubsub_v1.PublisherClient()
15
+
16
+ def publish(self, project, topic, data):
17
+
18
+ if get_config('ENV') == 'prod':
19
+ topic_path = self.publisher.topic_path(project, topic)
20
+
21
+ message_bytes = json \
22
+ .dumps(data) \
23
+ .encode('utf-8')
24
+
25
+ publish_future = self.publisher.publish(topic_path, data=message_bytes)
26
+ publish_future.result(timeout=10)
27
+ self.logger.info(f'published to {project}.{topic}')
28
+ return 'Message published.'
29
+ else:
30
+ self.logger.debug(f'[DEV] Message published to Project {project}, Topic {topic}: {data}')
@@ -0,0 +1,16 @@
1
+ Metadata-Version: 2.1
2
+ Name: airless-google-cloud-core
3
+ Version: 0.0.1.dev1
4
+ Summary: Airless package with the main components to use airless in google cloud
5
+ Project-URL: Homepage, https://github.com/astercapital/airless
6
+ Project-URL: Bug Tracker, https://github.com/astercapital/airless/issues
7
+ Requires-Python: >=3.9
8
+ Description-Content-Type: text/markdown
9
+ Requires-Dist: google-cloud-pubsub==2.13.11
10
+ Requires-Dist: airless-core>=0.1.0.dev1
11
+
12
+ # airless-google-cloud-core
13
+
14
+ [![PyPI version](https://badge.fury.io/py/airless-google-cloud-core.svg)](https://badge.fury.io/py/airless-google-cloud-core)
15
+
16
+ airless-google-cloud-core [Airless](https://github.com/astercapital/airless) package with the main components to use airless in google cloud.
@@ -0,0 +1,18 @@
1
+ README.md
2
+ pyproject.toml
3
+ setup.cfg
4
+ airless/google/cloud/__init__.py
5
+ airless/google/cloud/core/__init__.py
6
+ airless/google/cloud/core/operator/__init__.py
7
+ airless/google/cloud/core/operator/base.py
8
+ airless/google/cloud/core/operator/delay.py
9
+ airless/google/cloud/core/operator/error.py
10
+ airless/google/cloud/core/operator/redirect.py
11
+ airless/google/cloud/pubsub/__init__.py
12
+ airless/google/cloud/pubsub/hook/__init__.py
13
+ airless/google/cloud/pubsub/hook/pubsub.py
14
+ airless_google_cloud_core.egg-info/PKG-INFO
15
+ airless_google_cloud_core.egg-info/SOURCES.txt
16
+ airless_google_cloud_core.egg-info/dependency_links.txt
17
+ airless_google_cloud_core.egg-info/requires.txt
18
+ airless_google_cloud_core.egg-info/top_level.txt
@@ -0,0 +1,2 @@
1
+ google-cloud-pubsub==2.13.11
2
+ airless-core>=0.1.0.dev1
@@ -0,0 +1,19 @@
1
+ [project]
2
+ name = "airless-google-cloud-core"
3
+ version = "0.0.1.dev1"
4
+ description = "Airless package with the main components to use airless in google cloud"
5
+ readme = "README.md"
6
+ dynamic = ["dependencies", "requires-python"]
7
+
8
+ [build-system]
9
+ requires = ["setuptools", "wheel"]
10
+ build-backend = "setuptools.build_meta"
11
+
12
+ [project.urls]
13
+ "Homepage" = "https://github.com/astercapital/airless"
14
+ "Bug Tracker" = "https://github.com/astercapital/airless/issues"
15
+
16
+ [tool.pytest.ini_options]
17
+ minversion = "6.0"
18
+ addopts = "--capture=sys --cache-clear --disable-warnings --junitxml=pytest.xml --cov-report=xml:cov.xml --cov-report=term-missing:skip-covered --cov=airless"
19
+ testpaths = ["tests"]
@@ -0,0 +1,32 @@
1
+ [metadata]
2
+ name = airless-google-cloud-core
3
+ version = 0.0.0
4
+
5
+ [options]
6
+ python_requires = >=3.9
7
+ packages = find_namespace:
8
+ install_requires =
9
+ google-cloud-pubsub==2.13.11
10
+ airless-core>=0.1.0.dev1
11
+
12
+ [options.packages.find]
13
+ include = airless.google.cloud*
14
+
15
+ [flake8]
16
+ exclude =
17
+ .git,
18
+ __pycache__,
19
+ build,
20
+ dist,
21
+ *.pyc,
22
+ *.egg-info,
23
+ *.egg,
24
+ temp
25
+ ignore = E501
26
+ max-line-length = 120
27
+ max-complexity = 15
28
+
29
+ [egg_info]
30
+ tag_build =
31
+ tag_date = 0
32
+