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