franchise-cloud-utils 0.1.0__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.
@@ -0,0 +1,22 @@
1
+ Metadata-Version: 2.4
2
+ Name: franchise-cloud-utils
3
+ Version: 0.1.0
4
+ Summary: Advanced, scalable Cloud utilities for robust Django applications.
5
+ Author: Franchise Team
6
+ Project-URL: Homepage, https://github.com/your-org/franchise-cloud-utils
7
+ Classifier: Programming Language :: Python :: 3
8
+ Classifier: Operating System :: OS Independent
9
+ Requires-Python: >=3.9
10
+ Description-Content-Type: text/markdown
11
+ Requires-Dist: boto3>=1.28.0
12
+
13
+ # franchise-cloud-utils
14
+
15
+ Advanced programming constructs and utilities to create secure, dynamic, configurable, robust, and scalable cloud-based server applications.
16
+
17
+ ## Modules included:
18
+
19
+ 1. **Validators** (`franchise_cloud_utils.validator`): Employs Python descriptors to securely ensure data constraints without relying strictly on ORM validation.
20
+ 2. **RBAC** (`franchise_cloud_utils.rbac`): Uses metaprogramming for dynamic, robust role-based access control registries.
21
+ 3. **Events** (`franchise_cloud_utils.events`): Implements an observer pattern for decoupled application logic.
22
+ 4. **Cloud** (`franchise_cloud_utils.cloud`): Resilient AWS utility abstractions, featuring exponential backoff and singletons.
@@ -0,0 +1,10 @@
1
+ # franchise-cloud-utils
2
+
3
+ Advanced programming constructs and utilities to create secure, dynamic, configurable, robust, and scalable cloud-based server applications.
4
+
5
+ ## Modules included:
6
+
7
+ 1. **Validators** (`franchise_cloud_utils.validator`): Employs Python descriptors to securely ensure data constraints without relying strictly on ORM validation.
8
+ 2. **RBAC** (`franchise_cloud_utils.rbac`): Uses metaprogramming for dynamic, robust role-based access control registries.
9
+ 3. **Events** (`franchise_cloud_utils.events`): Implements an observer pattern for decoupled application logic.
10
+ 4. **Cloud** (`franchise_cloud_utils.cloud`): Resilient AWS utility abstractions, featuring exponential backoff and singletons.
@@ -0,0 +1,22 @@
1
+ Metadata-Version: 2.4
2
+ Name: franchise-cloud-utils
3
+ Version: 0.1.0
4
+ Summary: Advanced, scalable Cloud utilities for robust Django applications.
5
+ Author: Franchise Team
6
+ Project-URL: Homepage, https://github.com/your-org/franchise-cloud-utils
7
+ Classifier: Programming Language :: Python :: 3
8
+ Classifier: Operating System :: OS Independent
9
+ Requires-Python: >=3.9
10
+ Description-Content-Type: text/markdown
11
+ Requires-Dist: boto3>=1.28.0
12
+
13
+ # franchise-cloud-utils
14
+
15
+ Advanced programming constructs and utilities to create secure, dynamic, configurable, robust, and scalable cloud-based server applications.
16
+
17
+ ## Modules included:
18
+
19
+ 1. **Validators** (`franchise_cloud_utils.validator`): Employs Python descriptors to securely ensure data constraints without relying strictly on ORM validation.
20
+ 2. **RBAC** (`franchise_cloud_utils.rbac`): Uses metaprogramming for dynamic, robust role-based access control registries.
21
+ 3. **Events** (`franchise_cloud_utils.events`): Implements an observer pattern for decoupled application logic.
22
+ 4. **Cloud** (`franchise_cloud_utils.cloud`): Resilient AWS utility abstractions, featuring exponential backoff and singletons.
@@ -0,0 +1,8 @@
1
+ README.md
2
+ franchise_cloud_utils.py
3
+ pyproject.toml
4
+ franchise_cloud_utils.egg-info/PKG-INFO
5
+ franchise_cloud_utils.egg-info/SOURCES.txt
6
+ franchise_cloud_utils.egg-info/dependency_links.txt
7
+ franchise_cloud_utils.egg-info/requires.txt
8
+ franchise_cloud_utils.egg-info/top_level.txt
@@ -0,0 +1 @@
1
+ franchise_cloud_utils
@@ -0,0 +1,227 @@
1
+ """
2
+ Franchise Cloud Utilities (Single File Module)
3
+ Advanced constructs for secure, dynamic, scalable cloud-based applications.
4
+
5
+ Version 0.1.0
6
+ """
7
+ import re
8
+ import time
9
+ import logging
10
+ import threading
11
+ from functools import wraps
12
+ from typing import Callable, Dict, List, Any
13
+
14
+ # ==============================================================================
15
+ # Data Validation Descriptors
16
+ # ==============================================================================
17
+
18
+ class BaseField:
19
+ def __init__(self, name=None):
20
+ self.name = name
21
+
22
+ def __set_name__(self, owner, name):
23
+ self.name = name
24
+
25
+ def __get__(self, instance, owner):
26
+ if instance is None:
27
+ return self
28
+ return instance.__dict__.get(self.name)
29
+
30
+ class StringField(BaseField):
31
+ def __init__(self, min_length=0, max_length=None, pattern=None, **kwargs):
32
+ super().__init__(**kwargs)
33
+ self.min_length = min_length
34
+ self.max_length = max_length
35
+ self.pattern = re.compile(pattern) if pattern else None
36
+
37
+ def __set__(self, instance, value):
38
+ if not isinstance(value, str):
39
+ raise TypeError(f"'{self.name}' must be a string, got {type(value).__name__}")
40
+ if len(value) < self.min_length:
41
+ raise ValueError(f"'{self.name}' must be at least {self.min_length} characters")
42
+ if self.max_length and len(value) > self.max_length:
43
+ raise ValueError(f"'{self.name}' cannot exceed {self.max_length} characters")
44
+ if self.pattern and not self.pattern.match(value):
45
+ raise ValueError(f"'{self.name}' does not match required format")
46
+
47
+ instance.__dict__[self.name] = value
48
+
49
+ class IntegerField(BaseField):
50
+ def __init__(self, min_value=None, max_value=None, **kwargs):
51
+ super().__init__(**kwargs)
52
+ self.min_value = min_value
53
+ self.max_value = max_value
54
+
55
+ def __set__(self, instance, value):
56
+ if not isinstance(value, int) or isinstance(value, bool):
57
+ raise TypeError(f"'{self.name}' must be an integer")
58
+ if self.min_value is not None and value < self.min_value:
59
+ raise ValueError(f"'{self.name}' must be >= {self.min_value}")
60
+ if self.max_value is not None and value > self.max_value:
61
+ raise ValueError(f"'{self.name}' must be <= {self.max_value}")
62
+
63
+ instance.__dict__[self.name] = value
64
+
65
+ class SchemaValidator:
66
+ def __init__(self, **kwargs):
67
+ for key, value in kwargs.items():
68
+ if hasattr(self.__class__, key):
69
+ setattr(self, key, value)
70
+ else:
71
+ raise AttributeError(f"'{self.__class__.__name__}' does not have field '{key}'")
72
+
73
+
74
+ # ==============================================================================
75
+ # Role-Based Access Control (RBAC)
76
+ # ==============================================================================
77
+
78
+ _ROLE_REGISTRY = {}
79
+
80
+ class RoleRegistryMeta(type):
81
+ def __new__(cls, name, bases, attrs):
82
+ new_class = super().__new__(cls, name, bases, attrs)
83
+ if name != 'BaseRole':
84
+ _ROLE_REGISTRY[name] = new_class
85
+ return new_class
86
+
87
+ class BaseRole(metaclass=RoleRegistryMeta):
88
+ permissions = []
89
+ @classmethod
90
+ def can_access(cls, permission: str) -> bool:
91
+ return permission in cls.permissions
92
+
93
+ _tls = threading.local()
94
+
95
+ class sudo:
96
+ def __enter__(self):
97
+ self.original = getattr(_tls, 'is_sudo', False)
98
+ _tls.is_sudo = True
99
+ return self
100
+
101
+ def __exit__(self, exc_type, exc_val, exc_tb):
102
+ _tls.is_sudo = self.original
103
+
104
+ def require_roles(*allowed_roles):
105
+ def decorator(view_func):
106
+ @wraps(view_func)
107
+ def _wrapped_view(request, *args, **kwargs):
108
+ if getattr(_tls, 'is_sudo', False):
109
+ return view_func(request, *args, **kwargs)
110
+
111
+ user_role = getattr(request.user, 'role', None)
112
+ if user_role not in allowed_roles:
113
+ from django.core.exceptions import PermissionDenied
114
+ raise PermissionDenied("User does not have the required cloud privileges.")
115
+
116
+ return view_func(request, *args, **kwargs)
117
+ return _wrapped_view
118
+ return decorator
119
+
120
+
121
+ # ==============================================================================
122
+ # Event Observer Bus
123
+ # ==============================================================================
124
+
125
+ class EventSubscriber:
126
+ def __init__(self, callback: Callable, is_async: bool = False):
127
+ self.callback = callback
128
+ self.is_async = is_async
129
+
130
+ class EventDispatcher:
131
+ _instance = None
132
+ _lock = threading.Lock()
133
+
134
+ def __new__(cls):
135
+ with cls._lock:
136
+ if cls._instance is None:
137
+ cls._instance = super(EventDispatcher, cls).__new__(cls)
138
+ cls._instance.subscribers: Dict[str, List[EventSubscriber]] = {}
139
+ return cls._instance
140
+
141
+ def subscribe(self, event_type: str, callback: Callable, is_async: bool = False):
142
+ if event_type not in self.subscribers:
143
+ self.subscribers[event_type] = []
144
+ subscriber = EventSubscriber(callback, is_async=is_async)
145
+ self.subscribers[event_type].append(subscriber)
146
+
147
+ def dispatch(self, event_type: str, *args, **kwargs):
148
+ if event_type not in self.subscribers:
149
+ return
150
+ for subscriber in self.subscribers[event_type]:
151
+ if subscriber.is_async:
152
+ thread = threading.Thread(
153
+ target=subscriber.callback,
154
+ args=args,
155
+ kwargs=kwargs,
156
+ daemon=True
157
+ )
158
+ thread.start()
159
+ else:
160
+ subscriber.callback(*args, **kwargs)
161
+
162
+ bus = EventDispatcher()
163
+
164
+
165
+ # ==============================================================================
166
+ # Cloud Resiliency
167
+ # ==============================================================================
168
+
169
+ logger = logging.getLogger(__name__)
170
+
171
+ def retry_with_backoff(retries: int = 3, initial_backoff: float = 1.0, max_backoff: float = 60.0):
172
+ def decorator(func):
173
+ @wraps(func)
174
+ def wrapper(*args, **kwargs):
175
+ backoff = initial_backoff
176
+ for attempt in range(retries):
177
+ try:
178
+ return func(*args, **kwargs)
179
+ except Exception as e:
180
+ if attempt == retries - 1:
181
+ logger.error(f"Function {func.__name__} failed after {retries} attempts.")
182
+ raise e
183
+ logger.warning(
184
+ f"Attempt {attempt + 1} failed for {func.__name__}: {str(e)}. "
185
+ f"Retrying in {backoff} seconds..."
186
+ )
187
+ time.sleep(backoff)
188
+ backoff = min(backoff * 2, max_backoff)
189
+ return wrapper
190
+ return decorator
191
+
192
+ class AWSBorg:
193
+ _shared_state: Dict[str, Any] = {}
194
+
195
+ def __init__(self):
196
+ self.__dict__ = self._shared_state
197
+ if not hasattr(self, 'clients'):
198
+ self.clients: Dict[str, Any] = {}
199
+
200
+ def get_client(self, service_name: str, region_name: str = 'us-east-1'):
201
+ import boto3
202
+ key = f"{service_name}_{region_name}"
203
+ if key not in self.clients:
204
+ self.clients[key] = boto3.client(service_name, region_name=region_name)
205
+ return self.clients[key]
206
+
207
+ class SecretManagerCache:
208
+ def __init__(self, ttl_seconds: int = 300):
209
+ self.ttl = ttl_seconds
210
+ self._cache = {}
211
+ self._timestamps = {}
212
+ self._borg = AWSBorg()
213
+
214
+ @retry_with_backoff(retries=3)
215
+ def get_secret(self, secret_id: str) -> str:
216
+ now = time.time()
217
+ if secret_id in self._cache:
218
+ if now - self._timestamps.get(secret_id, 0) < self.ttl:
219
+ return self._cache[secret_id]
220
+
221
+ client = self._borg.get_client('secretsmanager')
222
+ response = client.get_secret_value(SecretId=secret_id)
223
+ secret_string = response.get('SecretString')
224
+
225
+ self._cache[secret_id] = secret_string
226
+ self._timestamps[secret_id] = now
227
+ return secret_string
@@ -0,0 +1,26 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "franchise-cloud-utils"
7
+ version = "0.1.0"
8
+ authors = [
9
+ { name="Franchise Team" },
10
+ ]
11
+ description = "Advanced, scalable Cloud utilities for robust Django applications."
12
+ readme = "README.md"
13
+ requires-python = ">=3.9"
14
+ classifiers = [
15
+ "Programming Language :: Python :: 3",
16
+ "Operating System :: OS Independent",
17
+ ]
18
+ dependencies = [
19
+ "boto3>=1.28.0",
20
+ ]
21
+
22
+ [project.urls]
23
+ "Homepage" = "https://github.com/your-org/franchise-cloud-utils"
24
+
25
+ [tool.setuptools]
26
+ py-modules = ["franchise_cloud_utils"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+