airless-google-cloud-core 0.0.2.dev1__tar.gz → 0.0.3__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 (28) hide show
  1. {airless_google_cloud_core-0.0.2.dev1 → airless_google_cloud_core-0.0.3}/PKG-INFO +3 -4
  2. airless_google_cloud_core-0.0.3/airless/google/cloud/core/operator/__init__.py +12 -0
  3. {airless_google_cloud_core-0.0.2.dev1 → airless_google_cloud_core-0.0.3}/airless/google/cloud/core/operator/base.py +6 -2
  4. airless_google_cloud_core-0.0.3/airless/google/cloud/core/operator/delay.py +11 -0
  5. {airless_google_cloud_core-0.0.2.dev1 → airless_google_cloud_core-0.0.3}/airless/google/cloud/core/operator/error.py +49 -7
  6. airless_google_cloud_core-0.0.3/airless/google/cloud/pubsub/hook/__init__.py +5 -0
  7. airless_google_cloud_core-0.0.3/airless/google/cloud/pubsub/hook/pubsub.py +40 -0
  8. {airless_google_cloud_core-0.0.2.dev1 → airless_google_cloud_core-0.0.3}/airless_google_cloud_core.egg-info/PKG-INFO +3 -4
  9. {airless_google_cloud_core-0.0.2.dev1 → airless_google_cloud_core-0.0.3}/airless_google_cloud_core.egg-info/SOURCES.txt +2 -6
  10. airless_google_cloud_core-0.0.3/pyproject.toml +54 -0
  11. airless_google_cloud_core-0.0.3/setup.cfg +4 -0
  12. airless_google_cloud_core-0.0.3/tests/test_fake.py +3 -0
  13. airless_google_cloud_core-0.0.2.dev1/airless/__init__.py +0 -1
  14. airless_google_cloud_core-0.0.2.dev1/airless/google/cloud/core/__init__.py +0 -0
  15. airless_google_cloud_core-0.0.2.dev1/airless/google/cloud/core/operator/__init__.py +0 -4
  16. airless_google_cloud_core-0.0.2.dev1/airless/google/cloud/core/operator/delay.py +0 -18
  17. airless_google_cloud_core-0.0.2.dev1/airless/google/cloud/pubsub/__init__.py +0 -0
  18. airless_google_cloud_core-0.0.2.dev1/airless/google/cloud/pubsub/hook/__init__.py +0 -1
  19. airless_google_cloud_core-0.0.2.dev1/airless/google/cloud/pubsub/hook/pubsub.py +0 -30
  20. airless_google_cloud_core-0.0.2.dev1/airless_google_cloud_core.egg-info/requires.txt +0 -2
  21. airless_google_cloud_core-0.0.2.dev1/pyproject.toml +0 -19
  22. airless_google_cloud_core-0.0.2.dev1/setup.cfg +0 -32
  23. {airless_google_cloud_core-0.0.2.dev1 → airless_google_cloud_core-0.0.3}/README.md +0 -0
  24. {airless_google_cloud_core-0.0.2.dev1/airless/google → airless_google_cloud_core-0.0.3/airless/google/cloud/core}/__init__.py +0 -0
  25. {airless_google_cloud_core-0.0.2.dev1 → airless_google_cloud_core-0.0.3}/airless/google/cloud/core/operator/redirect.py +0 -0
  26. {airless_google_cloud_core-0.0.2.dev1/airless/google/cloud → airless_google_cloud_core-0.0.3/airless/google/cloud/pubsub}/__init__.py +0 -0
  27. {airless_google_cloud_core-0.0.2.dev1 → airless_google_cloud_core-0.0.3}/airless_google_cloud_core.egg-info/dependency_links.txt +0 -0
  28. {airless_google_cloud_core-0.0.2.dev1 → airless_google_cloud_core-0.0.3}/airless_google_cloud_core.egg-info/top_level.txt +0 -0
@@ -1,13 +1,12 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: airless-google-cloud-core
3
- Version: 0.0.2.dev1
3
+ Version: 0.0.3
4
4
  Summary: Airless package with the main components to use airless in google cloud
5
+ License: MIT License
5
6
  Project-URL: Homepage, https://github.com/astercapital/airless
6
7
  Project-URL: Bug Tracker, https://github.com/astercapital/airless/issues
7
8
  Requires-Python: >=3.9
8
9
  Description-Content-Type: text/markdown
9
- Requires-Dist: google-cloud-pubsub==2.13.11
10
- Requires-Dist: airless-core>=0.1.0.dev1
11
10
 
12
11
  # airless-google-cloud-core
13
12
 
@@ -0,0 +1,12 @@
1
+ from .base import (GoogleBaseEventOperator, GoogleBaseFileOperator)
2
+ from .delay import (GoogleDelayOperator)
3
+ from .error import (GoogleErrorReprocessOperator)
4
+ from .redirect import (GoogleRedirectOperator)
5
+
6
+ __all__ = [
7
+ 'GoogleBaseEventOperator',
8
+ 'GoogleBaseFileOperator',
9
+ 'GoogleDelayOperator',
10
+ 'GoogleErrorReprocessOperator',
11
+ 'GoogleRedirectOperator'
12
+ ]
@@ -5,14 +5,18 @@ from airless.google.cloud.pubsub.hook import GooglePubsubHook
5
5
 
6
6
 
7
7
  class GoogleBaseFileOperator(BaseFileOperator):
8
+ """Base operator for file operations in Google Cloud."""
8
9
 
9
- def __init__(self):
10
+ def __init__(self) -> None:
11
+ """Initializes the GoogleBaseFileOperator."""
10
12
  super().__init__()
11
13
  self.queue_hook = GooglePubsubHook() # Have to redefine this attribute for each vendor
12
14
 
13
15
 
14
16
  class GoogleBaseEventOperator(BaseEventOperator):
17
+ """Base operator for event operations in Google Cloud."""
15
18
 
16
- def __init__(self):
19
+ def __init__(self) -> None:
20
+ """Initializes the GoogleBaseEventOperator."""
17
21
  super().__init__()
18
22
  self.queue_hook = GooglePubsubHook() # Have to redefine this attribute for each vendor
@@ -0,0 +1,11 @@
1
+
2
+ from airless.core.operator import DelayOperator
3
+ from airless.google.cloud.core.operator import GoogleBaseEventOperator
4
+
5
+
6
+ class GoogleDelayOperator(GoogleBaseEventOperator, DelayOperator):
7
+ """Operator that adds a delay to the pipeline."""
8
+
9
+ def __init__(self) -> None:
10
+ """Initializes the GoogleDelayOperator."""
11
+ super().__init__()
@@ -1,6 +1,7 @@
1
1
 
2
2
  import json
3
3
  import time
4
+ from typing import Any, Dict, List, Optional
4
5
 
5
6
  from datetime import datetime
6
7
 
@@ -10,12 +11,19 @@ from airless.google.cloud.core.operator import GoogleBaseEventOperator
10
11
 
11
12
 
12
13
  class GoogleErrorReprocessOperator(GoogleBaseEventOperator):
14
+ """Operator for reprocessing errors in Google Cloud."""
13
15
 
14
- def __init__(self):
16
+ def __init__(self) -> None:
17
+ """Initializes the GoogleErrorReprocessOperator."""
15
18
  super().__init__()
16
19
 
17
- def execute(self, data, topic):
20
+ def execute(self, data: Dict[str, Any], topic: str) -> None:
21
+ """Executes the error reprocessing logic.
18
22
 
23
+ Args:
24
+ data (Dict[str, Any]): The input data containing error information.
25
+ topic (str): The Pub/Sub topic to publish messages to.
26
+ """
19
27
  input_type = data['input_type']
20
28
  origin = data.get('origin', 'undefined')
21
29
  message_id = data.get('event_id')
@@ -25,7 +33,7 @@ class GoogleErrorReprocessOperator(GoogleBaseEventOperator):
25
33
  retry_interval = metadata.get('retry_interval', 5)
26
34
  retries = metadata.get('retries', 0)
27
35
  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)
36
+ max_interval = metadata.get('max_interval', 480)
29
37
 
30
38
  if (input_type == 'event') and (retries < max_retries):
31
39
  time.sleep(min(retry_interval ** retries, max_interval))
@@ -60,7 +68,14 @@ class GoogleErrorReprocessOperator(GoogleBaseEventOperator):
60
68
  if slack_send_topic and (origin != slack_send_topic):
61
69
  self.notify_slack(origin, message_id, data)
62
70
 
63
- def notify_email(self, origin, message_id, data):
71
+ def notify_email(self, origin: str, message_id: str, data: Dict[str, Any]) -> None:
72
+ """Sends a notification email.
73
+
74
+ Args:
75
+ origin (str): The origin of the error.
76
+ message_id (str): The ID of the message.
77
+ data (Dict[str, Any]): The data related to the error.
78
+ """
64
79
  email_message = {
65
80
  'sender': get_config('EMAIL_SENDER_ERROR'),
66
81
  'recipients': eval(get_config('EMAIL_RECIPIENTS_ERROR')),
@@ -72,7 +87,14 @@ class GoogleErrorReprocessOperator(GoogleBaseEventOperator):
72
87
  topic=get_config('PUBSUB_TOPIC_EMAIL_SEND'),
73
88
  data=email_message)
74
89
 
75
- def notify_slack(self, origin, message_id, data):
90
+ def notify_slack(self, origin: str, message_id: str, data: Dict[str, Any]) -> None:
91
+ """Sends a notification to Slack.
92
+
93
+ Args:
94
+ origin (str): The origin of the error.
95
+ message_id (str): The ID of the message.
96
+ data (Dict[str, Any]): The data related to the error.
97
+ """
76
98
  slack_message = {
77
99
  'channels': eval(get_config('SLACK_CHANNELS_ERROR')),
78
100
  'message': f'{origin} | {message_id}\n\n{json.dumps(data["data"])}\n\n{data["error"]}'
@@ -82,7 +104,17 @@ class GoogleErrorReprocessOperator(GoogleBaseEventOperator):
82
104
  topic=get_config('PUBSUB_TOPIC_SLACK_SEND'),
83
105
  data=slack_message)
84
106
 
85
- def prepare_row(self, row, message_id, origin):
107
+ def prepare_row(self, row: Dict[str, Any], message_id: Optional[str], origin: Optional[str]) -> Dict[str, Any]:
108
+ """Prepares a row for insertion.
109
+
110
+ Args:
111
+ row (Dict[str, Any]): The row data.
112
+ message_id (Optional[str]): The message ID.
113
+ origin (Optional[str]): The origin of the message.
114
+
115
+ Returns:
116
+ Dict[str, Any]: The prepared row.
117
+ """
86
118
  return {
87
119
  '_event_id': message_id or 1234,
88
120
  '_resource': origin or 'local',
@@ -90,6 +122,16 @@ class GoogleErrorReprocessOperator(GoogleBaseEventOperator):
90
122
  '_created_at': str(datetime.now())
91
123
  }
92
124
 
93
- def prepare_rows(self, data, message_id, origin):
125
+ def prepare_rows(self, data: Any, message_id: Optional[str], origin: Optional[str]) -> List[Dict[str, Any]]:
126
+ """Prepares multiple rows for insertion.
127
+
128
+ Args:
129
+ data (Any): The data to prepare.
130
+ message_id (Optional[str]): The message ID.
131
+ origin (Optional[str]): The origin of the message.
132
+
133
+ Returns:
134
+ List[Dict[str, Any]]: The list of prepared rows.
135
+ """
94
136
  prepared_rows = data if isinstance(data, list) else [data]
95
137
  return [self.prepare_row(row, message_id, origin) for row in prepared_rows]
@@ -0,0 +1,5 @@
1
+ from .pubsub import (GooglePubsubHook)
2
+
3
+ __all__ = [
4
+ 'GooglePubsubHook'
5
+ ]
@@ -0,0 +1,40 @@
1
+
2
+ import json
3
+ from typing import Any
4
+
5
+ from google.cloud import pubsub_v1
6
+
7
+ from airless.core.hook import QueueHook
8
+ from airless.core.utils import get_config
9
+
10
+
11
+ class GooglePubsubHook(QueueHook):
12
+ """Hook for interacting with Google Pub/Sub."""
13
+
14
+ def __init__(self) -> None:
15
+ """Initializes the GooglePubsubHook."""
16
+ super().__init__()
17
+ self.publisher = pubsub_v1.PublisherClient()
18
+
19
+ def publish(self, project: str, topic: str, data: Any) -> str:
20
+ """Publishes a message to a specified Pub/Sub topic.
21
+
22
+ Args:
23
+ project (str): The GCP project ID.
24
+ topic (str): The Pub/Sub topic name.
25
+ data (Any): The data to publish.
26
+
27
+ Returns:
28
+ str: A confirmation message.
29
+ """
30
+ if get_config('ENV') == 'prod':
31
+ topic_path = self.publisher.topic_path(project or get_config('GCP_PROJECT'), topic)
32
+
33
+ message_bytes = json.dumps(data).encode('utf-8')
34
+
35
+ publish_future = self.publisher.publish(topic_path, data=message_bytes)
36
+ publish_future.result(timeout=10)
37
+ self.logger.info(f'published to {project or get_config("GCP_PROJECT")}.{topic}')
38
+ return 'Message published.'
39
+ else:
40
+ self.logger.debug(f'[DEV] Message published to Project {project or get_config("GCP_PROJECT")}, Topic {topic}: {data}')
@@ -1,13 +1,12 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: airless-google-cloud-core
3
- Version: 0.0.2.dev1
3
+ Version: 0.0.3
4
4
  Summary: Airless package with the main components to use airless in google cloud
5
+ License: MIT License
5
6
  Project-URL: Homepage, https://github.com/astercapital/airless
6
7
  Project-URL: Bug Tracker, https://github.com/astercapital/airless/issues
7
8
  Requires-Python: >=3.9
8
9
  Description-Content-Type: text/markdown
9
- Requires-Dist: google-cloud-pubsub==2.13.11
10
- Requires-Dist: airless-core>=0.1.0.dev1
11
10
 
12
11
  # airless-google-cloud-core
13
12
 
@@ -1,9 +1,5 @@
1
1
  README.md
2
2
  pyproject.toml
3
- setup.cfg
4
- airless/__init__.py
5
- airless/google/__init__.py
6
- airless/google/cloud/__init__.py
7
3
  airless/google/cloud/core/__init__.py
8
4
  airless/google/cloud/core/operator/__init__.py
9
5
  airless/google/cloud/core/operator/base.py
@@ -16,5 +12,5 @@ airless/google/cloud/pubsub/hook/pubsub.py
16
12
  airless_google_cloud_core.egg-info/PKG-INFO
17
13
  airless_google_cloud_core.egg-info/SOURCES.txt
18
14
  airless_google_cloud_core.egg-info/dependency_links.txt
19
- airless_google_cloud_core.egg-info/requires.txt
20
- airless_google_cloud_core.egg-info/top_level.txt
15
+ airless_google_cloud_core.egg-info/top_level.txt
16
+ tests/test_fake.py
@@ -0,0 +1,54 @@
1
+ [project]
2
+ name = "airless-google-cloud-core"
3
+ version = "0.0.3"
4
+ description = "Airless package with the main components to use airless in google cloud"
5
+ readme = "README.md"
6
+ requires-python = ">=3.9"
7
+ dynamic = ["dependencies"]
8
+ license = {text = "MIT License"}
9
+
10
+ [build-system]
11
+ requires = ["setuptools", "wheel"]
12
+ build-backend = "setuptools.build_meta"
13
+
14
+ [project.urls]
15
+ "Homepage" = "https://github.com/astercapital/airless"
16
+ "Bug Tracker" = "https://github.com/astercapital/airless/issues"
17
+
18
+ [tool.pytest.ini_options]
19
+ minversion = "6.0"
20
+ addopts = "--capture=sys --cache-clear --disable-warnings --junitxml=pytest.xml --cov-report=xml:cov.xml --cov-report=term-missing:skip-covered --cov=airless"
21
+ testpaths = ["tests"]
22
+
23
+ [tool.setuptools.packages.find]
24
+ include = ["airless*"]
25
+
26
+ [tool.ruff]
27
+ exclude = [
28
+ ".git",
29
+ "__pycache__",
30
+ "build",
31
+ "dist",
32
+ "*.pyc",
33
+ "*.egg-info",
34
+ "*.egg",
35
+ "temp",
36
+ "venv"
37
+ ]
38
+ line-length = 88
39
+ indent-width = 4
40
+ target-version = "py39"
41
+
42
+ [tool.ruff.lint]
43
+ ignore = ["E501"]
44
+ fixable = ["ALL"]
45
+ unfixable = []
46
+ dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$"
47
+
48
+ [tool.ruff.format]
49
+ quote-style = "single"
50
+ indent-style = "space"
51
+ skip-magic-trailing-comma = false
52
+ line-ending = "lf"
53
+ docstring-code-format = false
54
+ docstring-code-line-length = "dynamic"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,3 @@
1
+
2
+ def test_fake():
3
+ assert 1 == 1
@@ -1 +0,0 @@
1
- __path__ = __import__('pkgutil').extend_path(__path__, __name__)
@@ -1,4 +0,0 @@
1
- from .base import (GoogleBaseEventOperator, GoogleBaseFileOperator)
2
- from .delay import (GoogleDelayOperator)
3
- from .error import (GoogleErrorReprocessOperator)
4
- from .redirect import (GoogleRedirectOperator)
@@ -1,18 +0,0 @@
1
-
2
- from airless.core.operator import DelayOperator
3
- from airless.google.cloud.core.operator import GoogleBaseEventOperator
4
-
5
-
6
-
7
- class GoogleDelayOperator(GoogleBaseEventOperator, DelayOperator):
8
-
9
- """
10
- Operator that adds a delay to the pipeline. The maximum delay is 500 due
11
- to Cloud Functions time constraint of 540 of execution time
12
-
13
- It can receive 1 parameter:
14
- seconds: number of seconds to wait
15
- """
16
-
17
- def __init__(self):
18
- super().__init__()
@@ -1 +0,0 @@
1
- from .pubsub import (GooglePubsubHook)
@@ -1,30 +0,0 @@
1
-
2
- import json
3
-
4
- from google.cloud import pubsub_v1
5
-
6
- from airless.core.hook import QueueHook
7
- from airless.core.utils 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}')
@@ -1,2 +0,0 @@
1
- google-cloud-pubsub==2.13.11
2
- airless-core>=0.1.0.dev1
@@ -1,19 +0,0 @@
1
- [project]
2
- name = "airless-google-cloud-core"
3
- version = "0.0.2.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"]
@@ -1,32 +0,0 @@
1
- [metadata]
2
- name = airless-google-cloud-core
3
- version = 0.0.1
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*
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
-