provide-foundation 0.0.0.dev1__py3-none-any.whl → 0.0.0.dev3__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 (163) hide show
  1. provide/foundation/__init__.py +36 -10
  2. provide/foundation/archive/__init__.py +1 -1
  3. provide/foundation/archive/base.py +15 -14
  4. provide/foundation/archive/bzip2.py +40 -40
  5. provide/foundation/archive/gzip.py +42 -42
  6. provide/foundation/archive/operations.py +93 -96
  7. provide/foundation/archive/tar.py +33 -31
  8. provide/foundation/archive/zip.py +52 -50
  9. provide/foundation/asynctools/__init__.py +20 -0
  10. provide/foundation/asynctools/core.py +126 -0
  11. provide/foundation/cli/__init__.py +2 -2
  12. provide/foundation/cli/commands/deps.py +15 -9
  13. provide/foundation/cli/commands/logs/__init__.py +3 -3
  14. provide/foundation/cli/commands/logs/generate.py +2 -2
  15. provide/foundation/cli/commands/logs/query.py +4 -4
  16. provide/foundation/cli/commands/logs/send.py +3 -3
  17. provide/foundation/cli/commands/logs/tail.py +3 -3
  18. provide/foundation/cli/decorators.py +11 -11
  19. provide/foundation/cli/main.py +1 -1
  20. provide/foundation/cli/testing.py +2 -40
  21. provide/foundation/cli/utils.py +21 -18
  22. provide/foundation/config/__init__.py +35 -2
  23. provide/foundation/config/base.py +2 -2
  24. provide/foundation/config/converters.py +477 -0
  25. provide/foundation/config/defaults.py +67 -0
  26. provide/foundation/config/env.py +6 -20
  27. provide/foundation/config/loader.py +10 -4
  28. provide/foundation/config/sync.py +8 -6
  29. provide/foundation/config/types.py +5 -5
  30. provide/foundation/config/validators.py +4 -4
  31. provide/foundation/console/input.py +5 -5
  32. provide/foundation/console/output.py +36 -14
  33. provide/foundation/context/__init__.py +8 -4
  34. provide/foundation/context/core.py +88 -110
  35. provide/foundation/crypto/certificates/__init__.py +9 -5
  36. provide/foundation/crypto/certificates/base.py +2 -2
  37. provide/foundation/crypto/certificates/certificate.py +48 -19
  38. provide/foundation/crypto/certificates/factory.py +26 -18
  39. provide/foundation/crypto/certificates/generator.py +24 -23
  40. provide/foundation/crypto/certificates/loader.py +24 -16
  41. provide/foundation/crypto/certificates/operations.py +17 -10
  42. provide/foundation/crypto/certificates/trust.py +21 -21
  43. provide/foundation/env/__init__.py +28 -0
  44. provide/foundation/env/core.py +218 -0
  45. provide/foundation/errors/__init__.py +3 -3
  46. provide/foundation/errors/decorators.py +0 -234
  47. provide/foundation/errors/types.py +0 -98
  48. provide/foundation/eventsets/display.py +13 -14
  49. provide/foundation/eventsets/registry.py +61 -31
  50. provide/foundation/eventsets/resolver.py +50 -46
  51. provide/foundation/eventsets/sets/das.py +8 -8
  52. provide/foundation/eventsets/sets/database.py +14 -14
  53. provide/foundation/eventsets/sets/http.py +21 -21
  54. provide/foundation/eventsets/sets/llm.py +16 -16
  55. provide/foundation/eventsets/sets/task_queue.py +13 -13
  56. provide/foundation/eventsets/types.py +7 -7
  57. provide/foundation/file/directory.py +14 -23
  58. provide/foundation/file/lock.py +4 -3
  59. provide/foundation/hub/components.py +75 -389
  60. provide/foundation/hub/config.py +157 -0
  61. provide/foundation/hub/discovery.py +63 -0
  62. provide/foundation/hub/handlers.py +89 -0
  63. provide/foundation/hub/lifecycle.py +195 -0
  64. provide/foundation/hub/manager.py +7 -4
  65. provide/foundation/hub/processors.py +49 -0
  66. provide/foundation/integrations/__init__.py +11 -0
  67. provide/foundation/{observability → integrations}/openobserve/__init__.py +10 -7
  68. provide/foundation/{observability → integrations}/openobserve/auth.py +1 -1
  69. provide/foundation/{observability → integrations}/openobserve/client.py +14 -14
  70. provide/foundation/{observability → integrations}/openobserve/commands.py +12 -12
  71. provide/foundation/integrations/openobserve/config.py +37 -0
  72. provide/foundation/{observability → integrations}/openobserve/formatters.py +1 -1
  73. provide/foundation/{observability → integrations}/openobserve/otlp.py +2 -2
  74. provide/foundation/{observability → integrations}/openobserve/search.py +2 -3
  75. provide/foundation/{observability → integrations}/openobserve/streaming.py +5 -5
  76. provide/foundation/logger/__init__.py +0 -1
  77. provide/foundation/logger/config/base.py +1 -1
  78. provide/foundation/logger/config/logging.py +69 -299
  79. provide/foundation/logger/config/telemetry.py +39 -121
  80. provide/foundation/logger/factories.py +2 -2
  81. provide/foundation/logger/processors/main.py +12 -10
  82. provide/foundation/logger/ratelimit/limiters.py +4 -4
  83. provide/foundation/logger/ratelimit/processor.py +1 -1
  84. provide/foundation/logger/setup/coordinator.py +39 -25
  85. provide/foundation/logger/setup/processors.py +3 -3
  86. provide/foundation/logger/setup/testing.py +14 -0
  87. provide/foundation/logger/trace.py +5 -5
  88. provide/foundation/metrics/__init__.py +1 -1
  89. provide/foundation/metrics/otel.py +3 -1
  90. provide/foundation/observability/__init__.py +3 -3
  91. provide/foundation/process/__init__.py +9 -0
  92. provide/foundation/process/exit.py +48 -0
  93. provide/foundation/process/lifecycle.py +69 -46
  94. provide/foundation/resilience/__init__.py +36 -0
  95. provide/foundation/resilience/circuit.py +166 -0
  96. provide/foundation/resilience/decorators.py +236 -0
  97. provide/foundation/resilience/fallback.py +208 -0
  98. provide/foundation/resilience/retry.py +327 -0
  99. provide/foundation/serialization/__init__.py +16 -0
  100. provide/foundation/serialization/core.py +70 -0
  101. provide/foundation/streams/config.py +78 -0
  102. provide/foundation/streams/console.py +4 -5
  103. provide/foundation/streams/core.py +5 -2
  104. provide/foundation/streams/file.py +12 -2
  105. provide/foundation/testing/__init__.py +29 -9
  106. provide/foundation/testing/archive/__init__.py +7 -7
  107. provide/foundation/testing/archive/fixtures.py +58 -54
  108. provide/foundation/testing/cli.py +30 -20
  109. provide/foundation/testing/common/__init__.py +13 -15
  110. provide/foundation/testing/common/fixtures.py +27 -57
  111. provide/foundation/testing/file/__init__.py +15 -15
  112. provide/foundation/testing/file/content_fixtures.py +289 -0
  113. provide/foundation/testing/file/directory_fixtures.py +107 -0
  114. provide/foundation/testing/file/fixtures.py +42 -516
  115. provide/foundation/testing/file/special_fixtures.py +145 -0
  116. provide/foundation/testing/logger.py +89 -8
  117. provide/foundation/testing/mocking/__init__.py +21 -21
  118. provide/foundation/testing/mocking/fixtures.py +80 -67
  119. provide/foundation/testing/process/__init__.py +23 -23
  120. provide/foundation/testing/process/async_fixtures.py +414 -0
  121. provide/foundation/testing/process/fixtures.py +48 -571
  122. provide/foundation/testing/process/subprocess_fixtures.py +210 -0
  123. provide/foundation/testing/threading/__init__.py +17 -17
  124. provide/foundation/testing/threading/basic_fixtures.py +105 -0
  125. provide/foundation/testing/threading/data_fixtures.py +101 -0
  126. provide/foundation/testing/threading/execution_fixtures.py +278 -0
  127. provide/foundation/testing/threading/fixtures.py +32 -502
  128. provide/foundation/testing/threading/sync_fixtures.py +100 -0
  129. provide/foundation/testing/time/__init__.py +11 -11
  130. provide/foundation/testing/time/fixtures.py +95 -83
  131. provide/foundation/testing/transport/__init__.py +9 -9
  132. provide/foundation/testing/transport/fixtures.py +54 -54
  133. provide/foundation/time/__init__.py +18 -0
  134. provide/foundation/time/core.py +63 -0
  135. provide/foundation/tools/__init__.py +2 -2
  136. provide/foundation/tools/base.py +68 -67
  137. provide/foundation/tools/cache.py +69 -74
  138. provide/foundation/tools/downloader.py +68 -62
  139. provide/foundation/tools/installer.py +51 -57
  140. provide/foundation/tools/registry.py +38 -45
  141. provide/foundation/tools/resolver.py +70 -68
  142. provide/foundation/tools/verifier.py +39 -50
  143. provide/foundation/tracer/spans.py +2 -14
  144. provide/foundation/transport/__init__.py +26 -33
  145. provide/foundation/transport/base.py +32 -30
  146. provide/foundation/transport/client.py +44 -49
  147. provide/foundation/transport/config.py +36 -107
  148. provide/foundation/transport/errors.py +13 -27
  149. provide/foundation/transport/http.py +69 -55
  150. provide/foundation/transport/middleware.py +113 -114
  151. provide/foundation/transport/registry.py +29 -27
  152. provide/foundation/transport/types.py +6 -6
  153. provide/foundation/utils/deps.py +17 -14
  154. provide/foundation/utils/parsing.py +49 -4
  155. {provide_foundation-0.0.0.dev1.dist-info → provide_foundation-0.0.0.dev3.dist-info}/METADATA +2 -2
  156. provide_foundation-0.0.0.dev3.dist-info/RECORD +233 -0
  157. provide_foundation-0.0.0.dev1.dist-info/RECORD +0 -200
  158. /provide/foundation/{observability → integrations}/openobserve/exceptions.py +0 -0
  159. /provide/foundation/{observability → integrations}/openobserve/models.py +0 -0
  160. {provide_foundation-0.0.0.dev1.dist-info → provide_foundation-0.0.0.dev3.dist-info}/WHEEL +0 -0
  161. {provide_foundation-0.0.0.dev1.dist-info → provide_foundation-0.0.0.dev3.dist-info}/entry_points.txt +0 -0
  162. {provide_foundation-0.0.0.dev1.dist-info → provide_foundation-0.0.0.dev3.dist-info}/licenses/LICENSE +0 -0
  163. {provide_foundation-0.0.0.dev1.dist-info → provide_foundation-0.0.0.dev3.dist-info}/top_level.txt +0 -0
@@ -6,38 +6,16 @@ import os
6
6
  from pathlib import Path
7
7
  import tempfile
8
8
  from typing import Any
9
- from unittest.mock import MagicMock
10
9
 
11
10
  import click
12
11
  from click.testing import CliRunner
13
12
 
14
- from provide.foundation.context import Context
13
+ from provide.foundation.context import CLIContext
15
14
  from provide.foundation.logger import get_logger
16
15
 
17
16
  log = get_logger(__name__)
18
17
 
19
18
 
20
- class MockContext(Context):
21
- """Mock context for testing that tracks method calls."""
22
-
23
- def __init__(self, **kwargs) -> None:
24
- """Initialize mock context with tracking."""
25
- super().__init__(**kwargs)
26
- self.calls = []
27
- self.saved_configs = []
28
- self.loaded_configs = []
29
-
30
- def save_config(self, path: str | Path) -> None:
31
- """Track save_config calls."""
32
- self.saved_configs.append(path)
33
- super().save_config(path)
34
-
35
- def load_config(self, path: str | Path) -> None:
36
- """Track load_config calls."""
37
- self.loaded_configs.append(path)
38
- super().load_config(path)
39
-
40
-
41
19
  @contextmanager
42
20
  def isolated_cli_runner(
43
21
  env: dict[str, str] | None = None,
@@ -150,7 +128,7 @@ def create_test_cli(
150
128
  @click.pass_context
151
129
  def cli(ctx, **kwargs) -> None:
152
130
  """Test CLI for testing."""
153
- ctx.obj = Context(**{k: v for k, v in kwargs.items() if v is not None})
131
+ ctx.obj = CLIContext(**{k: v for k, v in kwargs.items() if v is not None})
154
132
 
155
133
  if commands:
156
134
  for cmd in commands:
@@ -159,22 +137,6 @@ def create_test_cli(
159
137
  return cli
160
138
 
161
139
 
162
- def mock_logger():
163
- """
164
- Create a mock logger for testing.
165
-
166
- Returns:
167
- MagicMock with common logger methods
168
- """
169
- mock = MagicMock()
170
- mock.debug = MagicMock()
171
- mock.info = MagicMock()
172
- mock.warning = MagicMock()
173
- mock.error = MagicMock()
174
- mock.critical = MagicMock()
175
- return mock
176
-
177
-
178
140
  class CliTestCase:
179
141
  """Base class for CLI test cases with common utilities."""
180
142
 
@@ -1,12 +1,12 @@
1
1
  """Common CLI utilities for output, logging, and testing."""
2
2
 
3
- import json
4
3
  from typing import Any
5
4
 
6
5
  import click
7
6
  from click.testing import CliRunner, Result
8
7
 
9
- from provide.foundation.context import Context
8
+ from provide.foundation.console.output import perr, pout
9
+ from provide.foundation.context import CLIContext
10
10
  from provide.foundation.logger import (
11
11
  LoggingConfig,
12
12
  TelemetryConfig,
@@ -25,7 +25,10 @@ def echo_json(data: Any, err: bool = False) -> None:
25
25
  data: Data to output as JSON
26
26
  err: Whether to output to stderr
27
27
  """
28
- click.echo(json.dumps(data, indent=2, default=str), err=err)
28
+ if err:
29
+ perr(data)
30
+ else:
31
+ pout(data)
29
32
 
30
33
 
31
34
  def echo_error(message: str, json_output: bool = False) -> None:
@@ -37,9 +40,9 @@ def echo_error(message: str, json_output: bool = False) -> None:
37
40
  json_output: Whether to output as JSON
38
41
  """
39
42
  if json_output:
40
- echo_json({"error": message}, err=True)
43
+ perr(message, json_key="error")
41
44
  else:
42
- click.secho(f"✗ {message}", fg="red", err=True)
45
+ perr(f"✗ {message}", color="red")
43
46
 
44
47
 
45
48
  def echo_success(message: str, json_output: bool = False) -> None:
@@ -51,9 +54,9 @@ def echo_success(message: str, json_output: bool = False) -> None:
51
54
  json_output: Whether to output as JSON
52
55
  """
53
56
  if json_output:
54
- echo_json({"success": message})
57
+ pout(message, json_key="success")
55
58
  else:
56
- click.secho(f"✓ {message}", fg="green")
59
+ pout(f"✓ {message}", color="green")
57
60
 
58
61
 
59
62
  def echo_warning(message: str, json_output: bool = False) -> None:
@@ -65,9 +68,9 @@ def echo_warning(message: str, json_output: bool = False) -> None:
65
68
  json_output: Whether to output as JSON
66
69
  """
67
70
  if json_output:
68
- echo_json({"warning": message}, err=True)
71
+ perr(message, json_key="warning")
69
72
  else:
70
- click.secho(f"⚠ {message}", fg="yellow", err=True)
73
+ perr(f"⚠ {message}", color="yellow")
71
74
 
72
75
 
73
76
  def echo_info(message: str, json_output: bool = False) -> None:
@@ -79,23 +82,23 @@ def echo_info(message: str, json_output: bool = False) -> None:
79
82
  json_output: Whether to output as JSON
80
83
  """
81
84
  if json_output:
82
- echo_json({"info": message})
85
+ pout(message, json_key="info")
83
86
  else:
84
- click.echo(f"ℹ {message}")
87
+ pout(f"ℹ {message}")
85
88
 
86
89
 
87
90
  def setup_cli_logging(
88
- ctx: Context,
91
+ ctx: CLIContext,
89
92
  ) -> None:
90
93
  """
91
- Setup logging for CLI applications using a Context object.
94
+ Setup logging for CLI applications using a CLIContext object.
92
95
 
93
96
  This function is the designated way to configure logging within a CLI
94
97
  application built with foundation. It uses the provided context object
95
98
  to construct a full TelemetryConfig and initializes the system.
96
99
 
97
100
  Args:
98
- ctx: The foundation Context, populated by CLI decorators.
101
+ ctx: The foundation CLIContext, populated by CLI decorators.
99
102
  """
100
103
  console_formatter = "json" if ctx.json_output else ctx.log_format
101
104
 
@@ -116,9 +119,9 @@ def setup_cli_logging(
116
119
  setup_telemetry(config=telemetry_config)
117
120
 
118
121
 
119
- def create_cli_context(**kwargs) -> Context:
122
+ def create_cli_context(**kwargs) -> CLIContext:
120
123
  """
121
- Create a Context for CLI usage.
124
+ Create a CLIContext for CLI usage.
122
125
 
123
126
  Loads from environment, then overlays any provided kwargs.
124
127
 
@@ -126,9 +129,9 @@ def create_cli_context(**kwargs) -> Context:
126
129
  **kwargs: Override values for the context
127
130
 
128
131
  Returns:
129
- Configured Context instance
132
+ Configured CLIContext instance
130
133
  """
131
- ctx = Context.from_env()
134
+ ctx = CLIContext.from_env()
132
135
  for key, value in kwargs.items():
133
136
  if value is not None and hasattr(ctx, key):
134
137
  setattr(ctx, key, value)
@@ -9,6 +9,25 @@ from provide.foundation.config.base import (
9
9
  BaseConfig,
10
10
  field,
11
11
  )
12
+ from provide.foundation.config.converters import (
13
+ parse_bool_extended,
14
+ parse_comma_list,
15
+ parse_console_formatter,
16
+ parse_float_with_validation,
17
+ parse_headers,
18
+ parse_json_dict,
19
+ parse_json_list,
20
+ parse_log_level,
21
+ parse_module_levels,
22
+ parse_rate_limits,
23
+ parse_sample_rate,
24
+ validate_log_level,
25
+ validate_non_negative,
26
+ validate_overflow_policy,
27
+ validate_port,
28
+ validate_positive,
29
+ validate_sample_rate,
30
+ )
12
31
  from provide.foundation.config.env import (
13
32
  RuntimeConfig,
14
33
  env_field,
@@ -47,8 +66,6 @@ from provide.foundation.config.types import (
47
66
  )
48
67
  from provide.foundation.config.validators import (
49
68
  validate_choice,
50
- validate_non_negative,
51
- validate_positive,
52
69
  validate_range,
53
70
  )
54
71
  from provide.foundation.errors.config import (
@@ -96,11 +113,27 @@ __all__ = [
96
113
  "parse_dict",
97
114
  "parse_list",
98
115
  "set_config",
116
+ # Converters
117
+ "parse_bool_extended",
118
+ "parse_comma_list",
119
+ "parse_console_formatter",
120
+ "parse_float_with_validation",
121
+ "parse_headers",
122
+ "parse_json_dict",
123
+ "parse_json_list",
124
+ "parse_log_level",
125
+ "parse_module_levels",
126
+ "parse_rate_limits",
127
+ "parse_sample_rate",
99
128
  # Validators
100
129
  "validate_choice",
101
130
  "validate_config",
131
+ "validate_log_level",
102
132
  "validate_non_negative",
133
+ "validate_overflow_policy",
134
+ "validate_port",
103
135
  "validate_positive",
104
136
  "validate_range",
137
+ "validate_sample_rate",
105
138
  "validate_schema",
106
139
  ]
@@ -87,7 +87,7 @@ class BaseConfig:
87
87
  _source_map: dict[str, ConfigSource] = attrs_field(init=False, factory=lambda: {})
88
88
  _original_values: dict[str, Any] = attrs_field(init=False, factory=lambda: {})
89
89
 
90
- def __attrs_post_init__(self):
90
+ def __attrs_post_init__(self) -> None:
91
91
  """Post-initialization hook for subclasses."""
92
92
  # The _source_map and _original_values are now handled by attrs with factory
93
93
  # Note: validate() is now async, so we can't call it here
@@ -175,7 +175,7 @@ class BaseConfig:
175
175
  Configuration instance
176
176
  """
177
177
  # Filter data to only include fields defined in the class, excluding private fields
178
- field_names = {f.name for f in fields(cls) if not f.name.startswith('_')}
178
+ field_names = {f.name for f in fields(cls) if not f.name.startswith("_")}
179
179
  filtered_data = {k: v for k, v in data.items() if k in field_names}
180
180
 
181
181
  # Create instance