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,139 @@
1
+ """
2
+ Large Language Model (LLM) interaction event set for Foundation.
3
+ """
4
+
5
+ from provide.foundation.eventsets.types import EventSet, EventMapping, FieldMapping
6
+
7
+ EVENT_SET = EventSet(
8
+ name="llm",
9
+ description="LLM provider and interaction enrichment",
10
+ mappings=[
11
+ EventMapping(
12
+ name="llm_provider",
13
+ visual_markers={
14
+ "openai": "🤖",
15
+ "anthropic": "📚",
16
+ "google": "🇬",
17
+ "meta": "🦙",
18
+ "mistral": "🌬️",
19
+ "perplexity": "❓",
20
+ "cohere": "🔊",
21
+ "default": "💡",
22
+ },
23
+ metadata_fields={
24
+ "openai": {"llm.vendor": "openai", "llm.api": "openai"},
25
+ "anthropic": {"llm.vendor": "anthropic", "llm.api": "claude"},
26
+ "google": {"llm.vendor": "google", "llm.api": "gemini"},
27
+ "meta": {"llm.vendor": "meta", "llm.api": "llama"},
28
+ "mistral": {"llm.vendor": "mistral", "llm.api": "mistral"},
29
+ },
30
+ default_key="default"
31
+ ),
32
+ EventMapping(
33
+ name="llm_task",
34
+ visual_markers={
35
+ "generation": "✍️",
36
+ "completion": "✅",
37
+ "embedding": "🔗",
38
+ "chat": "💬",
39
+ "tool_use": "🛠️",
40
+ "summarization": "📜",
41
+ "translation": "🌐",
42
+ "classification": "🏷️",
43
+ "default": "⚡",
44
+ },
45
+ metadata_fields={
46
+ "generation": {"llm.type": "generative"},
47
+ "completion": {"llm.type": "completion"},
48
+ "embedding": {"llm.type": "embedding"},
49
+ "chat": {"llm.type": "conversational"},
50
+ "tool_use": {"llm.type": "function_calling"},
51
+ },
52
+ default_key="default"
53
+ ),
54
+ EventMapping(
55
+ name="llm_outcome",
56
+ visual_markers={
57
+ "success": "👍",
58
+ "error": "🔥",
59
+ "filtered_input": "🛡️👁️",
60
+ "filtered_output": "🛡️🗣️",
61
+ "rate_limit": "⏳",
62
+ "partial_success": "🤏",
63
+ "tool_call": "📞",
64
+ "default": "➡️",
65
+ },
66
+ metadata_fields={
67
+ "success": {"llm.success": True},
68
+ "error": {"llm.error": True},
69
+ "rate_limit": {"llm.rate_limited": True},
70
+ "filtered_input": {"llm.filtered": True, "llm.filter_type": "input"},
71
+ "filtered_output": {"llm.filtered": True, "llm.filter_type": "output"},
72
+ },
73
+ default_key="default"
74
+ ),
75
+ ],
76
+ field_mappings=[
77
+ FieldMapping(
78
+ log_key="llm.provider",
79
+ event_set_name="llm",
80
+ description="LLM provider name",
81
+ value_type="string"
82
+ ),
83
+ FieldMapping(
84
+ log_key="llm.task",
85
+ event_set_name="llm",
86
+ description="LLM task type",
87
+ value_type="string"
88
+ ),
89
+ FieldMapping(
90
+ log_key="llm.model",
91
+ event_set_name="llm",
92
+ description="Model identifier",
93
+ value_type="string"
94
+ ),
95
+ FieldMapping(
96
+ log_key="llm.outcome",
97
+ event_set_name="llm",
98
+ description="Operation outcome",
99
+ value_type="string"
100
+ ),
101
+ FieldMapping(
102
+ log_key="llm.input.tokens",
103
+ event_set_name="llm",
104
+ description="Input token count",
105
+ value_type="integer"
106
+ ),
107
+ FieldMapping(
108
+ log_key="llm.output.tokens",
109
+ event_set_name="llm",
110
+ description="Output token count",
111
+ value_type="integer"
112
+ ),
113
+ FieldMapping(
114
+ log_key="llm.tool.name",
115
+ event_set_name="llm",
116
+ description="Tool/function name",
117
+ value_type="string"
118
+ ),
119
+ FieldMapping(
120
+ log_key="llm.tool.call_id",
121
+ event_set_name="llm",
122
+ description="Tool call identifier",
123
+ value_type="string"
124
+ ),
125
+ FieldMapping(
126
+ log_key="duration_ms",
127
+ event_set_name="llm",
128
+ description="LLM operation duration",
129
+ value_type="integer"
130
+ ),
131
+ FieldMapping(
132
+ log_key="trace_id",
133
+ event_set_name="llm",
134
+ description="Distributed trace ID",
135
+ value_type="string"
136
+ ),
137
+ ],
138
+ priority=100 # High priority for LLM operations
139
+ )
@@ -0,0 +1,107 @@
1
+ """
2
+ Task queue and async job processing event set for Foundation.
3
+ """
4
+
5
+ from provide.foundation.eventsets.types import EventSet, EventMapping, FieldMapping
6
+
7
+ EVENT_SET = EventSet(
8
+ name="task_queue",
9
+ description="Asynchronous task queue operation enrichment",
10
+ mappings=[
11
+ EventMapping(
12
+ name="task_system",
13
+ visual_markers={
14
+ "celery": "🥕",
15
+ "rq": "🟥🇶",
16
+ "dramatiq": "🎭",
17
+ "kafka": "🌊",
18
+ "rabbitmq": "🐇",
19
+ "default": "📨",
20
+ },
21
+ metadata_fields={
22
+ "celery": {"task.broker": "celery"},
23
+ "rq": {"task.broker": "redis"},
24
+ "dramatiq": {"task.broker": "dramatiq"},
25
+ "kafka": {"task.broker": "kafka", "task.streaming": True},
26
+ "rabbitmq": {"task.broker": "amqp"},
27
+ },
28
+ default_key="default"
29
+ ),
30
+ EventMapping(
31
+ name="task_status",
32
+ visual_markers={
33
+ "submitted": "➡️📨",
34
+ "received": "📥",
35
+ "started": "▶️",
36
+ "progress": "🔄",
37
+ "retrying": "🔁",
38
+ "success": "✅🏁",
39
+ "failure": "❌🔥",
40
+ "revoked": "🚫",
41
+ "default": "❓",
42
+ },
43
+ metadata_fields={
44
+ "submitted": {"task.state": "pending"},
45
+ "received": {"task.state": "pending"},
46
+ "started": {"task.state": "active"},
47
+ "progress": {"task.state": "active"},
48
+ "retrying": {"task.state": "retry"},
49
+ "success": {"task.state": "completed", "task.success": True},
50
+ "failure": {"task.state": "failed", "task.success": False},
51
+ "revoked": {"task.state": "cancelled"},
52
+ },
53
+ default_key="default"
54
+ ),
55
+ ],
56
+ field_mappings=[
57
+ FieldMapping(
58
+ log_key="task.system",
59
+ event_set_name="task_queue",
60
+ description="Task queue system",
61
+ value_type="string"
62
+ ),
63
+ FieldMapping(
64
+ log_key="task.status",
65
+ event_set_name="task_queue",
66
+ description="Task execution status",
67
+ value_type="string"
68
+ ),
69
+ FieldMapping(
70
+ log_key="task.id",
71
+ event_set_name="task_queue",
72
+ description="Unique task identifier",
73
+ value_type="string"
74
+ ),
75
+ FieldMapping(
76
+ log_key="task.name",
77
+ event_set_name="task_queue",
78
+ description="Task or job name",
79
+ value_type="string"
80
+ ),
81
+ FieldMapping(
82
+ log_key="task.queue_name",
83
+ event_set_name="task_queue",
84
+ description="Queue name",
85
+ value_type="string"
86
+ ),
87
+ FieldMapping(
88
+ log_key="task.retries",
89
+ event_set_name="task_queue",
90
+ description="Retry attempt count",
91
+ value_type="integer"
92
+ ),
93
+ FieldMapping(
94
+ log_key="duration_ms",
95
+ event_set_name="task_queue",
96
+ description="Task execution duration",
97
+ value_type="integer"
98
+ ),
99
+ FieldMapping(
100
+ log_key="trace_id",
101
+ event_set_name="task_queue",
102
+ description="Distributed trace ID",
103
+ value_type="string"
104
+ ),
105
+ ],
106
+ priority=70
107
+ )
@@ -0,0 +1,70 @@
1
+ """
2
+ Event set type definitions for the Foundation event enrichment system.
3
+ """
4
+
5
+ from collections.abc import Callable
6
+ from typing import Any
7
+
8
+ from attrs import define, field
9
+
10
+
11
+ @define(frozen=True, slots=True)
12
+ class EventMapping:
13
+ """
14
+ Individual event enrichment mapping for a specific domain.
15
+
16
+ Attributes:
17
+ name: Unique identifier for this mapping
18
+ visual_markers: Mapping of values to visual indicators (e.g., emojis)
19
+ metadata_fields: Additional metadata to attach based on values
20
+ transformations: Value transformation functions
21
+ default_key: Key to use when no specific match is found
22
+ """
23
+
24
+ name: str
25
+ visual_markers: dict[str, str] = field(factory=lambda: {})
26
+ metadata_fields: dict[str, dict[str, Any]] = field(factory=lambda: {})
27
+ transformations: dict[str, Callable[[Any], Any]] = field(factory=lambda: {})
28
+ default_key: str = field(default="default")
29
+
30
+
31
+ @define(frozen=True, slots=True)
32
+ class FieldMapping:
33
+ """
34
+ Maps a log field to an event set for enrichment.
35
+
36
+ Attributes:
37
+ log_key: The field key in log events (e.g., "http.method", "llm.provider")
38
+ description: Human-readable description of this field
39
+ value_type: Expected type of the field value
40
+ event_set_name: Name of the EventSet to use for enrichment
41
+ default_override_key: Override the default key for this specific field
42
+ default_value: Default value to use if field is not present
43
+ """
44
+
45
+ log_key: str
46
+ description: str | None = field(default=None)
47
+ value_type: str | None = field(default=None)
48
+ event_set_name: str | None = field(default=None)
49
+ default_override_key: str | None = field(default=None)
50
+ default_value: Any | None = field(default=None)
51
+
52
+
53
+ @define(frozen=True, slots=True)
54
+ class EventSet:
55
+ """
56
+ Complete event enrichment domain definition.
57
+
58
+ Attributes:
59
+ name: Unique identifier for this event set
60
+ description: Human-readable description
61
+ mappings: List of EventMapping definitions
62
+ field_mappings: List of field-to-mapping associations
63
+ priority: Higher priority sets override lower ones
64
+ """
65
+
66
+ name: str
67
+ description: str | None = field(default=None)
68
+ mappings: list[EventMapping] = field(factory=lambda: [])
69
+ field_mappings: list[FieldMapping] = field(factory=lambda: [])
70
+ priority: int = field(default=0, converter=int)
@@ -6,6 +6,8 @@ from pathlib import Path
6
6
  import shutil
7
7
  import tempfile
8
8
 
9
+ from provide.foundation.errors.decorators import with_error_handling
10
+ from provide.foundation.errors.handlers import error_boundary
9
11
  from provide.foundation.logger import get_logger
10
12
 
11
13
  log = get_logger(__name__)
@@ -80,17 +82,12 @@ def temp_dir(
80
82
  yield temp_path
81
83
  finally:
82
84
  if cleanup and temp_path and temp_path.exists():
83
- try:
85
+ with error_boundary(Exception, reraise=False):
84
86
  shutil.rmtree(temp_path)
85
87
  log.debug("Cleaned up temp directory", path=str(temp_path))
86
- except Exception as e:
87
- log.warning(
88
- "Failed to cleanup temp directory",
89
- path=str(temp_path),
90
- error=str(e),
91
- )
92
88
 
93
89
 
90
+ @with_error_handling(fallback=False, suppress=(FileNotFoundError,) if False else ())
94
91
  def safe_rmtree(
95
92
  path: Path | str,
96
93
  missing_ok: bool = True,
@@ -109,21 +106,15 @@ def safe_rmtree(
109
106
  """
110
107
  path = Path(path)
111
108
 
112
- try:
113
- if path.exists():
114
- shutil.rmtree(path)
115
- log.debug("Removed directory tree", path=str(path))
116
- return True
117
- elif missing_ok:
118
- log.debug("Directory already absent", path=str(path))
119
- return False
120
- else:
121
- raise FileNotFoundError(f"Directory does not exist: {path}")
122
- except Exception as e:
123
- if not path.exists() and missing_ok:
124
- return False
125
- log.error("Failed to remove directory tree", path=str(path), error=str(e))
126
- raise
109
+ if path.exists():
110
+ shutil.rmtree(path)
111
+ log.debug("Removed directory tree", path=str(path))
112
+ return True
113
+ elif missing_ok:
114
+ log.debug("Directory already absent", path=str(path))
115
+ return False
116
+ else:
117
+ raise FileNotFoundError(f"Directory does not exist: {path}")
127
118
 
128
119
 
129
120
  __all__ = [
@@ -4,6 +4,8 @@ import os
4
4
  from pathlib import Path
5
5
  import time
6
6
 
7
+ from provide.foundation.config.defaults import DEFAULT_FILE_LOCK_TIMEOUT
8
+ from provide.foundation.errors.decorators import with_error_handling
7
9
  from provide.foundation.errors.resources import LockError
8
10
  from provide.foundation.logger import get_logger
9
11
 
@@ -25,7 +27,7 @@ class FileLock:
25
27
  def __init__(
26
28
  self,
27
29
  path: Path | str,
28
- timeout: float = 10.0,
30
+ timeout: float = DEFAULT_FILE_LOCK_TIMEOUT,
29
31
  check_interval: float = 0.1,
30
32
  ) -> None:
31
33
  """Initialize file lock.