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
@@ -9,12 +9,12 @@ Primary public interface for the library, re-exporting common components.
9
9
  # Export config module for easy access
10
10
  # New foundation components
11
11
  # Make the errors module available for detailed imports
12
- from provide.foundation import config, errors, platform, process
12
+ from provide.foundation import config, errors, platform, process, resilience
13
13
  from provide.foundation._version import __version__
14
14
 
15
15
  # Console I/O functions (always available - handles click dependency internally)
16
16
  from provide.foundation.console import perr, pin, pout
17
- from provide.foundation.context import Context
17
+ from provide.foundation.context import CLIContext, Context
18
18
 
19
19
  # Error handling exports - only the essentials
20
20
  from provide.foundation.errors import (
@@ -27,6 +27,14 @@ from provide.foundation.errors import (
27
27
  with_error_handling,
28
28
  )
29
29
 
30
+ # Event set exports
31
+ from provide.foundation.eventsets.display import show_event_matrix
32
+ from provide.foundation.eventsets.types import (
33
+ EventMapping,
34
+ EventSet,
35
+ FieldMapping,
36
+ )
37
+
30
38
  # Hub and Registry exports (public API)
31
39
  from provide.foundation.hub.components import ComponentCategory, get_component_registry
32
40
  from provide.foundation.hub.manager import Hub, clear_hub, get_hub
@@ -39,12 +47,17 @@ from provide.foundation.logger import (
39
47
  setup_logging, # Setup function (backward compatibility)
40
48
  )
41
49
 
42
- # Event set exports
43
- from provide.foundation.eventsets.display import show_event_matrix
44
- from provide.foundation.eventsets.types import (
45
- EventMapping,
46
- EventSet,
47
- FieldMapping,
50
+ # Resilience exports
51
+ from provide.foundation.resilience import (
52
+ BackoffStrategy,
53
+ CircuitBreaker,
54
+ CircuitState,
55
+ FallbackChain,
56
+ RetryExecutor,
57
+ RetryPolicy,
58
+ circuit_breaker,
59
+ fallback,
60
+ retry,
48
61
  )
49
62
  from provide.foundation.setup import (
50
63
  setup_telemetry,
@@ -66,7 +79,7 @@ from provide.foundation.utils import (
66
79
 
67
80
 
68
81
  # Lazy loading support for optional modules
69
- def __getattr__(name: str):
82
+ def __getattr__(name: str) -> object:
70
83
  """Support lazy loading of optional modules."""
71
84
  if name == "cli":
72
85
  try:
@@ -92,7 +105,8 @@ __all__ = [
92
105
  "show_event_matrix",
93
106
  "ConsoleFormatterStr",
94
107
  # New foundation modules
95
- "Context",
108
+ "CLIContext",
109
+ "Context", # Backward compatibility
96
110
  # Event set types
97
111
  "EventMapping",
98
112
  "EventSet",
@@ -129,7 +143,19 @@ __all__ = [
129
143
  "pout",
130
144
  "platform",
131
145
  "process",
146
+ # Resilience patterns
147
+ "retry",
148
+ "circuit_breaker",
149
+ "fallback",
150
+ "RetryPolicy",
151
+ "RetryExecutor",
152
+ "BackoffStrategy",
153
+ "CircuitBreaker",
154
+ "CircuitState",
155
+ "FallbackChain",
156
+ # Backward compatibility (deprecated)
132
157
  "retry_on_error",
158
+ "resilience", # The resilience module for detailed imports
133
159
  "setup_logging", # Backward compatibility
134
160
  "setup_logger", # Consistent naming
135
161
  "setup_telemetry",
@@ -20,4 +20,4 @@ __all__ = [
20
20
  "OperationChain",
21
21
  "TarArchive",
22
22
  "ZipArchive",
23
- ]
23
+ ]
@@ -8,63 +8,64 @@ from provide.foundation.errors import FoundationError
8
8
 
9
9
  class ArchiveError(FoundationError):
10
10
  """Base exception for archive-related errors."""
11
+
11
12
  pass
12
13
 
13
14
 
14
15
  class BaseArchive(ABC):
15
16
  """
16
17
  Abstract base class for all archive implementations.
17
-
18
+
18
19
  This defines the common interface that all archive implementations
19
20
  must follow, ensuring consistency across different archive formats.
20
21
  """
21
-
22
+
22
23
  @abstractmethod
23
24
  def create(self, source: Path, output: Path) -> Path:
24
25
  """
25
26
  Create an archive from source path.
26
-
27
+
27
28
  Args:
28
29
  source: Source file or directory to archive
29
30
  output: Output archive file path
30
-
31
+
31
32
  Returns:
32
33
  Path to the created archive file
33
-
34
+
34
35
  Raises:
35
36
  ArchiveError: If archive creation fails
36
37
  """
37
38
  pass
38
-
39
+
39
40
  @abstractmethod
40
41
  def extract(self, archive: Path, output: Path) -> Path:
41
42
  """
42
43
  Extract an archive to output path.
43
-
44
+
44
45
  Args:
45
46
  archive: Archive file to extract
46
47
  output: Output directory for extracted contents
47
-
48
+
48
49
  Returns:
49
50
  Path to the extraction directory
50
-
51
+
51
52
  Raises:
52
53
  ArchiveError: If extraction fails
53
54
  """
54
55
  pass
55
-
56
+
56
57
  @abstractmethod
57
58
  def validate(self, archive: Path) -> bool:
58
59
  """
59
60
  Validate that an archive is properly formed.
60
-
61
+
61
62
  Args:
62
63
  archive: Archive file to validate
63
-
64
+
64
65
  Returns:
65
66
  True if archive is valid, False otherwise
66
-
67
+
67
68
  Raises:
68
69
  ArchiveError: If validation cannot be performed
69
70
  """
70
- pass
71
+ pass
@@ -1,8 +1,8 @@
1
1
  """BZIP2 compression implementation."""
2
2
 
3
3
  import bz2
4
- import shutil
5
4
  from pathlib import Path
5
+ import shutil
6
6
  from typing import BinaryIO
7
7
 
8
8
  from attrs import define, field
@@ -18,118 +18,118 @@ logger = get_logger(__name__)
18
18
  class Bzip2Compressor:
19
19
  """
20
20
  BZIP2 compression implementation.
21
-
21
+
22
22
  Provides BZIP2 compression and decompression for single files.
23
23
  Does not handle bundling - use with TarArchive for .tar.bz2 files.
24
24
  """
25
-
25
+
26
26
  level: int = field(default=9) # Compression level 1-9 (1=fast, 9=best)
27
-
27
+
28
28
  @level.validator
29
- def _validate_level(self, attribute, value):
29
+ def _validate_level(self, attribute: object, value: int) -> None:
30
30
  if not 1 <= value <= 9:
31
31
  raise ValueError(f"Compression level must be 1-9, got {value}")
32
-
32
+
33
33
  def compress(self, input_stream: BinaryIO, output_stream: BinaryIO) -> None:
34
34
  """
35
35
  Compress data from input stream to output stream.
36
-
36
+
37
37
  Args:
38
38
  input_stream: Input binary stream
39
39
  output_stream: Output binary stream
40
-
40
+
41
41
  Raises:
42
42
  ArchiveError: If compression fails
43
43
  """
44
44
  try:
45
- with bz2.BZ2File(output_stream, 'wb', compresslevel=self.level) as bz:
45
+ with bz2.BZ2File(output_stream, "wb", compresslevel=self.level) as bz:
46
46
  shutil.copyfileobj(input_stream, bz)
47
47
  logger.debug(f"Compressed data with BZIP2 level {self.level}")
48
48
  except Exception as e:
49
49
  raise ArchiveError(f"Failed to compress with BZIP2: {e}") from e
50
-
50
+
51
51
  def decompress(self, input_stream: BinaryIO, output_stream: BinaryIO) -> None:
52
52
  """
53
53
  Decompress data from input stream to output stream.
54
-
54
+
55
55
  Args:
56
56
  input_stream: Input binary stream (bzip2 compressed)
57
57
  output_stream: Output binary stream
58
-
58
+
59
59
  Raises:
60
60
  ArchiveError: If decompression fails
61
61
  """
62
62
  try:
63
- with bz2.BZ2File(input_stream, 'rb') as bz:
63
+ with bz2.BZ2File(input_stream, "rb") as bz:
64
64
  shutil.copyfileobj(bz, output_stream)
65
65
  logger.debug("Decompressed BZIP2 data")
66
66
  except Exception as e:
67
67
  raise ArchiveError(f"Failed to decompress BZIP2: {e}") from e
68
-
68
+
69
69
  def compress_file(self, input_path: Path, output_path: Path) -> Path:
70
70
  """
71
71
  Compress a file.
72
-
72
+
73
73
  Args:
74
74
  input_path: Input file path
75
75
  output_path: Output file path (should end with .bz2)
76
-
76
+
77
77
  Returns:
78
78
  Path to compressed file
79
-
79
+
80
80
  Raises:
81
81
  ArchiveError: If compression fails
82
82
  """
83
83
  try:
84
84
  ensure_parent_dir(output_path)
85
-
86
- with open(input_path, 'rb') as f_in:
87
- with bz2.open(output_path, 'wb', compresslevel=self.level) as f_out:
85
+
86
+ with open(input_path, "rb") as f_in:
87
+ with bz2.open(output_path, "wb", compresslevel=self.level) as f_out:
88
88
  shutil.copyfileobj(f_in, f_out)
89
-
89
+
90
90
  logger.debug(f"Compressed {input_path} to {output_path}")
91
91
  return output_path
92
-
92
+
93
93
  except Exception as e:
94
94
  raise ArchiveError(f"Failed to compress file: {e}") from e
95
-
95
+
96
96
  def decompress_file(self, input_path: Path, output_path: Path) -> Path:
97
97
  """
98
98
  Decompress a file.
99
-
99
+
100
100
  Args:
101
101
  input_path: Input file path (bzip2 compressed)
102
102
  output_path: Output file path
103
-
103
+
104
104
  Returns:
105
105
  Path to decompressed file
106
-
106
+
107
107
  Raises:
108
108
  ArchiveError: If decompression fails
109
109
  """
110
110
  try:
111
111
  ensure_parent_dir(output_path)
112
-
113
- with bz2.open(input_path, 'rb') as f_in:
114
- with open(output_path, 'wb') as f_out:
112
+
113
+ with bz2.open(input_path, "rb") as f_in:
114
+ with open(output_path, "wb") as f_out:
115
115
  shutil.copyfileobj(f_in, f_out)
116
-
116
+
117
117
  logger.debug(f"Decompressed {input_path} to {output_path}")
118
118
  return output_path
119
-
119
+
120
120
  except Exception as e:
121
121
  raise ArchiveError(f"Failed to decompress file: {e}") from e
122
-
122
+
123
123
  def compress_bytes(self, data: bytes) -> bytes:
124
124
  """
125
125
  Compress bytes data.
126
-
126
+
127
127
  Args:
128
128
  data: Input bytes
129
-
129
+
130
130
  Returns:
131
131
  Compressed bytes
132
-
132
+
133
133
  Raises:
134
134
  ArchiveError: If compression fails
135
135
  """
@@ -137,21 +137,21 @@ class Bzip2Compressor:
137
137
  return bz2.compress(data, compresslevel=self.level)
138
138
  except Exception as e:
139
139
  raise ArchiveError(f"Failed to compress bytes: {e}") from e
140
-
140
+
141
141
  def decompress_bytes(self, data: bytes) -> bytes:
142
142
  """
143
143
  Decompress bytes data.
144
-
144
+
145
145
  Args:
146
146
  data: Compressed bytes
147
-
147
+
148
148
  Returns:
149
149
  Decompressed bytes
150
-
150
+
151
151
  Raises:
152
152
  ArchiveError: If decompression fails
153
153
  """
154
154
  try:
155
155
  return bz2.decompress(data)
156
156
  except Exception as e:
157
- raise ArchiveError(f"Failed to decompress bytes: {e}") from e
157
+ raise ArchiveError(f"Failed to decompress bytes: {e}") from e
@@ -1,16 +1,14 @@
1
1
  """GZIP compression implementation."""
2
2
 
3
3
  import gzip
4
- import shutil
5
- from io import BytesIO
6
4
  from pathlib import Path
5
+ import shutil
7
6
  from typing import BinaryIO
8
7
 
9
8
  from attrs import define, field
10
9
 
11
10
  from provide.foundation.archive.base import ArchiveError
12
11
  from provide.foundation.file import ensure_parent_dir
13
- from provide.foundation.file.utils import get_size
14
12
  from provide.foundation.logger import get_logger
15
13
 
16
14
  logger = get_logger(__name__)
@@ -20,118 +18,120 @@ logger = get_logger(__name__)
20
18
  class GzipCompressor:
21
19
  """
22
20
  GZIP compression implementation.
23
-
21
+
24
22
  Provides GZIP compression and decompression for single files.
25
23
  Does not handle bundling - use with TarArchive for .tar.gz files.
26
24
  """
27
-
25
+
28
26
  level: int = field(default=6) # Compression level 1-9 (1=fast, 9=best)
29
-
27
+
30
28
  @level.validator
31
- def _validate_level(self, attribute, value):
29
+ def _validate_level(self, attribute: object, value: int) -> None:
32
30
  if not 1 <= value <= 9:
33
31
  raise ValueError(f"Compression level must be 1-9, got {value}")
34
-
32
+
35
33
  def compress(self, input_stream: BinaryIO, output_stream: BinaryIO) -> None:
36
34
  """
37
35
  Compress data from input stream to output stream.
38
-
36
+
39
37
  Args:
40
38
  input_stream: Input binary stream
41
39
  output_stream: Output binary stream
42
-
40
+
43
41
  Raises:
44
42
  ArchiveError: If compression fails
45
43
  """
46
44
  try:
47
- with gzip.GzipFile(fileobj=output_stream, mode='wb', compresslevel=self.level) as gz:
45
+ with gzip.GzipFile(
46
+ fileobj=output_stream, mode="wb", compresslevel=self.level
47
+ ) as gz:
48
48
  shutil.copyfileobj(input_stream, gz)
49
49
  logger.debug(f"Compressed data with GZIP level {self.level}")
50
50
  except Exception as e:
51
51
  raise ArchiveError(f"Failed to compress with GZIP: {e}") from e
52
-
52
+
53
53
  def decompress(self, input_stream: BinaryIO, output_stream: BinaryIO) -> None:
54
54
  """
55
55
  Decompress data from input stream to output stream.
56
-
56
+
57
57
  Args:
58
58
  input_stream: Input binary stream (gzipped)
59
59
  output_stream: Output binary stream
60
-
60
+
61
61
  Raises:
62
62
  ArchiveError: If decompression fails
63
63
  """
64
64
  try:
65
- with gzip.GzipFile(fileobj=input_stream, mode='rb') as gz:
65
+ with gzip.GzipFile(fileobj=input_stream, mode="rb") as gz:
66
66
  shutil.copyfileobj(gz, output_stream)
67
67
  logger.debug("Decompressed GZIP data")
68
68
  except Exception as e:
69
69
  raise ArchiveError(f"Failed to decompress GZIP: {e}") from e
70
-
70
+
71
71
  def compress_file(self, input_path: Path, output_path: Path) -> Path:
72
72
  """
73
73
  Compress a file.
74
-
74
+
75
75
  Args:
76
76
  input_path: Input file path
77
77
  output_path: Output file path (should end with .gz)
78
-
78
+
79
79
  Returns:
80
80
  Path to compressed file
81
-
81
+
82
82
  Raises:
83
83
  ArchiveError: If compression fails
84
84
  """
85
85
  try:
86
86
  ensure_parent_dir(output_path)
87
-
88
- with open(input_path, 'rb') as f_in:
89
- with gzip.open(output_path, 'wb', compresslevel=self.level) as f_out:
87
+
88
+ with open(input_path, "rb") as f_in:
89
+ with gzip.open(output_path, "wb", compresslevel=self.level) as f_out:
90
90
  shutil.copyfileobj(f_in, f_out)
91
-
91
+
92
92
  logger.debug(f"Compressed {input_path} to {output_path}")
93
93
  return output_path
94
-
94
+
95
95
  except Exception as e:
96
96
  raise ArchiveError(f"Failed to compress file: {e}") from e
97
-
97
+
98
98
  def decompress_file(self, input_path: Path, output_path: Path) -> Path:
99
99
  """
100
100
  Decompress a file.
101
-
101
+
102
102
  Args:
103
103
  input_path: Input file path (gzipped)
104
104
  output_path: Output file path
105
-
105
+
106
106
  Returns:
107
107
  Path to decompressed file
108
-
108
+
109
109
  Raises:
110
110
  ArchiveError: If decompression fails
111
111
  """
112
112
  try:
113
113
  ensure_parent_dir(output_path)
114
-
115
- with gzip.open(input_path, 'rb') as f_in:
116
- with open(output_path, 'wb') as f_out:
114
+
115
+ with gzip.open(input_path, "rb") as f_in:
116
+ with open(output_path, "wb") as f_out:
117
117
  shutil.copyfileobj(f_in, f_out)
118
-
118
+
119
119
  logger.debug(f"Decompressed {input_path} to {output_path}")
120
120
  return output_path
121
-
121
+
122
122
  except Exception as e:
123
123
  raise ArchiveError(f"Failed to decompress file: {e}") from e
124
-
124
+
125
125
  def compress_bytes(self, data: bytes) -> bytes:
126
126
  """
127
127
  Compress bytes data.
128
-
128
+
129
129
  Args:
130
130
  data: Input bytes
131
-
131
+
132
132
  Returns:
133
133
  Compressed bytes
134
-
134
+
135
135
  Raises:
136
136
  ArchiveError: If compression fails
137
137
  """
@@ -139,21 +139,21 @@ class GzipCompressor:
139
139
  return gzip.compress(data, compresslevel=self.level)
140
140
  except Exception as e:
141
141
  raise ArchiveError(f"Failed to compress bytes: {e}") from e
142
-
142
+
143
143
  def decompress_bytes(self, data: bytes) -> bytes:
144
144
  """
145
145
  Decompress bytes data.
146
-
146
+
147
147
  Args:
148
148
  data: Compressed bytes
149
-
149
+
150
150
  Returns:
151
151
  Decompressed bytes
152
-
152
+
153
153
  Raises:
154
154
  ArchiveError: If decompression fails
155
155
  """
156
156
  try:
157
157
  return gzip.decompress(data)
158
158
  except Exception as e:
159
- raise ArchiveError(f"Failed to decompress bytes: {e}") from e
159
+ raise ArchiveError(f"Failed to decompress bytes: {e}") from e