provide-foundation 0.0.0.dev0__py3-none-any.whl → 0.0.0.dev1__py3-none-any.whl

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 (92) hide show
  1. provide/foundation/__init__.py +12 -20
  2. provide/foundation/archive/__init__.py +23 -0
  3. provide/foundation/archive/base.py +70 -0
  4. provide/foundation/archive/bzip2.py +157 -0
  5. provide/foundation/archive/gzip.py +159 -0
  6. provide/foundation/archive/operations.py +336 -0
  7. provide/foundation/archive/tar.py +164 -0
  8. provide/foundation/archive/zip.py +203 -0
  9. provide/foundation/config/base.py +2 -2
  10. provide/foundation/config/sync.py +19 -4
  11. provide/foundation/core.py +1 -2
  12. provide/foundation/crypto/__init__.py +2 -0
  13. provide/foundation/crypto/certificates/__init__.py +34 -0
  14. provide/foundation/crypto/certificates/base.py +173 -0
  15. provide/foundation/crypto/certificates/certificate.py +290 -0
  16. provide/foundation/crypto/certificates/factory.py +213 -0
  17. provide/foundation/crypto/certificates/generator.py +138 -0
  18. provide/foundation/crypto/certificates/loader.py +130 -0
  19. provide/foundation/crypto/certificates/operations.py +198 -0
  20. provide/foundation/crypto/certificates/trust.py +107 -0
  21. provide/foundation/eventsets/__init__.py +0 -0
  22. provide/foundation/eventsets/display.py +84 -0
  23. provide/foundation/eventsets/registry.py +160 -0
  24. provide/foundation/eventsets/resolver.py +192 -0
  25. provide/foundation/eventsets/sets/das.py +128 -0
  26. provide/foundation/eventsets/sets/database.py +125 -0
  27. provide/foundation/eventsets/sets/http.py +153 -0
  28. provide/foundation/eventsets/sets/llm.py +139 -0
  29. provide/foundation/eventsets/sets/task_queue.py +107 -0
  30. provide/foundation/eventsets/types.py +70 -0
  31. provide/foundation/hub/components.py +7 -133
  32. provide/foundation/logger/__init__.py +3 -10
  33. provide/foundation/logger/config/logging.py +6 -6
  34. provide/foundation/logger/core.py +0 -2
  35. provide/foundation/logger/custom_processors.py +1 -0
  36. provide/foundation/logger/factories.py +11 -2
  37. provide/foundation/logger/processors/main.py +20 -84
  38. provide/foundation/logger/setup/__init__.py +5 -1
  39. provide/foundation/logger/setup/coordinator.py +75 -23
  40. provide/foundation/logger/setup/processors.py +2 -9
  41. provide/foundation/logger/trace.py +27 -0
  42. provide/foundation/metrics/otel.py +10 -10
  43. provide/foundation/process/lifecycle.py +82 -26
  44. provide/foundation/testing/__init__.py +77 -0
  45. provide/foundation/testing/archive/__init__.py +24 -0
  46. provide/foundation/testing/archive/fixtures.py +217 -0
  47. provide/foundation/testing/common/__init__.py +34 -0
  48. provide/foundation/testing/common/fixtures.py +263 -0
  49. provide/foundation/testing/file/__init__.py +40 -0
  50. provide/foundation/testing/file/fixtures.py +523 -0
  51. provide/foundation/testing/logger.py +41 -11
  52. provide/foundation/testing/mocking/__init__.py +46 -0
  53. provide/foundation/testing/mocking/fixtures.py +331 -0
  54. provide/foundation/testing/process/__init__.py +48 -0
  55. provide/foundation/testing/process/fixtures.py +577 -0
  56. provide/foundation/testing/threading/__init__.py +38 -0
  57. provide/foundation/testing/threading/fixtures.py +520 -0
  58. provide/foundation/testing/time/__init__.py +32 -0
  59. provide/foundation/testing/time/fixtures.py +409 -0
  60. provide/foundation/testing/transport/__init__.py +30 -0
  61. provide/foundation/testing/transport/fixtures.py +280 -0
  62. provide/foundation/tools/__init__.py +58 -0
  63. provide/foundation/tools/base.py +348 -0
  64. provide/foundation/tools/cache.py +266 -0
  65. provide/foundation/tools/downloader.py +213 -0
  66. provide/foundation/tools/installer.py +254 -0
  67. provide/foundation/tools/registry.py +223 -0
  68. provide/foundation/tools/resolver.py +321 -0
  69. provide/foundation/tools/verifier.py +186 -0
  70. provide/foundation/tracer/otel.py +7 -11
  71. provide/foundation/transport/__init__.py +155 -0
  72. provide/foundation/transport/base.py +171 -0
  73. provide/foundation/transport/client.py +266 -0
  74. provide/foundation/transport/config.py +209 -0
  75. provide/foundation/transport/errors.py +79 -0
  76. provide/foundation/transport/http.py +232 -0
  77. provide/foundation/transport/middleware.py +366 -0
  78. provide/foundation/transport/registry.py +167 -0
  79. provide/foundation/transport/types.py +45 -0
  80. {provide_foundation-0.0.0.dev0.dist-info → provide_foundation-0.0.0.dev1.dist-info}/METADATA +5 -28
  81. {provide_foundation-0.0.0.dev0.dist-info → provide_foundation-0.0.0.dev1.dist-info}/RECORD +85 -34
  82. provide/foundation/cli/commands/logs/generate_old.py +0 -569
  83. provide/foundation/crypto/certificates.py +0 -896
  84. provide/foundation/logger/emoji/__init__.py +0 -44
  85. provide/foundation/logger/emoji/matrix.py +0 -209
  86. provide/foundation/logger/emoji/sets.py +0 -458
  87. provide/foundation/logger/emoji/types.py +0 -56
  88. provide/foundation/logger/setup/emoji_resolver.py +0 -64
  89. {provide_foundation-0.0.0.dev0.dist-info → provide_foundation-0.0.0.dev1.dist-info}/WHEEL +0 -0
  90. {provide_foundation-0.0.0.dev0.dist-info → provide_foundation-0.0.0.dev1.dist-info}/entry_points.txt +0 -0
  91. {provide_foundation-0.0.0.dev0.dist-info → provide_foundation-0.0.0.dev1.dist-info}/licenses/LICENSE +0 -0
  92. {provide_foundation-0.0.0.dev0.dist-info → provide_foundation-0.0.0.dev1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,366 @@
1
+ """
2
+ Transport middleware system with Hub registration.
3
+ """
4
+
5
+ import asyncio
6
+ import time
7
+ from abc import ABC, abstractmethod
8
+ from typing import Any
9
+
10
+ from attrs import define, field
11
+
12
+ from provide.foundation.hub import get_component_registry
13
+ from provide.foundation.hub.components import ComponentCategory
14
+ from provide.foundation.logger import get_logger
15
+ from provide.foundation.metrics import counter, histogram
16
+ from provide.foundation.transport.base import Request, Response
17
+ from provide.foundation.transport.errors import TransportError
18
+
19
+ log = get_logger(__name__)
20
+
21
+
22
+ class Middleware(ABC):
23
+ """Abstract base class for transport middleware."""
24
+
25
+ @abstractmethod
26
+ async def process_request(self, request: Request) -> Request:
27
+ """Process request before sending."""
28
+ pass
29
+
30
+ @abstractmethod
31
+ async def process_response(self, response: Response) -> Response:
32
+ """Process response after receiving."""
33
+ pass
34
+
35
+ @abstractmethod
36
+ async def process_error(self, error: Exception, request: Request) -> Exception:
37
+ """Process errors during request."""
38
+ pass
39
+
40
+
41
+ @define
42
+ class LoggingMiddleware(Middleware):
43
+ """Built-in telemetry middleware using foundation.logger."""
44
+
45
+ log_requests: bool = field(default=True)
46
+ log_responses: bool = field(default=True)
47
+ log_bodies: bool = field(default=False)
48
+
49
+ async def process_request(self, request: Request) -> Request:
50
+ """Log outgoing request."""
51
+ if self.log_requests:
52
+ log.info(
53
+ f"🚀 {request.method} {request.uri}",
54
+ method=request.method,
55
+ uri=str(request.uri),
56
+ headers=dict(request.headers) if hasattr(request, 'headers') else {},
57
+ )
58
+
59
+ if self.log_bodies and request.body:
60
+ log.trace("Request body", body=request.body, method=request.method, uri=str(request.uri))
61
+
62
+ return request
63
+
64
+ async def process_response(self, response: Response) -> Response:
65
+ """Log incoming response."""
66
+ if self.log_responses:
67
+ status_emoji = self._get_status_emoji(response.status)
68
+ log.info(
69
+ f"{status_emoji} {response.status} ({response.elapsed_ms:.0f}ms)",
70
+ status_code=response.status,
71
+ elapsed_ms=response.elapsed_ms,
72
+ method=response.request.method if response.request else None,
73
+ uri=str(response.request.uri) if response.request else None,
74
+ headers=dict(response.headers) if hasattr(response, 'headers') else {},
75
+ )
76
+
77
+ if self.log_bodies and response.body:
78
+ log.trace(
79
+ "Response body",
80
+ body=response.text[:500], # Truncate large bodies
81
+ status_code=response.status,
82
+ method=response.request.method if response.request else None,
83
+ uri=str(response.request.uri) if response.request else None,
84
+ )
85
+
86
+ return response
87
+
88
+ async def process_error(self, error: Exception, request: Request) -> Exception:
89
+ """Log errors."""
90
+ log.error(
91
+ f"❌ {request.method} {request.uri} failed: {error}",
92
+ method=request.method,
93
+ uri=str(request.uri),
94
+ error_type=error.__class__.__name__,
95
+ error_message=str(error),
96
+ )
97
+ return error
98
+
99
+ def _get_status_emoji(self, status_code: int) -> str:
100
+ """Get emoji for status code."""
101
+ if 200 <= status_code < 300:
102
+ return "✅"
103
+ elif 300 <= status_code < 400:
104
+ return "↩️"
105
+ elif 400 <= status_code < 500:
106
+ return "⚠️"
107
+ elif 500 <= status_code < 600:
108
+ return "❌"
109
+ else:
110
+ return "❓"
111
+
112
+
113
+ @define
114
+ class RetryMiddleware(Middleware):
115
+ """Automatic retry middleware with exponential backoff."""
116
+
117
+ max_retries: int = field(default=3)
118
+ backoff_factor: float = field(default=0.5)
119
+ retryable_status_codes: set[int] = field(factory=lambda: {500, 502, 503, 504})
120
+ retryable_exceptions: tuple[type[Exception], ...] = field(
121
+ factory=lambda: (TransportError,)
122
+ )
123
+
124
+ async def process_request(self, request: Request) -> Request:
125
+ """No request processing needed."""
126
+ return request
127
+
128
+ async def process_response(self, response: Response) -> Response:
129
+ """No response processing needed (retries handled in execute)."""
130
+ return response
131
+
132
+ async def process_error(self, error: Exception, request: Request) -> Exception:
133
+ """Handle error, potentially with retries (this is called by client)."""
134
+ return error
135
+
136
+ async def execute_with_retry(self, execute_func, request: Request) -> Response:
137
+ """Execute request with retry logic."""
138
+ last_exception = None
139
+
140
+ for attempt in range(self.max_retries + 1):
141
+ try:
142
+ response = await execute_func(request)
143
+
144
+ # Check if status code is retryable
145
+ if response.status in self.retryable_status_codes and attempt < self.max_retries:
146
+ wait_time = self.backoff_factor * (2 ** attempt)
147
+ log.info(f"🔄 Retry {attempt + 1}/{self.max_retries} after {wait_time:.1f}s (status {response.status})")
148
+ await asyncio.sleep(wait_time)
149
+ continue
150
+
151
+ return response
152
+
153
+ except self.retryable_exceptions as e:
154
+ last_exception = e
155
+
156
+ if attempt < self.max_retries:
157
+ wait_time = self.backoff_factor * (2 ** attempt)
158
+ log.info(f"🔄 Retry {attempt + 1}/{self.max_retries} after {wait_time:.1f}s (error: {e})")
159
+ await asyncio.sleep(wait_time)
160
+ else:
161
+ break
162
+
163
+ # All retries exhausted
164
+ if last_exception:
165
+ raise last_exception
166
+ else:
167
+ # This shouldn't happen, but just in case
168
+ raise TransportError("Max retries exceeded")
169
+
170
+
171
+ @define
172
+ class MetricsMiddleware(Middleware):
173
+ """Middleware for collecting transport metrics using foundation.metrics."""
174
+
175
+ # Create metrics instances
176
+ _request_counter = counter(
177
+ "transport_requests_total",
178
+ description="Total number of transport requests",
179
+ unit="requests"
180
+ )
181
+ _request_duration = histogram(
182
+ "transport_request_duration_seconds",
183
+ description="Duration of transport requests",
184
+ unit="seconds"
185
+ )
186
+ _error_counter = counter(
187
+ "transport_errors_total",
188
+ description="Total number of transport errors",
189
+ unit="errors"
190
+ )
191
+
192
+ async def process_request(self, request: Request) -> Request:
193
+ """Record request start time."""
194
+ request.metadata["start_time"] = time.perf_counter()
195
+ return request
196
+
197
+ async def process_response(self, response: Response) -> Response:
198
+ """Record response metrics."""
199
+ if response.request and "start_time" in response.request.metadata:
200
+ start_time = response.request.metadata["start_time"]
201
+ duration = time.perf_counter() - start_time
202
+
203
+ method = response.request.method
204
+ status_class = f"{response.status // 100}xx"
205
+
206
+ # Record metrics with labels
207
+ self._request_counter.inc(1,
208
+ method=method,
209
+ status_code=str(response.status),
210
+ status_class=status_class
211
+ )
212
+
213
+ self._request_duration.observe(duration,
214
+ method=method,
215
+ status_class=status_class
216
+ )
217
+
218
+ return response
219
+
220
+ async def process_error(self, error: Exception, request: Request) -> Exception:
221
+ """Record error metrics."""
222
+ method = request.method
223
+ error_type = error.__class__.__name__
224
+
225
+ self._error_counter.inc(1,
226
+ method=method,
227
+ error_type=error_type
228
+ )
229
+
230
+ return error
231
+
232
+
233
+ @define
234
+ class MiddlewarePipeline:
235
+ """Pipeline for executing middleware in order."""
236
+
237
+ middleware: list[Middleware] = field(factory=list)
238
+
239
+ def add(self, middleware: Middleware) -> None:
240
+ """Add middleware to the pipeline."""
241
+ self.middleware.append(middleware)
242
+ log.trace(f"Added middleware: {middleware.__class__.__name__}")
243
+
244
+ def remove(self, middleware_class: type[Middleware]) -> bool:
245
+ """Remove middleware by class type."""
246
+ for i, mw in enumerate(self.middleware):
247
+ if isinstance(mw, middleware_class):
248
+ del self.middleware[i]
249
+ log.trace(f"Removed middleware: {middleware_class.__name__}")
250
+ return True
251
+ return False
252
+
253
+ async def process_request(self, request: Request) -> Request:
254
+ """Process request through all middleware."""
255
+ for mw in self.middleware:
256
+ request = await mw.process_request(request)
257
+ return request
258
+
259
+ async def process_response(self, response: Response) -> Response:
260
+ """Process response through all middleware (in reverse order)."""
261
+ for mw in reversed(self.middleware):
262
+ response = await mw.process_response(response)
263
+ return response
264
+
265
+ async def process_error(self, error: Exception, request: Request) -> Exception:
266
+ """Process error through all middleware."""
267
+ for mw in self.middleware:
268
+ error = await mw.process_error(error, request)
269
+ return error
270
+
271
+
272
+ def register_middleware(
273
+ name: str,
274
+ middleware_class: type[Middleware],
275
+ category: str = "transport.middleware",
276
+ **metadata
277
+ ) -> None:
278
+ """Register middleware in the Hub."""
279
+ registry = get_component_registry()
280
+
281
+ registry.register(
282
+ name=name,
283
+ value=middleware_class,
284
+ dimension=category,
285
+ metadata={
286
+ "category": category,
287
+ "priority": metadata.get("priority", 100),
288
+ "class_name": middleware_class.__name__,
289
+ **metadata
290
+ },
291
+ replace=True,
292
+ )
293
+
294
+ log.debug(f"Registered middleware {middleware_class.__name__} as '{name}'")
295
+
296
+
297
+ def get_middleware_by_category(category: str = "transport.middleware") -> list[type[Middleware]]:
298
+ """Get all middleware for a category, sorted by priority."""
299
+ registry = get_component_registry()
300
+ middleware = []
301
+
302
+ for entry in registry:
303
+ if entry.dimension == category:
304
+ priority = entry.metadata.get("priority", 100)
305
+ middleware.append((entry.value, priority))
306
+
307
+ # Sort by priority (lower numbers = higher priority)
308
+ middleware.sort(key=lambda x: x[1])
309
+ return [mw[0] for mw in middleware]
310
+
311
+
312
+ def create_default_pipeline() -> MiddlewarePipeline:
313
+ """Create pipeline with default middleware."""
314
+ pipeline = MiddlewarePipeline()
315
+
316
+ # Add built-in middleware
317
+ pipeline.add(LoggingMiddleware())
318
+ pipeline.add(MetricsMiddleware())
319
+
320
+ return pipeline
321
+
322
+
323
+ # Auto-register built-in middleware
324
+ def _register_builtin_middleware():
325
+ """Register built-in middleware with the Hub."""
326
+ try:
327
+ register_middleware(
328
+ "logging",
329
+ LoggingMiddleware,
330
+ description="Built-in request/response logging",
331
+ priority=10,
332
+ )
333
+
334
+ register_middleware(
335
+ "retry",
336
+ RetryMiddleware,
337
+ description="Automatic retry with exponential backoff",
338
+ priority=20,
339
+ )
340
+
341
+ register_middleware(
342
+ "metrics",
343
+ MetricsMiddleware,
344
+ description="Request/response metrics collection",
345
+ priority=30,
346
+ )
347
+
348
+ except ImportError:
349
+ # Registry not available yet
350
+ pass
351
+
352
+
353
+ # Register when module is imported
354
+ _register_builtin_middleware()
355
+
356
+
357
+ __all__ = [
358
+ "Middleware",
359
+ "LoggingMiddleware",
360
+ "RetryMiddleware",
361
+ "MetricsMiddleware",
362
+ "MiddlewarePipeline",
363
+ "register_middleware",
364
+ "get_middleware_by_category",
365
+ "create_default_pipeline",
366
+ ]
@@ -0,0 +1,167 @@
1
+ """
2
+ Transport registration and discovery using Foundation Hub.
3
+ """
4
+
5
+ from typing import Any
6
+
7
+ from provide.foundation.hub import get_component_registry
8
+ from provide.foundation.hub.components import ComponentCategory
9
+ from provide.foundation.logger import get_logger
10
+ from provide.foundation.transport.base import Transport
11
+ from provide.foundation.transport.errors import TransportNotFoundError
12
+ from provide.foundation.transport.types import TransportType
13
+
14
+ log = get_logger(__name__)
15
+
16
+
17
+ def register_transport(
18
+ transport_type: TransportType,
19
+ transport_class: type[Transport],
20
+ schemes: list[str] | None = None,
21
+ **metadata
22
+ ) -> None:
23
+ """
24
+ Register a transport implementation in the Hub.
25
+
26
+ Args:
27
+ transport_type: The primary transport type
28
+ transport_class: Transport implementation class
29
+ schemes: List of URI schemes this transport handles
30
+ **metadata: Additional metadata for the transport
31
+ """
32
+ registry = get_component_registry()
33
+
34
+ # Default schemes to just the transport type
35
+ if schemes is None:
36
+ schemes = [transport_type.value]
37
+
38
+ registry.register(
39
+ name=transport_type.value,
40
+ value=transport_class,
41
+ dimension=ComponentCategory.TRANSPORT.value,
42
+ metadata={
43
+ "transport_type": transport_type,
44
+ "schemes": schemes,
45
+ "class_name": transport_class.__name__,
46
+ **metadata
47
+ },
48
+ replace=True, # Allow re-registration
49
+ )
50
+
51
+ log.debug(f"Registered transport {transport_class.__name__} for schemes: {schemes}")
52
+
53
+
54
+ def get_transport_for_scheme(scheme: str) -> type[Transport]:
55
+ """
56
+ Get transport class for a URI scheme.
57
+
58
+ Args:
59
+ scheme: URI scheme (e.g., 'http', 'https', 'ws')
60
+
61
+ Returns:
62
+ Transport class that handles the scheme
63
+
64
+ Raises:
65
+ TransportNotFoundError: If no transport is registered for the scheme
66
+ """
67
+ registry = get_component_registry()
68
+
69
+ # Search through registered transports
70
+ for entry in registry:
71
+ if entry.dimension == ComponentCategory.TRANSPORT.value:
72
+ schemes = entry.metadata.get("schemes", [])
73
+ if scheme.lower() in schemes:
74
+ log.trace(f"Found transport {entry.value.__name__} for scheme '{scheme}'")
75
+ return entry.value
76
+
77
+ raise TransportNotFoundError(
78
+ f"No transport registered for scheme: {scheme}",
79
+ scheme=scheme,
80
+ )
81
+
82
+
83
+ def get_transport(uri: str) -> Transport:
84
+ """
85
+ Get transport instance for a URI.
86
+
87
+ Args:
88
+ uri: Full URI to get transport for
89
+
90
+ Returns:
91
+ Transport instance ready to use
92
+
93
+ Raises:
94
+ TransportNotFoundError: If no transport supports the URI scheme
95
+ """
96
+ scheme = uri.split("://")[0].lower()
97
+ transport_class = get_transport_for_scheme(scheme)
98
+ return transport_class()
99
+
100
+
101
+ def list_registered_transports() -> dict[str, dict[str, Any]]:
102
+ """
103
+ List all registered transports.
104
+
105
+ Returns:
106
+ Dictionary mapping transport names to their info
107
+ """
108
+ registry = get_component_registry()
109
+ transports = {}
110
+
111
+ for entry in registry:
112
+ if entry.dimension == ComponentCategory.TRANSPORT.value:
113
+ transports[entry.name] = {
114
+ "class": entry.value,
115
+ "schemes": entry.metadata.get("schemes", []),
116
+ "transport_type": entry.metadata.get("transport_type"),
117
+ "metadata": entry.metadata,
118
+ }
119
+
120
+ return transports
121
+
122
+
123
+ def get_transport_info(scheme_or_name: str) -> dict[str, Any] | None:
124
+ """
125
+ Get detailed information about a transport.
126
+
127
+ Args:
128
+ scheme_or_name: URI scheme or transport name
129
+
130
+ Returns:
131
+ Transport information or None if not found
132
+ """
133
+ registry = get_component_registry()
134
+
135
+ for entry in registry:
136
+ if entry.dimension == ComponentCategory.TRANSPORT.value:
137
+ # Check if it matches by name
138
+ if entry.name == scheme_or_name:
139
+ return {
140
+ "name": entry.name,
141
+ "class": entry.value,
142
+ "schemes": entry.metadata.get("schemes", []),
143
+ "transport_type": entry.metadata.get("transport_type"),
144
+ "metadata": entry.metadata,
145
+ }
146
+
147
+ # Check if it matches by scheme
148
+ schemes = entry.metadata.get("schemes", [])
149
+ if scheme_or_name.lower() in schemes:
150
+ return {
151
+ "name": entry.name,
152
+ "class": entry.value,
153
+ "schemes": schemes,
154
+ "transport_type": entry.metadata.get("transport_type"),
155
+ "metadata": entry.metadata,
156
+ }
157
+
158
+ return None
159
+
160
+
161
+ __all__ = [
162
+ "register_transport",
163
+ "get_transport_for_scheme",
164
+ "get_transport",
165
+ "list_registered_transports",
166
+ "get_transport_info",
167
+ ]
@@ -0,0 +1,45 @@
1
+ """
2
+ Transport type definitions and enums.
3
+ """
4
+
5
+ from enum import Enum
6
+ from typing import Any, TypeAlias
7
+
8
+ # Type aliases
9
+ Headers: TypeAlias = dict[str, str]
10
+ Params: TypeAlias = dict[str, Any]
11
+ Data: TypeAlias = dict[str, Any] | bytes | str | None
12
+
13
+
14
+ class TransportType(str, Enum):
15
+ """Supported transport types."""
16
+
17
+ HTTP = "http"
18
+ HTTPS = "https"
19
+ WS = "ws"
20
+ WSS = "wss"
21
+ GRPC = "grpc"
22
+ GRAPHQL = "graphql"
23
+ AMQP = "amqp"
24
+ MQTT = "mqtt"
25
+
26
+
27
+ class HTTPMethod(str, Enum):
28
+ """HTTP methods."""
29
+
30
+ GET = "GET"
31
+ POST = "POST"
32
+ PUT = "PUT"
33
+ PATCH = "PATCH"
34
+ DELETE = "DELETE"
35
+ HEAD = "HEAD"
36
+ OPTIONS = "OPTIONS"
37
+
38
+
39
+ __all__ = [
40
+ "Headers",
41
+ "Params",
42
+ "Data",
43
+ "TransportType",
44
+ "HTTPMethod",
45
+ ]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: provide-foundation
3
- Version: 0.0.0.dev0
3
+ Version: 0.0.0.dev1
4
4
  Summary: Foundation Telemetry: An opinionated, developer-friendly telemetry wrapper for Python.
5
5
  Author-email: Tim Perkins <code@tim.life>
6
6
  Maintainer-email: "provide.io" <code@provide.io>
@@ -29,13 +29,15 @@ Provides-Extra: cli
29
29
  Requires-Dist: click>=8.1.7; extra == "cli"
30
30
  Provides-Extra: crypto
31
31
  Requires-Dist: cryptography>=45.0.7; extra == "crypto"
32
+ Provides-Extra: transport
33
+ Requires-Dist: httpx>=0.27.0; extra == "transport"
32
34
  Provides-Extra: opentelemetry
33
35
  Requires-Dist: opentelemetry-api>=1.22.0; extra == "opentelemetry"
34
36
  Requires-Dist: opentelemetry-sdk>=1.22.0; extra == "opentelemetry"
35
37
  Requires-Dist: opentelemetry-exporter-otlp-proto-grpc>=1.22.0; extra == "opentelemetry"
36
38
  Requires-Dist: opentelemetry-exporter-otlp-proto-http>=1.22.0; extra == "opentelemetry"
37
39
  Provides-Extra: all
38
- Requires-Dist: provide-foundation[cli,crypto,opentelemetry]; extra == "all"
40
+ Requires-Dist: provide-foundation[cli,crypto,opentelemetry,transport]; extra == "all"
39
41
  Dynamic: license-file
40
42
 
41
43
  # provide.foundation
@@ -439,31 +441,6 @@ Complete working examples are available in the [examples/](examples/) directory:
439
441
 
440
442
  ---
441
443
 
442
- ## Performance
443
-
444
- - **Logging**: 14,000+ messages/second with emoji processing and structured logging
445
- - **Configuration**: Lazy loading with multi-source caching for optimal performance
446
- - **File Operations**: Atomic writes with format detection prevent corruption
447
- - **Process Management**: Efficient streaming with async support and backpressure handling
448
- - **Cryptography**: Hardware-accelerated operations with secure algorithm defaults
449
- - **Platform Detection**: Cached system information for minimal overhead
450
-
451
- ---
452
-
453
- ## Contributing
454
-
455
- We welcome contributions! Please see:
456
- - [DEVELOPMENT.md](DEVELOPMENT.md) - Development setup and guidelines
457
- - [GitHub Issues](https://github.com/provide-io/provide-foundation/issues) - Bug reports and feature requests
458
-
459
- ---
460
-
461
- ## License
462
-
463
- MIT License - see [LICENSE](LICENSE) file for details.
464
-
465
- ---
466
-
467
444
  <p align="center">
468
- Built by <a href="https://provide.io">Provide</a>
445
+ Built by <a href="https://provide.io">provide.io</a>
469
446
  </p>