provide-foundation 0.0.0.dev0__py3-none-any.whl → 0.0.0.dev2__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 (161) hide show
  1. provide/foundation/__init__.py +41 -23
  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 +334 -0
  7. provide/foundation/archive/tar.py +164 -0
  8. provide/foundation/archive/zip.py +203 -0
  9. provide/foundation/cli/__init__.py +2 -2
  10. provide/foundation/cli/commands/deps.py +13 -7
  11. provide/foundation/cli/commands/logs/__init__.py +1 -1
  12. provide/foundation/cli/commands/logs/query.py +1 -1
  13. provide/foundation/cli/commands/logs/send.py +1 -1
  14. provide/foundation/cli/commands/logs/tail.py +1 -1
  15. provide/foundation/cli/decorators.py +11 -10
  16. provide/foundation/cli/main.py +1 -1
  17. provide/foundation/cli/testing.py +2 -35
  18. provide/foundation/cli/utils.py +21 -17
  19. provide/foundation/config/__init__.py +35 -2
  20. provide/foundation/config/base.py +2 -2
  21. provide/foundation/config/converters.py +479 -0
  22. provide/foundation/config/defaults.py +67 -0
  23. provide/foundation/config/env.py +4 -19
  24. provide/foundation/config/loader.py +9 -3
  25. provide/foundation/config/sync.py +19 -4
  26. provide/foundation/console/input.py +5 -5
  27. provide/foundation/console/output.py +35 -13
  28. provide/foundation/context/__init__.py +8 -4
  29. provide/foundation/context/core.py +85 -109
  30. provide/foundation/core.py +1 -2
  31. provide/foundation/crypto/__init__.py +2 -0
  32. provide/foundation/crypto/certificates/__init__.py +34 -0
  33. provide/foundation/crypto/certificates/base.py +173 -0
  34. provide/foundation/crypto/certificates/certificate.py +290 -0
  35. provide/foundation/crypto/certificates/factory.py +213 -0
  36. provide/foundation/crypto/certificates/generator.py +138 -0
  37. provide/foundation/crypto/certificates/loader.py +130 -0
  38. provide/foundation/crypto/certificates/operations.py +198 -0
  39. provide/foundation/crypto/certificates/trust.py +107 -0
  40. provide/foundation/errors/__init__.py +2 -3
  41. provide/foundation/errors/decorators.py +0 -231
  42. provide/foundation/errors/types.py +0 -97
  43. provide/foundation/eventsets/__init__.py +0 -0
  44. provide/foundation/eventsets/display.py +84 -0
  45. provide/foundation/eventsets/registry.py +160 -0
  46. provide/foundation/eventsets/resolver.py +192 -0
  47. provide/foundation/eventsets/sets/das.py +128 -0
  48. provide/foundation/eventsets/sets/database.py +125 -0
  49. provide/foundation/eventsets/sets/http.py +153 -0
  50. provide/foundation/eventsets/sets/llm.py +139 -0
  51. provide/foundation/eventsets/sets/task_queue.py +107 -0
  52. provide/foundation/eventsets/types.py +70 -0
  53. provide/foundation/file/directory.py +13 -22
  54. provide/foundation/file/lock.py +3 -1
  55. provide/foundation/hub/components.py +77 -515
  56. provide/foundation/hub/config.py +151 -0
  57. provide/foundation/hub/discovery.py +62 -0
  58. provide/foundation/hub/handlers.py +81 -0
  59. provide/foundation/hub/lifecycle.py +194 -0
  60. provide/foundation/hub/manager.py +4 -4
  61. provide/foundation/hub/processors.py +44 -0
  62. provide/foundation/integrations/__init__.py +11 -0
  63. provide/foundation/{observability → integrations}/openobserve/__init__.py +10 -7
  64. provide/foundation/{observability → integrations}/openobserve/auth.py +1 -1
  65. provide/foundation/{observability → integrations}/openobserve/client.py +12 -12
  66. provide/foundation/{observability → integrations}/openobserve/commands.py +3 -3
  67. provide/foundation/integrations/openobserve/config.py +37 -0
  68. provide/foundation/{observability → integrations}/openobserve/formatters.py +1 -1
  69. provide/foundation/{observability → integrations}/openobserve/otlp.py +1 -1
  70. provide/foundation/{observability → integrations}/openobserve/search.py +2 -2
  71. provide/foundation/{observability → integrations}/openobserve/streaming.py +4 -4
  72. provide/foundation/logger/__init__.py +3 -10
  73. provide/foundation/logger/config/logging.py +68 -298
  74. provide/foundation/logger/config/telemetry.py +41 -121
  75. provide/foundation/logger/core.py +0 -2
  76. provide/foundation/logger/custom_processors.py +1 -0
  77. provide/foundation/logger/factories.py +11 -2
  78. provide/foundation/logger/processors/main.py +20 -84
  79. provide/foundation/logger/setup/__init__.py +5 -1
  80. provide/foundation/logger/setup/coordinator.py +76 -24
  81. provide/foundation/logger/setup/processors.py +2 -9
  82. provide/foundation/logger/trace.py +27 -0
  83. provide/foundation/metrics/otel.py +10 -10
  84. provide/foundation/observability/__init__.py +2 -2
  85. provide/foundation/process/__init__.py +9 -0
  86. provide/foundation/process/exit.py +47 -0
  87. provide/foundation/process/lifecycle.py +115 -59
  88. provide/foundation/resilience/__init__.py +35 -0
  89. provide/foundation/resilience/circuit.py +164 -0
  90. provide/foundation/resilience/decorators.py +220 -0
  91. provide/foundation/resilience/fallback.py +193 -0
  92. provide/foundation/resilience/retry.py +325 -0
  93. provide/foundation/streams/config.py +79 -0
  94. provide/foundation/streams/console.py +7 -8
  95. provide/foundation/streams/core.py +6 -3
  96. provide/foundation/streams/file.py +12 -2
  97. provide/foundation/testing/__init__.py +84 -2
  98. provide/foundation/testing/archive/__init__.py +24 -0
  99. provide/foundation/testing/archive/fixtures.py +217 -0
  100. provide/foundation/testing/cli.py +30 -17
  101. provide/foundation/testing/common/__init__.py +32 -0
  102. provide/foundation/testing/common/fixtures.py +236 -0
  103. provide/foundation/testing/file/__init__.py +40 -0
  104. provide/foundation/testing/file/content_fixtures.py +316 -0
  105. provide/foundation/testing/file/directory_fixtures.py +107 -0
  106. provide/foundation/testing/file/fixtures.py +52 -0
  107. provide/foundation/testing/file/special_fixtures.py +153 -0
  108. provide/foundation/testing/logger.py +117 -11
  109. provide/foundation/testing/mocking/__init__.py +46 -0
  110. provide/foundation/testing/mocking/fixtures.py +331 -0
  111. provide/foundation/testing/process/__init__.py +48 -0
  112. provide/foundation/testing/process/async_fixtures.py +405 -0
  113. provide/foundation/testing/process/fixtures.py +56 -0
  114. provide/foundation/testing/process/subprocess_fixtures.py +209 -0
  115. provide/foundation/testing/threading/__init__.py +38 -0
  116. provide/foundation/testing/threading/basic_fixtures.py +101 -0
  117. provide/foundation/testing/threading/data_fixtures.py +99 -0
  118. provide/foundation/testing/threading/execution_fixtures.py +263 -0
  119. provide/foundation/testing/threading/fixtures.py +54 -0
  120. provide/foundation/testing/threading/sync_fixtures.py +97 -0
  121. provide/foundation/testing/time/__init__.py +32 -0
  122. provide/foundation/testing/time/fixtures.py +409 -0
  123. provide/foundation/testing/transport/__init__.py +30 -0
  124. provide/foundation/testing/transport/fixtures.py +280 -0
  125. provide/foundation/tools/__init__.py +58 -0
  126. provide/foundation/tools/base.py +348 -0
  127. provide/foundation/tools/cache.py +268 -0
  128. provide/foundation/tools/downloader.py +224 -0
  129. provide/foundation/tools/installer.py +254 -0
  130. provide/foundation/tools/registry.py +223 -0
  131. provide/foundation/tools/resolver.py +321 -0
  132. provide/foundation/tools/verifier.py +186 -0
  133. provide/foundation/tracer/otel.py +7 -11
  134. provide/foundation/tracer/spans.py +2 -2
  135. provide/foundation/transport/__init__.py +155 -0
  136. provide/foundation/transport/base.py +171 -0
  137. provide/foundation/transport/client.py +266 -0
  138. provide/foundation/transport/config.py +140 -0
  139. provide/foundation/transport/errors.py +79 -0
  140. provide/foundation/transport/http.py +232 -0
  141. provide/foundation/transport/middleware.py +360 -0
  142. provide/foundation/transport/registry.py +167 -0
  143. provide/foundation/transport/types.py +45 -0
  144. provide/foundation/utils/deps.py +14 -12
  145. provide/foundation/utils/parsing.py +49 -4
  146. {provide_foundation-0.0.0.dev0.dist-info → provide_foundation-0.0.0.dev2.dist-info}/METADATA +5 -28
  147. provide_foundation-0.0.0.dev2.dist-info/RECORD +225 -0
  148. provide/foundation/cli/commands/logs/generate_old.py +0 -569
  149. provide/foundation/crypto/certificates.py +0 -896
  150. provide/foundation/logger/emoji/__init__.py +0 -44
  151. provide/foundation/logger/emoji/matrix.py +0 -209
  152. provide/foundation/logger/emoji/sets.py +0 -458
  153. provide/foundation/logger/emoji/types.py +0 -56
  154. provide/foundation/logger/setup/emoji_resolver.py +0 -64
  155. provide_foundation-0.0.0.dev0.dist-info/RECORD +0 -149
  156. /provide/foundation/{observability → integrations}/openobserve/exceptions.py +0 -0
  157. /provide/foundation/{observability → integrations}/openobserve/models.py +0 -0
  158. {provide_foundation-0.0.0.dev0.dist-info → provide_foundation-0.0.0.dev2.dist-info}/WHEEL +0 -0
  159. {provide_foundation-0.0.0.dev0.dist-info → provide_foundation-0.0.0.dev2.dist-info}/entry_points.txt +0 -0
  160. {provide_foundation-0.0.0.dev0.dist-info → provide_foundation-0.0.0.dev2.dist-info}/licenses/LICENSE +0 -0
  161. {provide_foundation-0.0.0.dev0.dist-info → provide_foundation-0.0.0.dev2.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,151 @@
1
+ """
2
+ Hub configuration management utilities.
3
+
4
+ Provides functions for resolving configuration values from registered sources,
5
+ loading configurations, and managing the configuration chain.
6
+ """
7
+
8
+ import asyncio
9
+ import inspect
10
+ from typing import Any, TypeVar
11
+
12
+ from provide.foundation.errors.decorators import with_error_handling
13
+ from provide.foundation.hub.registry import RegistryEntry
14
+ from provide.foundation.logger import get_logger
15
+
16
+ T = TypeVar("T")
17
+
18
+ log = get_logger(__name__)
19
+
20
+
21
+ def _get_registry_and_lock():
22
+ """Get registry and lock from components module."""
23
+ from provide.foundation.hub.components import get_component_registry, _registry_lock, ComponentCategory
24
+ return get_component_registry(), _registry_lock, ComponentCategory
25
+
26
+
27
+ @with_error_handling(fallback=None, suppress=(Exception,))
28
+ def resolve_config_value(key: str) -> Any:
29
+ """Resolve configuration value using priority-ordered sources."""
30
+ registry, registry_lock, ComponentCategory = _get_registry_and_lock()
31
+
32
+ with registry_lock:
33
+ # Get all config sources
34
+ all_entries = list(registry)
35
+ config_sources = [
36
+ entry
37
+ for entry in all_entries
38
+ if entry.dimension == ComponentCategory.CONFIG_SOURCE.value
39
+ ]
40
+
41
+ # Sort by priority (highest first)
42
+ config_sources.sort(key=lambda e: e.metadata.get("priority", 0), reverse=True)
43
+
44
+ # Try each source
45
+ for entry in config_sources:
46
+ source = entry.value
47
+ if hasattr(source, "get_value"):
48
+ # Try to get value, continue on error
49
+ try:
50
+ value = source.get_value(key)
51
+ if value is not None:
52
+ return value
53
+ except Exception:
54
+ continue
55
+
56
+ return None
57
+
58
+
59
+ def get_config_chain() -> list[RegistryEntry]:
60
+ """Get configuration sources ordered by priority."""
61
+ registry, registry_lock, ComponentCategory = _get_registry_and_lock()
62
+
63
+ with registry_lock:
64
+ # Get all config sources
65
+ all_entries = list(registry)
66
+ config_sources = [
67
+ entry
68
+ for entry in all_entries
69
+ if entry.dimension == ComponentCategory.CONFIG_SOURCE.value
70
+ ]
71
+
72
+ # Sort by priority (highest first)
73
+ config_sources.sort(key=lambda e: e.metadata.get("priority", 0), reverse=True)
74
+ return config_sources
75
+
76
+
77
+ @with_error_handling(
78
+ fallback={},
79
+ context_provider=lambda: {"function": "load_all_configs"}
80
+ )
81
+ async def load_all_configs() -> dict[str, Any]:
82
+ """Load configurations from all registered sources."""
83
+ configs = {}
84
+ chain = get_config_chain()
85
+
86
+ for entry in chain:
87
+ source = entry.value
88
+ if hasattr(source, "load_config"):
89
+ try:
90
+ if inspect.iscoroutinefunction(source.load_config):
91
+ source_config = await source.load_config()
92
+ else:
93
+ source_config = source.load_config()
94
+
95
+ if source_config:
96
+ configs.update(source_config)
97
+ except Exception as e:
98
+ log.warning(
99
+ "Config source failed to load", source=entry.name, error=str(e)
100
+ )
101
+
102
+ return configs
103
+
104
+
105
+ def load_config_from_registry(config_class: type[T]) -> T:
106
+ """
107
+ Load configuration from registry sources.
108
+
109
+ Args:
110
+ config_class: Configuration class to instantiate
111
+
112
+ Returns:
113
+ Configuration instance loaded from registry sources
114
+ """
115
+ registry, registry_lock, ComponentCategory = _get_registry_and_lock()
116
+
117
+ with registry_lock:
118
+ # Get configuration data from registry
119
+ config_data = {}
120
+
121
+ # Load from all config sources
122
+ chain = get_config_chain()
123
+ for entry in chain:
124
+ source = entry.value
125
+ if hasattr(source, "load_config"):
126
+ try:
127
+ # Skip async sources in sync context
128
+ if inspect.iscoroutinefunction(source.load_config):
129
+ log.debug("Skipping async config source in sync context", source=entry.name)
130
+ continue
131
+
132
+ source_data = source.load_config()
133
+ if source_data:
134
+ config_data.update(source_data)
135
+ except Exception as e:
136
+ log.warning(
137
+ "Failed to load config from source",
138
+ source=entry.name,
139
+ error=str(e)
140
+ )
141
+
142
+ # Create config instance
143
+ return config_class.from_dict(config_data)
144
+
145
+
146
+ __all__ = [
147
+ "resolve_config_value",
148
+ "get_config_chain",
149
+ "load_all_configs",
150
+ "load_config_from_registry",
151
+ ]
@@ -0,0 +1,62 @@
1
+ """
2
+ Hub component discovery and dependency resolution utilities.
3
+
4
+ Provides functions for discovering components and resolving their dependencies
5
+ in the Hub registry system.
6
+ """
7
+
8
+ from typing import Any
9
+
10
+ from provide.foundation.hub.registry import Registry
11
+
12
+
13
+ def _get_registry_and_lock():
14
+ """Get registry and lock from components module."""
15
+ from provide.foundation.hub.components import get_component_registry, _registry_lock
16
+ return get_component_registry(), _registry_lock
17
+
18
+
19
+ def resolve_component_dependencies(name: str, dimension: str) -> dict[str, Any]:
20
+ """Resolve component dependencies recursively."""
21
+ registry, registry_lock = _get_registry_and_lock()
22
+
23
+ with registry_lock:
24
+ entry = registry.get_entry(name, dimension)
25
+
26
+ if not entry:
27
+ return {}
28
+
29
+ dependencies = {}
30
+ dep_names = entry.metadata.get("dependencies", [])
31
+
32
+ for dep_name in dep_names:
33
+ # Try same dimension first
34
+ dep_component = registry.get(dep_name, dimension)
35
+ if dep_component is not None:
36
+ dependencies[dep_name] = dep_component
37
+ else:
38
+ # Search across dimensions
39
+ dep_component = registry.get(dep_name)
40
+ if dep_component is not None:
41
+ dependencies[dep_name] = dep_component
42
+
43
+ return dependencies
44
+
45
+
46
+ def discover_components(
47
+ group: str,
48
+ dimension: str = "component",
49
+ registry: Registry | None = None,
50
+ ) -> dict[str, type[Any]]:
51
+ """
52
+ Discover and register components from entry points.
53
+
54
+ This is a stub for the TDD implementation.
55
+ """
56
+ return {}
57
+
58
+
59
+ __all__ = [
60
+ "resolve_component_dependencies",
61
+ "discover_components",
62
+ ]
@@ -0,0 +1,81 @@
1
+ """
2
+ Hub error handler management utilities.
3
+
4
+ Provides functions for discovering and executing error handlers from the registry.
5
+ """
6
+
7
+ from typing import Any
8
+
9
+ from provide.foundation.errors.decorators import with_error_handling
10
+ from provide.foundation.hub.registry import RegistryEntry
11
+ from provide.foundation.logger import get_logger
12
+
13
+ log = get_logger(__name__)
14
+
15
+
16
+ def _get_registry_and_lock():
17
+ """Get registry and lock from components module."""
18
+ from provide.foundation.hub.components import get_component_registry, _registry_lock, ComponentCategory
19
+ return get_component_registry(), _registry_lock, ComponentCategory
20
+
21
+
22
+ def get_handlers_for_exception(exception: Exception) -> list[RegistryEntry]:
23
+ """Get error handlers that can handle the given exception type."""
24
+ registry, registry_lock, ComponentCategory = _get_registry_and_lock()
25
+
26
+ with registry_lock:
27
+ # Get all error handlers
28
+ all_entries = list(registry)
29
+ handlers = [
30
+ entry
31
+ for entry in all_entries
32
+ if entry.dimension == ComponentCategory.ERROR_HANDLER.value
33
+ ]
34
+
35
+ # Filter by exception type
36
+ exception_type_name = type(exception).__name__
37
+ matching_handlers = []
38
+
39
+ for entry in handlers:
40
+ exception_types = entry.metadata.get("exception_types", [])
41
+ if any(
42
+ exc_type in exception_type_name or exception_type_name in exc_type
43
+ for exc_type in exception_types
44
+ ):
45
+ matching_handlers.append(entry)
46
+
47
+ # Sort by priority (highest first)
48
+ matching_handlers.sort(
49
+ key=lambda e: e.metadata.get("priority", 0), reverse=True
50
+ )
51
+ return matching_handlers
52
+
53
+
54
+ @with_error_handling(
55
+ fallback=None,
56
+ context_provider=lambda: {"function": "execute_error_handlers", "module": "hub.handlers"}
57
+ )
58
+ def execute_error_handlers(
59
+ exception: Exception, context: dict[str, Any]
60
+ ) -> dict[str, Any] | None:
61
+ """Execute error handlers until one handles the exception."""
62
+ handlers = get_handlers_for_exception(exception)
63
+
64
+ for entry in handlers:
65
+ handler = entry.value
66
+ try:
67
+ result = handler(exception, context)
68
+ if result is not None:
69
+ return result
70
+ except Exception as handler_error:
71
+ log.error(
72
+ "Error handler failed", handler=entry.name, error=str(handler_error)
73
+ )
74
+
75
+ return None
76
+
77
+
78
+ __all__ = [
79
+ "get_handlers_for_exception",
80
+ "execute_error_handlers",
81
+ ]
@@ -0,0 +1,194 @@
1
+ """
2
+ Hub component lifecycle management utilities.
3
+
4
+ Provides functions for initializing, managing, and cleaning up components
5
+ registered in the Hub registry system.
6
+ """
7
+
8
+ import asyncio
9
+ import inspect
10
+ from typing import Any
11
+
12
+ from provide.foundation.logger import get_logger
13
+
14
+ log = get_logger(__name__)
15
+
16
+
17
+ def _get_registry_and_globals():
18
+ """Get registry, lock, and initialized components from components module."""
19
+ from provide.foundation.hub.components import (
20
+ get_component_registry,
21
+ _registry_lock,
22
+ _initialized_components
23
+ )
24
+ return get_component_registry(), _registry_lock, _initialized_components
25
+
26
+
27
+ def get_or_initialize_component(name: str, dimension: str) -> Any:
28
+ """Get component, initializing lazily if needed."""
29
+ registry, registry_lock, initialized_components = _get_registry_and_globals()
30
+
31
+ with registry_lock:
32
+ key = (name, dimension)
33
+
34
+ # Return already initialized component
35
+ if key in initialized_components:
36
+ return initialized_components[key]
37
+
38
+ entry = registry.get_entry(name, dimension)
39
+
40
+ if not entry:
41
+ return None
42
+
43
+ # If already initialized, return it
44
+ if entry.value is not None:
45
+ initialized_components[key] = entry.value
46
+ return entry.value
47
+
48
+ # Initialize lazily
49
+ if entry.metadata.get("lazy", False):
50
+ factory = entry.metadata.get("factory")
51
+ if factory:
52
+ try:
53
+ component = factory()
54
+ # Update registry with initialized component
55
+ registry.register(
56
+ name=name,
57
+ value=component,
58
+ dimension=dimension,
59
+ metadata=entry.metadata,
60
+ replace=True,
61
+ )
62
+ initialized_components[key] = component
63
+ return component
64
+ except Exception as e:
65
+ log.error(
66
+ "Component initialization failed",
67
+ component=name,
68
+ dimension=dimension,
69
+ error=str(e),
70
+ )
71
+
72
+ return entry.value
73
+
74
+
75
+ async def initialize_async_component(name: str, dimension: str) -> Any:
76
+ """Initialize component asynchronously."""
77
+ registry, registry_lock, initialized_components = _get_registry_and_globals()
78
+
79
+ with registry_lock:
80
+ key = (name, dimension)
81
+
82
+ # Return already initialized component
83
+ if key in initialized_components:
84
+ return initialized_components[key]
85
+
86
+ entry = registry.get_entry(name, dimension)
87
+
88
+ if not entry:
89
+ return None
90
+
91
+ # Initialize with async factory
92
+ if entry.metadata.get("async", False):
93
+ factory = entry.metadata.get("factory")
94
+ if factory:
95
+ try:
96
+ if inspect.iscoroutinefunction(factory):
97
+ component = await factory()
98
+ else:
99
+ component = factory()
100
+
101
+ # Update registry
102
+ registry.register(
103
+ name=name,
104
+ value=component,
105
+ dimension=dimension,
106
+ metadata=entry.metadata,
107
+ replace=True,
108
+ )
109
+ initialized_components[key] = component
110
+ return component
111
+ except Exception as e:
112
+ log.error(
113
+ "Async component initialization failed",
114
+ component=name,
115
+ dimension=dimension,
116
+ error=str(e),
117
+ )
118
+
119
+ return entry.value
120
+
121
+
122
+ def cleanup_all_components(dimension: str | None = None) -> None:
123
+ """Clean up all components in dimension."""
124
+ registry, registry_lock, _ = _get_registry_and_globals()
125
+
126
+ with registry_lock:
127
+ if dimension:
128
+ entries = [entry for entry in registry if entry.dimension == dimension]
129
+ else:
130
+ entries = list(registry)
131
+
132
+ for entry in entries:
133
+ if entry.metadata.get("supports_cleanup", False):
134
+ component = entry.value
135
+ if hasattr(component, "cleanup"):
136
+ try:
137
+ cleanup_func = component.cleanup
138
+ if inspect.iscoroutinefunction(cleanup_func):
139
+ # Run async cleanup
140
+ loop = None
141
+ try:
142
+ loop = asyncio.get_event_loop()
143
+ if loop.is_running():
144
+ # Create task if loop is running
145
+ loop.create_task(cleanup_func())
146
+ else:
147
+ loop.run_until_complete(cleanup_func())
148
+ except RuntimeError:
149
+ # Create new loop if none exists
150
+ loop = asyncio.new_event_loop()
151
+ loop.run_until_complete(cleanup_func())
152
+ loop.close()
153
+ else:
154
+ cleanup_func()
155
+ except Exception as e:
156
+ log.error(
157
+ "Component cleanup failed",
158
+ component=entry.name,
159
+ dimension=entry.dimension,
160
+ error=str(e),
161
+ )
162
+
163
+
164
+ async def initialize_all_async_components() -> None:
165
+ """Initialize all async components in dependency order."""
166
+ registry, _, _ = _get_registry_and_globals()
167
+
168
+ # Get all async components
169
+ async_components = [
170
+ entry for entry in registry if entry.metadata.get("async", False)
171
+ ]
172
+
173
+ # Sort by priority for initialization order
174
+ async_components.sort(key=lambda e: e.metadata.get("priority", 0), reverse=True)
175
+
176
+ # Initialize each component
177
+ for entry in async_components:
178
+ try:
179
+ await initialize_async_component(entry.name, entry.dimension)
180
+ except Exception as e:
181
+ log.error(
182
+ "Failed to initialize async component",
183
+ component=entry.name,
184
+ dimension=entry.dimension,
185
+ error=str(e),
186
+ )
187
+
188
+
189
+ __all__ = [
190
+ "get_or_initialize_component",
191
+ "initialize_async_component",
192
+ "cleanup_all_components",
193
+ "initialize_all_async_components",
194
+ ]
@@ -19,7 +19,7 @@ except ImportError:
19
19
  click = None
20
20
  _HAS_CLICK = False
21
21
 
22
- from provide.foundation.context import Context
22
+ from provide.foundation.context import CLIContext
23
23
  from provide.foundation.errors.config import ValidationError
24
24
  from provide.foundation.errors.decorators import with_error_handling
25
25
  from provide.foundation.errors.resources import AlreadyExistsError
@@ -60,7 +60,7 @@ class Hub:
60
60
 
61
61
  def __init__(
62
62
  self,
63
- context: Context | None = None,
63
+ context: CLIContext | None = None,
64
64
  component_registry: Registry | None = None,
65
65
  command_registry: Registry | None = None,
66
66
  ) -> None:
@@ -68,11 +68,11 @@ class Hub:
68
68
  Initialize the hub.
69
69
 
70
70
  Args:
71
- context: Foundation context for configuration
71
+ context: Foundation CLIContext for configuration
72
72
  component_registry: Custom component registry
73
73
  command_registry: Custom command registry
74
74
  """
75
- self.context = context or Context()
75
+ self.context = context or CLIContext()
76
76
  self._component_registry = component_registry or get_component_registry()
77
77
  self._command_registry = command_registry or get_command_registry()
78
78
  self._cli_group: click.Group | None = None
@@ -0,0 +1,44 @@
1
+ """
2
+ Hub processor pipeline management utilities.
3
+
4
+ Provides functions for managing log processors and processing stages
5
+ in the Hub registry system.
6
+ """
7
+
8
+ from provide.foundation.hub.registry import RegistryEntry
9
+
10
+
11
+ def _get_registry_and_lock():
12
+ """Get registry and lock from components module."""
13
+ from provide.foundation.hub.components import get_component_registry, _registry_lock, ComponentCategory
14
+ return get_component_registry(), _registry_lock, ComponentCategory
15
+
16
+
17
+ def get_processor_pipeline() -> list[RegistryEntry]:
18
+ """Get log processors ordered by priority."""
19
+ registry, registry_lock, ComponentCategory = _get_registry_and_lock()
20
+
21
+ with registry_lock:
22
+ # Get all processors
23
+ all_entries = list(registry)
24
+ processors = [
25
+ entry
26
+ for entry in all_entries
27
+ if entry.dimension == ComponentCategory.PROCESSOR.value
28
+ ]
29
+
30
+ # Sort by priority (highest first)
31
+ processors.sort(key=lambda e: e.metadata.get("priority", 0), reverse=True)
32
+ return processors
33
+
34
+
35
+ def get_processors_for_stage(stage: str) -> list[RegistryEntry]:
36
+ """Get processors for a specific processing stage."""
37
+ pipeline = get_processor_pipeline()
38
+ return [entry for entry in pipeline if entry.metadata.get("stage") == stage]
39
+
40
+
41
+ __all__ = [
42
+ "get_processor_pipeline",
43
+ "get_processors_for_stage",
44
+ ]
@@ -0,0 +1,11 @@
1
+ """
2
+ Optional integrations for Foundation.
3
+
4
+ This module contains integrations with external services and tools
5
+ that are not part of the core foundation library.
6
+ """
7
+
8
+ __all__ = [
9
+ # Available integrations (import on demand)
10
+ # "openobserve",
11
+ ]
@@ -1,11 +1,12 @@
1
1
  """
2
2
  OpenObserve integration for Foundation.
3
3
 
4
- Provides log querying and streaming capabilities when OpenTelemetry is available.
4
+ Provides log querying and streaming capabilities as an optional integration.
5
5
  """
6
6
 
7
- from provide.foundation.observability.openobserve.client import OpenObserveClient
8
- from provide.foundation.observability.openobserve.exceptions import (
7
+ from provide.foundation.integrations.openobserve.client import OpenObserveClient
8
+ from provide.foundation.integrations.openobserve.config import OpenObserveConfig
9
+ from provide.foundation.integrations.openobserve.exceptions import (
9
10
  OpenObserveAuthenticationError,
10
11
  OpenObserveConfigError,
11
12
  OpenObserveConnectionError,
@@ -13,7 +14,7 @@ from provide.foundation.observability.openobserve.exceptions import (
13
14
  OpenObserveQueryError,
14
15
  OpenObserveStreamingError,
15
16
  )
16
- from provide.foundation.observability.openobserve.formatters import (
17
+ from provide.foundation.integrations.openobserve.formatters import (
17
18
  format_csv,
18
19
  format_json,
19
20
  format_log_line,
@@ -21,13 +22,13 @@ from provide.foundation.observability.openobserve.formatters import (
21
22
  format_summary,
22
23
  format_table,
23
24
  )
24
- from provide.foundation.observability.openobserve.models import (
25
+ from provide.foundation.integrations.openobserve.models import (
25
26
  SearchQuery,
26
27
  SearchResponse,
27
28
  StreamInfo,
28
29
  parse_relative_time,
29
30
  )
30
- from provide.foundation.observability.openobserve.search import (
31
+ from provide.foundation.integrations.openobserve.search import (
31
32
  aggregate_by_level,
32
33
  get_current_trace_logs,
33
34
  search_by_level,
@@ -36,13 +37,15 @@ from provide.foundation.observability.openobserve.search import (
36
37
  search_errors,
37
38
  search_logs,
38
39
  )
39
- from provide.foundation.observability.openobserve.streaming import (
40
+ from provide.foundation.integrations.openobserve.streaming import (
40
41
  stream_logs,
41
42
  stream_search_http2,
42
43
  tail_logs,
43
44
  )
44
45
 
45
46
  __all__ = [
47
+ # Configuration
48
+ "OpenObserveConfig",
46
49
  # Client
47
50
  "OpenObserveClient",
48
51
  # Search functions
@@ -4,7 +4,7 @@ Authentication handling for OpenObserve.
4
4
 
5
5
  import base64
6
6
 
7
- from provide.foundation.observability.openobserve.exceptions import (
7
+ from provide.foundation.integrations.openobserve.exceptions import (
8
8
  OpenObserveAuthenticationError,
9
9
  )
10
10