exonware-xwsystem 0.1.0.1__py3-none-any.whl → 0.1.0.3__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.
- exonware/__init__.py +2 -1
- exonware/conf.py +2 -2
- exonware/xwsystem/__init__.py +115 -43
- exonware/xwsystem/base.py +30 -0
- exonware/xwsystem/caching/__init__.py +39 -13
- exonware/xwsystem/caching/base.py +24 -6
- exonware/xwsystem/caching/bloom_cache.py +2 -2
- exonware/xwsystem/caching/cache_manager.py +2 -1
- exonware/xwsystem/caching/conditional.py +2 -2
- exonware/xwsystem/caching/contracts.py +85 -139
- exonware/xwsystem/caching/decorators.py +6 -19
- exonware/xwsystem/caching/defs.py +2 -1
- exonware/xwsystem/caching/disk_cache.py +2 -1
- exonware/xwsystem/caching/distributed.py +2 -1
- exonware/xwsystem/caching/errors.py +2 -1
- exonware/xwsystem/caching/events.py +110 -27
- exonware/xwsystem/caching/eviction_strategies.py +2 -2
- exonware/xwsystem/caching/external_caching_python.py +701 -0
- exonware/xwsystem/caching/facade.py +253 -0
- exonware/xwsystem/caching/factory.py +300 -0
- exonware/xwsystem/caching/fluent.py +14 -12
- exonware/xwsystem/caching/integrity.py +21 -6
- exonware/xwsystem/caching/lfu_cache.py +2 -1
- exonware/xwsystem/caching/lfu_optimized.py +18 -6
- exonware/xwsystem/caching/lru_cache.py +7 -4
- exonware/xwsystem/caching/memory_bounded.py +2 -2
- exonware/xwsystem/caching/metrics_exporter.py +2 -2
- exonware/xwsystem/caching/observable_cache.py +2 -2
- exonware/xwsystem/caching/pluggable_cache.py +2 -2
- exonware/xwsystem/caching/rate_limiter.py +2 -2
- exonware/xwsystem/caching/read_through.py +2 -2
- exonware/xwsystem/caching/secure_cache.py +81 -28
- exonware/xwsystem/caching/serializable.py +9 -7
- exonware/xwsystem/caching/stats.py +2 -2
- exonware/xwsystem/caching/tagging.py +2 -2
- exonware/xwsystem/caching/ttl_cache.py +4 -3
- exonware/xwsystem/caching/two_tier_cache.py +6 -3
- exonware/xwsystem/caching/utils.py +30 -12
- exonware/xwsystem/caching/validation.py +2 -2
- exonware/xwsystem/caching/warming.py +6 -3
- exonware/xwsystem/caching/write_behind.py +15 -6
- exonware/xwsystem/config/__init__.py +11 -17
- exonware/xwsystem/config/base.py +5 -5
- exonware/xwsystem/config/contracts.py +93 -153
- exonware/xwsystem/config/defaults.py +3 -2
- exonware/xwsystem/config/defs.py +3 -2
- exonware/xwsystem/config/errors.py +2 -5
- exonware/xwsystem/config/logging.py +12 -8
- exonware/xwsystem/config/logging_setup.py +3 -2
- exonware/xwsystem/config/performance.py +1 -46
- exonware/xwsystem/config/performance_modes.py +9 -8
- exonware/xwsystem/config/version_manager.py +1 -0
- exonware/xwsystem/config.py +27 -0
- exonware/xwsystem/console/__init__.py +53 -0
- exonware/xwsystem/console/base.py +133 -0
- exonware/xwsystem/console/cli/__init__.py +61 -0
- exonware/xwsystem/{cli → console/cli}/args.py +27 -24
- exonware/xwsystem/{cli → console/cli}/base.py +18 -87
- exonware/xwsystem/{cli → console/cli}/colors.py +15 -13
- exonware/xwsystem/console/cli/console.py +98 -0
- exonware/xwsystem/{cli → console/cli}/contracts.py +51 -69
- exonware/xwsystem/console/cli/defs.py +87 -0
- exonware/xwsystem/console/cli/encoding.py +69 -0
- exonware/xwsystem/{cli → console/cli}/errors.py +8 -3
- exonware/xwsystem/console/cli/event_logger.py +166 -0
- exonware/xwsystem/{cli → console/cli}/progress.py +25 -21
- exonware/xwsystem/{cli → console/cli}/prompts.py +3 -2
- exonware/xwsystem/{cli → console/cli}/tables.py +27 -24
- exonware/xwsystem/console/contracts.py +113 -0
- exonware/xwsystem/console/defs.py +154 -0
- exonware/xwsystem/console/errors.py +34 -0
- exonware/xwsystem/console/event_logger.py +385 -0
- exonware/xwsystem/console/writer.py +132 -0
- exonware/xwsystem/contracts.py +28 -0
- exonware/xwsystem/data_structures/__init__.py +23 -0
- exonware/xwsystem/data_structures/trie.py +34 -0
- exonware/xwsystem/data_structures/union_find.py +144 -0
- exonware/xwsystem/defs.py +17 -0
- exonware/xwsystem/errors.py +23 -0
- exonware/xwsystem/facade.py +62 -0
- exonware/xwsystem/http_client/__init__.py +22 -1
- exonware/xwsystem/http_client/advanced_client.py +8 -5
- exonware/xwsystem/http_client/base.py +3 -2
- exonware/xwsystem/http_client/client.py +7 -4
- exonware/xwsystem/http_client/contracts.py +42 -56
- exonware/xwsystem/http_client/defs.py +2 -1
- exonware/xwsystem/http_client/errors.py +2 -1
- exonware/xwsystem/http_client/facade.py +156 -0
- exonware/xwsystem/io/__init__.py +22 -3
- exonware/xwsystem/io/archive/__init__.py +8 -2
- exonware/xwsystem/io/archive/archive.py +1 -1
- exonware/xwsystem/io/archive/archive_files.py +4 -7
- exonware/xwsystem/io/archive/archivers.py +120 -10
- exonware/xwsystem/io/archive/base.py +4 -5
- exonware/xwsystem/io/archive/codec_integration.py +1 -2
- exonware/xwsystem/io/archive/compression.py +1 -2
- exonware/xwsystem/io/archive/facade.py +263 -0
- exonware/xwsystem/io/archive/formats/__init__.py +2 -3
- exonware/xwsystem/io/archive/formats/brotli_format.py +20 -7
- exonware/xwsystem/io/archive/formats/lz4_format.py +20 -7
- exonware/xwsystem/io/archive/formats/rar.py +11 -5
- exonware/xwsystem/io/archive/formats/sevenzip.py +12 -6
- exonware/xwsystem/io/archive/formats/squashfs_format.py +1 -2
- exonware/xwsystem/io/archive/formats/tar.py +52 -7
- exonware/xwsystem/io/archive/formats/wim_format.py +11 -5
- exonware/xwsystem/io/archive/formats/zip.py +1 -2
- exonware/xwsystem/io/archive/formats/zpaq_format.py +1 -2
- exonware/xwsystem/io/archive/formats/zstandard.py +20 -7
- exonware/xwsystem/io/base.py +119 -115
- exonware/xwsystem/io/codec/__init__.py +4 -2
- exonware/xwsystem/io/codec/base.py +19 -13
- exonware/xwsystem/io/codec/contracts.py +59 -2
- exonware/xwsystem/io/codec/registry.py +67 -21
- exonware/xwsystem/io/common/__init__.py +1 -1
- exonware/xwsystem/io/common/atomic.py +29 -16
- exonware/xwsystem/io/common/base.py +11 -10
- exonware/xwsystem/io/common/lock.py +6 -5
- exonware/xwsystem/io/common/path_manager.py +2 -1
- exonware/xwsystem/io/common/watcher.py +1 -2
- exonware/xwsystem/io/contracts.py +301 -433
- exonware/xwsystem/io/contracts_1.py +1180 -0
- exonware/xwsystem/io/data_operations.py +19 -20
- exonware/xwsystem/io/defs.py +4 -3
- exonware/xwsystem/io/errors.py +3 -2
- exonware/xwsystem/io/facade.py +87 -61
- exonware/xwsystem/io/file/__init__.py +1 -1
- exonware/xwsystem/io/file/base.py +8 -9
- exonware/xwsystem/io/file/conversion.py +2 -3
- exonware/xwsystem/io/file/file.py +61 -18
- exonware/xwsystem/io/file/paged_source.py +8 -8
- exonware/xwsystem/io/file/paging/__init__.py +1 -2
- exonware/xwsystem/io/file/paging/byte_paging.py +4 -5
- exonware/xwsystem/io/file/paging/line_paging.py +2 -3
- exonware/xwsystem/io/file/paging/record_paging.py +2 -3
- exonware/xwsystem/io/file/paging/registry.py +1 -2
- exonware/xwsystem/io/file/source.py +13 -17
- exonware/xwsystem/io/filesystem/__init__.py +1 -1
- exonware/xwsystem/io/filesystem/base.py +1 -2
- exonware/xwsystem/io/filesystem/local.py +3 -4
- exonware/xwsystem/io/folder/__init__.py +1 -1
- exonware/xwsystem/io/folder/base.py +1 -2
- exonware/xwsystem/io/folder/folder.py +16 -7
- exonware/xwsystem/io/indexing/__init__.py +14 -0
- exonware/xwsystem/io/indexing/facade.py +443 -0
- exonware/xwsystem/io/path_parser.py +98 -0
- exonware/xwsystem/io/serialization/__init__.py +21 -3
- exonware/xwsystem/io/serialization/auto_serializer.py +146 -20
- exonware/xwsystem/io/serialization/base.py +84 -34
- exonware/xwsystem/io/serialization/contracts.py +50 -73
- exonware/xwsystem/io/serialization/defs.py +2 -1
- exonware/xwsystem/io/serialization/errors.py +2 -1
- exonware/xwsystem/io/serialization/flyweight.py +154 -7
- exonware/xwsystem/io/serialization/format_detector.py +15 -14
- exonware/xwsystem/io/serialization/formats/__init__.py +8 -5
- exonware/xwsystem/io/serialization/formats/binary/bson.py +15 -6
- exonware/xwsystem/io/serialization/formats/binary/cbor.py +5 -5
- exonware/xwsystem/io/serialization/formats/binary/marshal.py +5 -5
- exonware/xwsystem/io/serialization/formats/binary/msgpack.py +5 -5
- exonware/xwsystem/io/serialization/formats/binary/pickle.py +5 -5
- exonware/xwsystem/io/serialization/formats/binary/plistlib.py +5 -5
- exonware/xwsystem/io/serialization/formats/database/dbm.py +7 -7
- exonware/xwsystem/io/serialization/formats/database/shelve.py +7 -7
- exonware/xwsystem/io/serialization/formats/database/sqlite3.py +7 -7
- exonware/xwsystem/io/serialization/formats/tabular/__init__.py +27 -0
- exonware/xwsystem/io/serialization/formats/tabular/base.py +89 -0
- exonware/xwsystem/io/serialization/formats/tabular/csv.py +319 -0
- exonware/xwsystem/io/serialization/formats/tabular/df.py +249 -0
- exonware/xwsystem/io/serialization/formats/tabular/excel.py +291 -0
- exonware/xwsystem/io/serialization/formats/tabular/googlesheets.py +374 -0
- exonware/xwsystem/io/serialization/formats/text/__init__.py +1 -1
- exonware/xwsystem/io/serialization/formats/text/append_only_log.py +5 -7
- exonware/xwsystem/io/serialization/formats/text/configparser.py +5 -5
- exonware/xwsystem/io/serialization/formats/text/csv.py +7 -5
- exonware/xwsystem/io/serialization/formats/text/formdata.py +5 -5
- exonware/xwsystem/io/serialization/formats/text/json.py +27 -18
- exonware/xwsystem/io/serialization/formats/text/json5.py +8 -4
- exonware/xwsystem/io/serialization/formats/text/jsonlines.py +18 -14
- exonware/xwsystem/io/serialization/formats/text/multipart.py +5 -5
- exonware/xwsystem/io/serialization/formats/text/toml.py +8 -6
- exonware/xwsystem/io/serialization/formats/text/xml.py +25 -20
- exonware/xwsystem/io/serialization/formats/text/yaml.py +8 -6
- exonware/xwsystem/io/serialization/parsers/__init__.py +3 -2
- exonware/xwsystem/io/serialization/parsers/base.py +6 -5
- exonware/xwsystem/io/serialization/parsers/hybrid_parser.py +7 -6
- exonware/xwsystem/io/serialization/parsers/msgspec_parser.py +10 -7
- exonware/xwsystem/io/serialization/parsers/orjson_direct_parser.py +7 -6
- exonware/xwsystem/io/serialization/parsers/orjson_parser.py +11 -8
- exonware/xwsystem/io/serialization/parsers/pysimdjson_parser.py +13 -9
- exonware/xwsystem/io/serialization/parsers/rapidjson_parser.py +10 -7
- exonware/xwsystem/io/serialization/parsers/registry.py +11 -10
- exonware/xwsystem/io/serialization/parsers/standard.py +7 -6
- exonware/xwsystem/io/serialization/parsers/ujson_parser.py +10 -7
- exonware/xwsystem/io/serialization/registry.py +4 -4
- exonware/xwsystem/io/serialization/serializer.py +168 -79
- exonware/xwsystem/io/serialization/universal_options.py +367 -0
- exonware/xwsystem/io/serialization/utils/__init__.py +1 -2
- exonware/xwsystem/io/serialization/utils/path_ops.py +5 -6
- exonware/xwsystem/io/source_reader.py +223 -0
- exonware/xwsystem/io/stream/__init__.py +1 -1
- exonware/xwsystem/io/stream/async_operations.py +61 -14
- exonware/xwsystem/io/stream/base.py +1 -2
- exonware/xwsystem/io/stream/codec_io.py +6 -7
- exonware/xwsystem/ipc/__init__.py +1 -0
- exonware/xwsystem/ipc/async_fabric.py +4 -4
- exonware/xwsystem/ipc/base.py +6 -5
- exonware/xwsystem/ipc/contracts.py +41 -66
- exonware/xwsystem/ipc/defs.py +2 -1
- exonware/xwsystem/ipc/errors.py +2 -1
- exonware/xwsystem/ipc/message_queue.py +5 -2
- exonware/xwsystem/ipc/pipes.py +70 -34
- exonware/xwsystem/ipc/process_manager.py +7 -5
- exonware/xwsystem/ipc/process_pool.py +6 -5
- exonware/xwsystem/ipc/shared_memory.py +64 -11
- exonware/xwsystem/monitoring/__init__.py +7 -0
- exonware/xwsystem/monitoring/base.py +11 -8
- exonware/xwsystem/monitoring/contracts.py +86 -144
- exonware/xwsystem/monitoring/defs.py +2 -1
- exonware/xwsystem/monitoring/error_recovery.py +16 -3
- exonware/xwsystem/monitoring/errors.py +2 -1
- exonware/xwsystem/monitoring/facade.py +183 -0
- exonware/xwsystem/monitoring/memory_monitor.py +1 -0
- exonware/xwsystem/monitoring/metrics.py +1 -0
- exonware/xwsystem/monitoring/performance_manager_generic.py +7 -7
- exonware/xwsystem/monitoring/performance_monitor.py +1 -0
- exonware/xwsystem/monitoring/performance_validator.py +1 -0
- exonware/xwsystem/monitoring/system_monitor.py +6 -5
- exonware/xwsystem/monitoring/tracing.py +18 -16
- exonware/xwsystem/monitoring/tracker.py +2 -1
- exonware/xwsystem/operations/__init__.py +5 -50
- exonware/xwsystem/operations/base.py +3 -44
- exonware/xwsystem/operations/contracts.py +25 -15
- exonware/xwsystem/operations/defs.py +1 -1
- exonware/xwsystem/operations/diff.py +5 -4
- exonware/xwsystem/operations/errors.py +1 -1
- exonware/xwsystem/operations/merge.py +6 -4
- exonware/xwsystem/operations/patch.py +5 -4
- exonware/xwsystem/patterns/__init__.py +1 -0
- exonware/xwsystem/patterns/base.py +2 -1
- exonware/xwsystem/patterns/context_manager.py +2 -1
- exonware/xwsystem/patterns/contracts.py +215 -256
- exonware/xwsystem/patterns/defs.py +2 -1
- exonware/xwsystem/patterns/dynamic_facade.py +1 -0
- exonware/xwsystem/patterns/errors.py +2 -4
- exonware/xwsystem/patterns/handler_factory.py +2 -3
- exonware/xwsystem/patterns/import_registry.py +1 -0
- exonware/xwsystem/patterns/object_pool.py +1 -0
- exonware/xwsystem/patterns/registry.py +4 -43
- exonware/xwsystem/plugins/__init__.py +2 -1
- exonware/xwsystem/plugins/base.py +6 -5
- exonware/xwsystem/plugins/contracts.py +94 -158
- exonware/xwsystem/plugins/defs.py +2 -1
- exonware/xwsystem/plugins/errors.py +2 -1
- exonware/xwsystem/py.typed +3 -0
- exonware/xwsystem/query/__init__.py +36 -0
- exonware/xwsystem/query/contracts.py +56 -0
- exonware/xwsystem/query/errors.py +22 -0
- exonware/xwsystem/query/registry.py +128 -0
- exonware/xwsystem/runtime/__init__.py +2 -1
- exonware/xwsystem/runtime/base.py +4 -3
- exonware/xwsystem/runtime/contracts.py +39 -60
- exonware/xwsystem/runtime/defs.py +2 -1
- exonware/xwsystem/runtime/env.py +11 -9
- exonware/xwsystem/runtime/errors.py +2 -1
- exonware/xwsystem/runtime/reflection.py +3 -2
- exonware/xwsystem/security/__init__.py +68 -11
- exonware/xwsystem/security/audit.py +167 -0
- exonware/xwsystem/security/base.py +121 -24
- exonware/xwsystem/security/contracts.py +91 -146
- exonware/xwsystem/security/crypto.py +17 -16
- exonware/xwsystem/security/defs.py +2 -1
- exonware/xwsystem/security/errors.py +2 -1
- exonware/xwsystem/security/facade.py +321 -0
- exonware/xwsystem/security/file_security.py +330 -0
- exonware/xwsystem/security/hazmat.py +11 -8
- exonware/xwsystem/security/monitor.py +372 -0
- exonware/xwsystem/security/path_validator.py +140 -18
- exonware/xwsystem/security/policy.py +357 -0
- exonware/xwsystem/security/resource_limits.py +1 -0
- exonware/xwsystem/security/validator.py +455 -0
- exonware/xwsystem/shared/__init__.py +14 -1
- exonware/xwsystem/shared/base.py +285 -2
- exonware/xwsystem/shared/contracts.py +415 -126
- exonware/xwsystem/shared/defs.py +2 -1
- exonware/xwsystem/shared/errors.py +2 -2
- exonware/xwsystem/shared/xwobject.py +316 -0
- exonware/xwsystem/structures/__init__.py +1 -0
- exonware/xwsystem/structures/base.py +3 -2
- exonware/xwsystem/structures/circular_detector.py +15 -14
- exonware/xwsystem/structures/contracts.py +53 -76
- exonware/xwsystem/structures/defs.py +2 -1
- exonware/xwsystem/structures/errors.py +2 -1
- exonware/xwsystem/structures/tree_walker.py +2 -1
- exonware/xwsystem/threading/__init__.py +21 -4
- exonware/xwsystem/threading/async_primitives.py +6 -5
- exonware/xwsystem/threading/base.py +3 -2
- exonware/xwsystem/threading/contracts.py +87 -143
- exonware/xwsystem/threading/defs.py +2 -1
- exonware/xwsystem/threading/errors.py +2 -1
- exonware/xwsystem/threading/facade.py +175 -0
- exonware/xwsystem/threading/locks.py +1 -0
- exonware/xwsystem/threading/safe_factory.py +1 -0
- exonware/xwsystem/utils/__init__.py +40 -0
- exonware/xwsystem/utils/base.py +22 -21
- exonware/xwsystem/utils/contracts.py +50 -73
- exonware/xwsystem/utils/dt/__init__.py +19 -3
- exonware/xwsystem/utils/dt/base.py +5 -4
- exonware/xwsystem/utils/dt/contracts.py +22 -29
- exonware/xwsystem/utils/dt/defs.py +2 -1
- exonware/xwsystem/utils/dt/errors.py +2 -5
- exonware/xwsystem/utils/dt/formatting.py +88 -2
- exonware/xwsystem/utils/dt/humanize.py +10 -9
- exonware/xwsystem/utils/dt/parsing.py +56 -5
- exonware/xwsystem/utils/dt/timezone_utils.py +2 -24
- exonware/xwsystem/utils/errors.py +2 -4
- exonware/xwsystem/utils/paths.py +1 -0
- exonware/xwsystem/utils/string.py +49 -0
- exonware/xwsystem/utils/test_runner.py +185 -0
- exonware/xwsystem/utils/utils_contracts.py +2 -1
- exonware/xwsystem/utils/web.py +110 -0
- exonware/xwsystem/validation/__init__.py +25 -1
- exonware/xwsystem/validation/base.py +6 -5
- exonware/xwsystem/validation/contracts.py +29 -41
- exonware/xwsystem/validation/data_validator.py +1 -0
- exonware/xwsystem/validation/declarative.py +11 -8
- exonware/xwsystem/validation/defs.py +2 -1
- exonware/xwsystem/validation/errors.py +2 -1
- exonware/xwsystem/validation/facade.py +198 -0
- exonware/xwsystem/validation/fluent_validator.py +22 -19
- exonware/xwsystem/validation/schema_discovery.py +210 -0
- exonware/xwsystem/validation/type_safety.py +2 -1
- exonware/xwsystem/version.py +2 -2
- {exonware_xwsystem-0.1.0.1.dist-info → exonware_xwsystem-0.1.0.3.dist-info}/METADATA +71 -4
- exonware_xwsystem-0.1.0.3.dist-info/RECORD +337 -0
- exonware/xwsystem/cli/__init__.py +0 -43
- exonware/xwsystem/cli/console.py +0 -113
- exonware/xwsystem/cli/defs.py +0 -134
- exonware/xwsystem/conf.py +0 -44
- exonware/xwsystem/security/auth.py +0 -484
- exonware_xwsystem-0.1.0.1.dist-info/RECORD +0 -284
- {exonware_xwsystem-0.1.0.1.dist-info → exonware_xwsystem-0.1.0.3.dist-info}/WHEEL +0 -0
- {exonware_xwsystem-0.1.0.1.dist-info → exonware_xwsystem-0.1.0.3.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
#exonware/xwsystem/src/exonware/xwsystem/io/archive/facade.py
|
|
2
|
+
"""
|
|
3
|
+
Company: eXonware.com
|
|
4
|
+
Author: Eng. Muhammad AlShehri
|
|
5
|
+
Email: connect@exonware.com
|
|
6
|
+
Version: 0.1.0.3
|
|
7
|
+
Generation Date: January 2026
|
|
8
|
+
|
|
9
|
+
XWArchive - Unified Archiving Facade
|
|
10
|
+
|
|
11
|
+
Simplified API for all archive formats:
|
|
12
|
+
- ZIP, TAR, TAR.GZ, TAR.BZ2, TAR.XZ, 7Z, RAR, etc.
|
|
13
|
+
- Auto-detect format from file path
|
|
14
|
+
- Compression support
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
from pathlib import Path
|
|
18
|
+
from typing import Any, Optional, Union, List
|
|
19
|
+
|
|
20
|
+
from .archive import Archive
|
|
21
|
+
from .archivers import ZipArchiver, TarArchiver
|
|
22
|
+
from .formats import get_archiver_for_file, get_archiver_by_id
|
|
23
|
+
from .archive_files import ZipFile, TarFile
|
|
24
|
+
from ..defs import ArchiveFormat, CompressionAlgorithm, CompressionLevel
|
|
25
|
+
from ...config.logging_setup import get_logger
|
|
26
|
+
|
|
27
|
+
logger = get_logger(__name__)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class XWArchive:
|
|
31
|
+
"""
|
|
32
|
+
Unified archiving facade - simple API for all archive formats.
|
|
33
|
+
|
|
34
|
+
Examples:
|
|
35
|
+
>>> # Format-specific
|
|
36
|
+
>>> archive = XWArchive("zip") # or format="zip"
|
|
37
|
+
>>> archive = XWArchive("tar.gz")
|
|
38
|
+
>>> archive = XWArchive("7z")
|
|
39
|
+
|
|
40
|
+
>>> # Auto-detect from path
|
|
41
|
+
>>> archive = XWArchive("backup.zip") # Detects ZIP
|
|
42
|
+
|
|
43
|
+
>>> # With compression
|
|
44
|
+
>>> archive = XWArchive("tar.gz", compression="gzip", level="best")
|
|
45
|
+
|
|
46
|
+
>>> # Quick operations
|
|
47
|
+
>>> XWArchive.create("files.zip", ["file1.txt", "file2.txt"])
|
|
48
|
+
>>> XWArchive.extract("archive.zip", "output_dir")
|
|
49
|
+
|
|
50
|
+
>>> # File operations
|
|
51
|
+
>>> with XWArchive("backup.zip") as arch:
|
|
52
|
+
... arch.add("file.txt")
|
|
53
|
+
... arch.extract("file.txt", "output/")
|
|
54
|
+
"""
|
|
55
|
+
|
|
56
|
+
def __init__(
|
|
57
|
+
self,
|
|
58
|
+
format_or_path: Union[str, Path],
|
|
59
|
+
*,
|
|
60
|
+
format: Optional[str] = None,
|
|
61
|
+
compression: Optional[str] = None,
|
|
62
|
+
level: Union[str, int] = "balanced",
|
|
63
|
+
**kwargs
|
|
64
|
+
):
|
|
65
|
+
"""
|
|
66
|
+
Initialize unified archive.
|
|
67
|
+
|
|
68
|
+
Args:
|
|
69
|
+
format_or_path: Format name ("zip", "tar.gz") or file path ("backup.zip")
|
|
70
|
+
format: Explicit format name (overrides auto-detection)
|
|
71
|
+
compression: Compression algorithm ("gzip", "bzip2", "lzma", "zstd", etc.)
|
|
72
|
+
level: Compression level ("fast", "balanced", "best") or int (0-9)
|
|
73
|
+
**kwargs: Additional archive options
|
|
74
|
+
"""
|
|
75
|
+
self.format_or_path = format_or_path
|
|
76
|
+
self.format = format
|
|
77
|
+
self.compression = compression
|
|
78
|
+
self.level = level
|
|
79
|
+
self.kwargs = kwargs
|
|
80
|
+
|
|
81
|
+
# Auto-detect format from path if it looks like a file path
|
|
82
|
+
if isinstance(format_or_path, (str, Path)):
|
|
83
|
+
path = Path(format_or_path)
|
|
84
|
+
# Check if it's a file path (has extension or path separators)
|
|
85
|
+
is_file_path = path.suffix or "/" in str(format_or_path) or "\\" in str(format_or_path)
|
|
86
|
+
|
|
87
|
+
if is_file_path and not format:
|
|
88
|
+
# Looks like a file path - try to detect format from extension
|
|
89
|
+
try:
|
|
90
|
+
detected = get_archiver_for_file(str(path))
|
|
91
|
+
if detected:
|
|
92
|
+
self.format = detected.codec_id
|
|
93
|
+
self.file_path = path
|
|
94
|
+
else:
|
|
95
|
+
# Fallback: extract format from extension
|
|
96
|
+
ext = path.suffix.lstrip('.').lower()
|
|
97
|
+
if ext in ('zip', 'tar', 'gz', 'bz2', 'xz', '7z', 'rar'):
|
|
98
|
+
self.format = ext
|
|
99
|
+
self.file_path = path
|
|
100
|
+
else:
|
|
101
|
+
self.format = "zip" # Default
|
|
102
|
+
self.file_path = path
|
|
103
|
+
except Exception:
|
|
104
|
+
# Fallback: extract format from extension
|
|
105
|
+
ext = path.suffix.lstrip('.').lower()
|
|
106
|
+
self.format = ext if ext else "zip"
|
|
107
|
+
self.file_path = path
|
|
108
|
+
else:
|
|
109
|
+
# Use as format name
|
|
110
|
+
self.format = format or str(format_or_path)
|
|
111
|
+
|
|
112
|
+
# Determine compression level
|
|
113
|
+
if isinstance(level, str):
|
|
114
|
+
level_map = {
|
|
115
|
+
"fast": CompressionLevel.FAST,
|
|
116
|
+
"balanced": CompressionLevel.BALANCED,
|
|
117
|
+
"best": CompressionLevel.BEST,
|
|
118
|
+
}
|
|
119
|
+
self.compression_level = level_map.get(level.lower(), CompressionLevel.BALANCED)
|
|
120
|
+
else:
|
|
121
|
+
self.compression_level = level
|
|
122
|
+
|
|
123
|
+
# Create archiver instance
|
|
124
|
+
self._archiver = self._create_archiver()
|
|
125
|
+
self._archive_file = None
|
|
126
|
+
|
|
127
|
+
def _create_archiver(self):
|
|
128
|
+
"""Create archiver instance based on format."""
|
|
129
|
+
if self.format:
|
|
130
|
+
try:
|
|
131
|
+
archiver = get_archiver_by_id(self.format.lower())
|
|
132
|
+
if archiver:
|
|
133
|
+
return archiver()
|
|
134
|
+
except Exception:
|
|
135
|
+
pass
|
|
136
|
+
|
|
137
|
+
# Fallback to common formats
|
|
138
|
+
format_lower = (self.format or "").lower()
|
|
139
|
+
|
|
140
|
+
if format_lower in ("zip", ".zip"):
|
|
141
|
+
return ZipArchiver()
|
|
142
|
+
elif format_lower in ("tar", ".tar"):
|
|
143
|
+
return TarArchiver()
|
|
144
|
+
elif format_lower in ("tar.gz", ".tar.gz", "targz"):
|
|
145
|
+
return TarArchiver() # TarArchiver handles compression
|
|
146
|
+
elif format_lower in ("tar.bz2", ".tar.bz2", "tarbz2"):
|
|
147
|
+
return TarArchiver()
|
|
148
|
+
elif format_lower in ("tar.xz", ".tar.xz", "tarxz"):
|
|
149
|
+
return TarArchiver()
|
|
150
|
+
else:
|
|
151
|
+
# Try to get from registry
|
|
152
|
+
try:
|
|
153
|
+
return get_archiver_by_id(format_lower)()
|
|
154
|
+
except Exception:
|
|
155
|
+
raise ValueError(f"Unknown archive format: {self.format}")
|
|
156
|
+
|
|
157
|
+
def create(self, archive_path: Union[str, Path], files: List[Union[str, Path]], **options) -> Path:
|
|
158
|
+
"""
|
|
159
|
+
Create archive from files.
|
|
160
|
+
|
|
161
|
+
Args:
|
|
162
|
+
archive_path: Path to create archive at
|
|
163
|
+
files: List of files/directories to archive
|
|
164
|
+
**options: Additional archive options
|
|
165
|
+
|
|
166
|
+
Returns:
|
|
167
|
+
Path to created archive
|
|
168
|
+
"""
|
|
169
|
+
archive_path = Path(archive_path)
|
|
170
|
+
files = [Path(f) for f in files]
|
|
171
|
+
|
|
172
|
+
# Use Archive facade for file operations
|
|
173
|
+
archive = Archive()
|
|
174
|
+
archive.create(files, archive_path, format=self.format or None, **options)
|
|
175
|
+
|
|
176
|
+
return archive_path
|
|
177
|
+
|
|
178
|
+
def extract(self, archive_path: Union[str, Path], output_dir: Union[str, Path], **options) -> Path:
|
|
179
|
+
"""
|
|
180
|
+
Extract archive to directory.
|
|
181
|
+
|
|
182
|
+
Args:
|
|
183
|
+
archive_path: Path to archive
|
|
184
|
+
output_dir: Directory to extract to
|
|
185
|
+
**options: Additional extraction options
|
|
186
|
+
|
|
187
|
+
Returns:
|
|
188
|
+
Output directory path
|
|
189
|
+
"""
|
|
190
|
+
archive_path = Path(archive_path)
|
|
191
|
+
output_dir = Path(output_dir)
|
|
192
|
+
|
|
193
|
+
# Use Archive facade
|
|
194
|
+
archive = Archive()
|
|
195
|
+
archive.extract(archive_path, output_dir, **options)
|
|
196
|
+
|
|
197
|
+
return output_dir
|
|
198
|
+
|
|
199
|
+
def add(self, file_path: Union[str, Path], **options) -> None:
|
|
200
|
+
"""Add file to archive (when used as context manager)."""
|
|
201
|
+
if not hasattr(self, 'file_path') or not self.file_path:
|
|
202
|
+
raise ValueError("No archive file path specified. Initialize with file path for context manager usage.")
|
|
203
|
+
|
|
204
|
+
# Use Archive facade to add file
|
|
205
|
+
archive = Archive()
|
|
206
|
+
archive.add_file(self.file_path, Path(file_path), **options)
|
|
207
|
+
|
|
208
|
+
def list_contents(self) -> List[str]:
|
|
209
|
+
"""List files in archive."""
|
|
210
|
+
if not self._archive_file:
|
|
211
|
+
raise ValueError("Archive not opened")
|
|
212
|
+
return self._archive_file.list_contents()
|
|
213
|
+
|
|
214
|
+
def __enter__(self):
|
|
215
|
+
"""Context manager entry."""
|
|
216
|
+
return self
|
|
217
|
+
|
|
218
|
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
219
|
+
"""Context manager exit."""
|
|
220
|
+
if self._archive_file:
|
|
221
|
+
# Archive files handle their own cleanup
|
|
222
|
+
pass
|
|
223
|
+
|
|
224
|
+
@classmethod
|
|
225
|
+
def create_archive(
|
|
226
|
+
cls,
|
|
227
|
+
archive_path: Union[str, Path],
|
|
228
|
+
files: List[Union[str, Path]],
|
|
229
|
+
format: Optional[str] = None,
|
|
230
|
+
**options
|
|
231
|
+
) -> Path:
|
|
232
|
+
"""
|
|
233
|
+
Static method to create archive.
|
|
234
|
+
|
|
235
|
+
Examples:
|
|
236
|
+
>>> XWArchive.create_archive("files.zip", ["file1.txt", "file2.txt"])
|
|
237
|
+
"""
|
|
238
|
+
# Auto-detect format from path
|
|
239
|
+
archive_path = Path(archive_path)
|
|
240
|
+
if not format:
|
|
241
|
+
format = archive_path.suffix.lstrip('.') or "zip"
|
|
242
|
+
|
|
243
|
+
archive = cls(format, **options)
|
|
244
|
+
return archive.create(archive_path, files, **options)
|
|
245
|
+
|
|
246
|
+
@classmethod
|
|
247
|
+
def extract_archive(
|
|
248
|
+
cls,
|
|
249
|
+
archive_path: Union[str, Path],
|
|
250
|
+
output_dir: Union[str, Path],
|
|
251
|
+
**options
|
|
252
|
+
) -> Path:
|
|
253
|
+
"""
|
|
254
|
+
Static method to extract archive.
|
|
255
|
+
|
|
256
|
+
Examples:
|
|
257
|
+
>>> XWArchive.extract_archive("archive.zip", "output_dir")
|
|
258
|
+
"""
|
|
259
|
+
archive_path = Path(archive_path)
|
|
260
|
+
format = archive_path.suffix.lstrip('.') or "zip"
|
|
261
|
+
|
|
262
|
+
archive = cls(format, **options)
|
|
263
|
+
return archive.extract(archive_path, output_dir, **options)
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
Company: eXonware.com
|
|
5
5
|
Author: Eng. Muhammad AlShehri
|
|
6
6
|
Email: connect@exonware.com
|
|
7
|
-
Version: 0.1.0.
|
|
7
|
+
Version: 0.1.0.3
|
|
8
8
|
Generation Date: November 1, 2025
|
|
9
9
|
|
|
10
10
|
Archive format implementations - COMPREHENSIVE 2025 SUPPORT.
|
|
@@ -33,7 +33,7 @@ Priority 4 (Performance): Efficient format handling
|
|
|
33
33
|
Priority 5 (Extensibility): Easy to add more formats
|
|
34
34
|
"""
|
|
35
35
|
|
|
36
|
-
# Standard formats (
|
|
36
|
+
# Standard formats (stdlib)
|
|
37
37
|
from .zip import ZipArchiver
|
|
38
38
|
from .tar import TarArchiver
|
|
39
39
|
|
|
@@ -132,4 +132,3 @@ __all__ = [
|
|
|
132
132
|
"get_archiver_by_id",
|
|
133
133
|
"register_archive_format",
|
|
134
134
|
]
|
|
135
|
-
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
Company: eXonware.com
|
|
5
5
|
Author: Eng. Muhammad AlShehri
|
|
6
6
|
Email: connect@exonware.com
|
|
7
|
-
Version: 0.1.0.
|
|
7
|
+
Version: 0.1.0.3
|
|
8
8
|
Generation Date: November 1, 2025
|
|
9
9
|
|
|
10
10
|
Brotli (.br) compression format - RANK #6 WEB COMPRESSION.
|
|
@@ -18,6 +18,7 @@ Priority 4 (Performance): Optimized for web
|
|
|
18
18
|
Priority 5 (Extensibility): Lazy installation of brotli
|
|
19
19
|
"""
|
|
20
20
|
|
|
21
|
+
import sys
|
|
21
22
|
import tarfile
|
|
22
23
|
from pathlib import Path
|
|
23
24
|
from typing import Optional
|
|
@@ -25,10 +26,17 @@ from typing import Optional
|
|
|
25
26
|
from ...contracts import IArchiveFormat
|
|
26
27
|
from ...errors import ArchiveError
|
|
27
28
|
|
|
28
|
-
#
|
|
29
|
+
# Optional dependency: brotli
|
|
30
|
+
import importlib.util
|
|
29
31
|
try:
|
|
30
|
-
|
|
31
|
-
|
|
32
|
+
_brotli_spec = importlib.util.find_spec('brotli')
|
|
33
|
+
if _brotli_spec is not None and _brotli_spec.loader is not None:
|
|
34
|
+
import brotli
|
|
35
|
+
else:
|
|
36
|
+
brotli = None # type: ignore
|
|
37
|
+
except (ValueError, AttributeError, ImportError):
|
|
38
|
+
# Handle case where find_spec raises ValueError (e.g., module.__spec__ is None)
|
|
39
|
+
# or other import-related errors
|
|
32
40
|
brotli = None # type: ignore
|
|
33
41
|
|
|
34
42
|
|
|
@@ -119,12 +127,18 @@ class BrotliArchiver(IArchiveFormat):
|
|
|
119
127
|
|
|
120
128
|
extracted = []
|
|
121
129
|
with tarfile.open(fileobj=tar_buffer, mode='r') as tar:
|
|
130
|
+
# Use data filter for Python 3.12+ compatibility (prevents deprecation warning)
|
|
131
|
+
# For older Python versions, filter parameter is not available
|
|
132
|
+
extract_kwargs = {}
|
|
133
|
+
if sys.version_info >= (3, 12):
|
|
134
|
+
extract_kwargs['filter'] = 'data'
|
|
135
|
+
|
|
122
136
|
if members:
|
|
123
137
|
for member in members:
|
|
124
|
-
tar.extract(member, output_dir)
|
|
138
|
+
tar.extract(member, output_dir, **extract_kwargs)
|
|
125
139
|
extracted.append(output_dir / member)
|
|
126
140
|
else:
|
|
127
|
-
tar.extractall(output_dir)
|
|
141
|
+
tar.extractall(output_dir, **extract_kwargs)
|
|
128
142
|
extracted = [output_dir / m.name for m in tar.getmembers()]
|
|
129
143
|
|
|
130
144
|
return extracted
|
|
@@ -148,4 +162,3 @@ class BrotliArchiver(IArchiveFormat):
|
|
|
148
162
|
def add_file(self, archive: Path, file: Path, arcname: Optional[str] = None) -> None:
|
|
149
163
|
"""Not supported - recreate archive instead."""
|
|
150
164
|
raise ArchiveError("Brotli doesn't support append mode. Recreate the archive.")
|
|
151
|
-
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
Company: eXonware.com
|
|
5
5
|
Author: Eng. Muhammad AlShehri
|
|
6
6
|
Email: connect@exonware.com
|
|
7
|
-
Version: 0.1.0.
|
|
7
|
+
Version: 0.1.0.3
|
|
8
8
|
Generation Date: November 1, 2025
|
|
9
9
|
|
|
10
10
|
LZ4 compression format - RANK #7 FASTEST COMPRESSION.
|
|
@@ -18,6 +18,7 @@ Priority 4 (Performance): Best speed (slower ratio)
|
|
|
18
18
|
Priority 5 (Extensibility): Lazy installation of lz4
|
|
19
19
|
"""
|
|
20
20
|
|
|
21
|
+
import sys
|
|
21
22
|
import tarfile
|
|
22
23
|
from pathlib import Path
|
|
23
24
|
from typing import Optional
|
|
@@ -25,10 +26,17 @@ from typing import Optional
|
|
|
25
26
|
from ...contracts import IArchiveFormat
|
|
26
27
|
from ...errors import ArchiveError
|
|
27
28
|
|
|
28
|
-
#
|
|
29
|
+
# Optional dependency: lz4
|
|
30
|
+
import importlib.util
|
|
29
31
|
try:
|
|
30
|
-
|
|
31
|
-
|
|
32
|
+
_lz4_spec = importlib.util.find_spec('lz4')
|
|
33
|
+
if _lz4_spec is not None and _lz4_spec.loader is not None:
|
|
34
|
+
import lz4.frame as lz4
|
|
35
|
+
else:
|
|
36
|
+
lz4 = None # type: ignore
|
|
37
|
+
except (ValueError, AttributeError, ImportError):
|
|
38
|
+
# Handle case where find_spec raises ValueError (e.g., module.__spec__ is None)
|
|
39
|
+
# or other import-related errors
|
|
32
40
|
lz4 = None # type: ignore
|
|
33
41
|
|
|
34
42
|
|
|
@@ -118,12 +126,18 @@ class Lz4Archiver(IArchiveFormat):
|
|
|
118
126
|
|
|
119
127
|
extracted = []
|
|
120
128
|
with tarfile.open(fileobj=tar_buffer, mode='r') as tar:
|
|
129
|
+
# Use data filter for Python 3.12+ compatibility (prevents deprecation warning)
|
|
130
|
+
# For older Python versions, filter parameter is not available
|
|
131
|
+
extract_kwargs = {}
|
|
132
|
+
if sys.version_info >= (3, 12):
|
|
133
|
+
extract_kwargs['filter'] = 'data'
|
|
134
|
+
|
|
121
135
|
if members:
|
|
122
136
|
for member in members:
|
|
123
|
-
tar.extract(member, output_dir)
|
|
137
|
+
tar.extract(member, output_dir, **extract_kwargs)
|
|
124
138
|
extracted.append(output_dir / member)
|
|
125
139
|
else:
|
|
126
|
-
tar.extractall(output_dir)
|
|
140
|
+
tar.extractall(output_dir, **extract_kwargs)
|
|
127
141
|
extracted = [output_dir / m.name for m in tar.getmembers()]
|
|
128
142
|
|
|
129
143
|
return extracted
|
|
@@ -147,4 +161,3 @@ class Lz4Archiver(IArchiveFormat):
|
|
|
147
161
|
def add_file(self, archive: Path, file: Path, arcname: Optional[str] = None) -> None:
|
|
148
162
|
"""Not supported - recreate archive instead."""
|
|
149
163
|
raise ArchiveError("LZ4 doesn't support append mode. Recreate the archive.")
|
|
150
|
-
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
Company: eXonware.com
|
|
5
5
|
Author: Eng. Muhammad AlShehri
|
|
6
6
|
Email: connect@exonware.com
|
|
7
|
-
Version: 0.1.0.
|
|
7
|
+
Version: 0.1.0.3
|
|
8
8
|
Generation Date: November 1, 2025
|
|
9
9
|
|
|
10
10
|
RAR5 archive format implementation - RANK #3 PROPRIETARY COMPRESSION.
|
|
@@ -24,10 +24,17 @@ from typing import Optional
|
|
|
24
24
|
from ...contracts import IArchiveFormat
|
|
25
25
|
from ...errors import ArchiveError
|
|
26
26
|
|
|
27
|
-
#
|
|
27
|
+
# Optional dependency: rarfile
|
|
28
|
+
import importlib.util
|
|
28
29
|
try:
|
|
29
|
-
|
|
30
|
-
|
|
30
|
+
_rarfile_spec = importlib.util.find_spec('rarfile')
|
|
31
|
+
if _rarfile_spec is not None and _rarfile_spec.loader is not None:
|
|
32
|
+
import rarfile
|
|
33
|
+
else:
|
|
34
|
+
rarfile = None # type: ignore
|
|
35
|
+
except (ValueError, AttributeError, ImportError):
|
|
36
|
+
# Handle case where find_spec raises ValueError (e.g., module.__spec__ is None)
|
|
37
|
+
# or other import-related errors
|
|
31
38
|
rarfile = None # type: ignore
|
|
32
39
|
|
|
33
40
|
|
|
@@ -123,4 +130,3 @@ class RarArchiver(IArchiveFormat):
|
|
|
123
130
|
def add_file(self, archive: Path, file: Path, arcname: Optional[str] = None) -> None:
|
|
124
131
|
"""RAR append not supported (requires WinRAR binary)."""
|
|
125
132
|
raise ArchiveError("RAR append requires WinRAR/RAR binary (proprietary).")
|
|
126
|
-
|
|
@@ -4,10 +4,10 @@
|
|
|
4
4
|
Company: eXonware.com
|
|
5
5
|
Author: Eng. Muhammad AlShehri
|
|
6
6
|
Email: connect@exonware.com
|
|
7
|
-
Version: 0.1.0.
|
|
7
|
+
Version: 0.1.0.3
|
|
8
8
|
Generation Date: November 1, 2025
|
|
9
9
|
|
|
10
|
-
7z archive format implementation -
|
|
10
|
+
7z archive format implementation - High compression ratio.
|
|
11
11
|
|
|
12
12
|
**Best overall ratio + AES-256 encryption + solid archiving**
|
|
13
13
|
|
|
@@ -24,10 +24,17 @@ from typing import Optional
|
|
|
24
24
|
from ...contracts import IArchiveFormat
|
|
25
25
|
from ...errors import ArchiveError
|
|
26
26
|
|
|
27
|
-
#
|
|
27
|
+
# Optional dependency: py7zr
|
|
28
|
+
import importlib.util
|
|
28
29
|
try:
|
|
29
|
-
|
|
30
|
-
|
|
30
|
+
_py7zr_spec = importlib.util.find_spec('py7zr')
|
|
31
|
+
if _py7zr_spec is not None and _py7zr_spec.loader is not None:
|
|
32
|
+
import py7zr
|
|
33
|
+
else:
|
|
34
|
+
py7zr = None # type: ignore
|
|
35
|
+
except (ValueError, AttributeError, ImportError):
|
|
36
|
+
# Handle case where find_spec raises ValueError (e.g., module.__spec__ is None)
|
|
37
|
+
# or other import-related errors
|
|
31
38
|
py7zr = None # type: ignore
|
|
32
39
|
|
|
33
40
|
|
|
@@ -133,4 +140,3 @@ class SevenZipArchiver(IArchiveFormat):
|
|
|
133
140
|
zf.write(file, arcname=arcname)
|
|
134
141
|
except Exception as e:
|
|
135
142
|
raise ArchiveError(f"Failed to add file to 7z: {e}")
|
|
136
|
-
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
Company: eXonware.com
|
|
5
5
|
Author: Eng. Muhammad AlShehri
|
|
6
6
|
Email: connect@exonware.com
|
|
7
|
-
Version: 0.1.0.
|
|
7
|
+
Version: 0.1.0.3
|
|
8
8
|
Generation Date: November 1, 2025
|
|
9
9
|
|
|
10
10
|
SquashFS filesystem format - RANK #10 EMBEDDED SYSTEMS.
|
|
@@ -152,4 +152,3 @@ class SquashfsArchiver(IArchiveFormat):
|
|
|
152
152
|
def add_file(self, archive: Path, file: Path, arcname: Optional[str] = None) -> None:
|
|
153
153
|
"""SquashFS doesn't support append (read-only FS)."""
|
|
154
154
|
raise ArchiveError("SquashFS is read-only. Recreate the filesystem to add files.")
|
|
155
|
-
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
Company: eXonware.com
|
|
5
5
|
Author: Eng. Muhammad AlShehri
|
|
6
6
|
Email: connect@exonware.com
|
|
7
|
-
Version: 0.1.0.
|
|
7
|
+
Version: 0.1.0.3
|
|
8
8
|
Generation Date: 30-Oct-2025
|
|
9
9
|
|
|
10
10
|
TAR archive format implementation.
|
|
@@ -16,6 +16,7 @@ Priority 4 (Performance): Efficient TAR operations
|
|
|
16
16
|
Priority 5 (Extensibility): Registered via registry
|
|
17
17
|
"""
|
|
18
18
|
|
|
19
|
+
import sys
|
|
19
20
|
import tarfile
|
|
20
21
|
from pathlib import Path
|
|
21
22
|
from typing import Optional
|
|
@@ -80,10 +81,12 @@ class TarArchiver(IArchiveFormat):
|
|
|
80
81
|
with tarfile.open(archive, 'r:*') as tf:
|
|
81
82
|
if members:
|
|
82
83
|
for member in members:
|
|
83
|
-
tf.extract(member, output_dir)
|
|
84
|
+
tf.extract(member, output_dir, filter='data')
|
|
84
85
|
extracted.append(output_dir / member)
|
|
85
86
|
else:
|
|
86
|
-
|
|
87
|
+
# Use data filter for Python 3.14+ compatibility (prevents deprecation warning)
|
|
88
|
+
# data_filter allows all files but validates paths for security
|
|
89
|
+
tf.extractall(output_dir, filter='data')
|
|
87
90
|
extracted = [output_dir / member.name for member in tf.getmembers()]
|
|
88
91
|
|
|
89
92
|
return extracted
|
|
@@ -94,13 +97,55 @@ class TarArchiver(IArchiveFormat):
|
|
|
94
97
|
return [member.name for member in tf.getmembers()]
|
|
95
98
|
|
|
96
99
|
def add_file(self, archive: Path, file: Path, arcname: Optional[str] = None) -> None:
|
|
97
|
-
"""Add file to TAR archive."""
|
|
100
|
+
"""Add file to TAR archive (supports compressed archives)."""
|
|
98
101
|
arcname = arcname or file.name
|
|
99
102
|
|
|
100
|
-
#
|
|
103
|
+
# Uncompressed TAR - direct append
|
|
101
104
|
if archive.suffix == '.tar':
|
|
102
105
|
with tarfile.open(archive, 'a') as tf:
|
|
103
106
|
tf.add(file, arcname=arcname)
|
|
104
107
|
else:
|
|
105
|
-
|
|
106
|
-
|
|
108
|
+
# Compressed TAR - decompress, append, recompress
|
|
109
|
+
import tempfile
|
|
110
|
+
import shutil
|
|
111
|
+
|
|
112
|
+
# Determine compression type
|
|
113
|
+
suffix = "".join(archive.suffixes).lower()
|
|
114
|
+
compression = None
|
|
115
|
+
if '.gz' in suffix or '.tgz' in suffix:
|
|
116
|
+
compression = 'gz'
|
|
117
|
+
elif '.bz2' in suffix or '.tbz' in suffix:
|
|
118
|
+
compression = 'bz2'
|
|
119
|
+
elif '.xz' in suffix or '.txz' in suffix:
|
|
120
|
+
compression = 'xz'
|
|
121
|
+
|
|
122
|
+
if compression is None:
|
|
123
|
+
raise ValueError(f"Unsupported compression format: {suffix}")
|
|
124
|
+
|
|
125
|
+
# Create temporary uncompressed TAR
|
|
126
|
+
with tempfile.NamedTemporaryFile(suffix='.tar', delete=False) as tmp_tar:
|
|
127
|
+
tmp_tar_path = Path(tmp_tar.name)
|
|
128
|
+
|
|
129
|
+
try:
|
|
130
|
+
# Extract existing archive to temporary TAR
|
|
131
|
+
if archive.exists():
|
|
132
|
+
with tarfile.open(archive, 'r:*') as source_tf:
|
|
133
|
+
with tarfile.open(tmp_tar_path, 'w') as tmp_tf:
|
|
134
|
+
for member in source_tf.getmembers():
|
|
135
|
+
tmp_tf.addfile(member, source_tf.extractfile(member))
|
|
136
|
+
|
|
137
|
+
# Add new file to temporary TAR
|
|
138
|
+
with tarfile.open(tmp_tar_path, 'a') as tmp_tf:
|
|
139
|
+
tmp_tf.add(file, arcname=arcname)
|
|
140
|
+
|
|
141
|
+
# Recompress to original archive
|
|
142
|
+
mode_map = {'gz': 'w:gz', 'bz2': 'w:bz2', 'xz': 'w:xz'}
|
|
143
|
+
with tarfile.open(tmp_tar_path, 'r') as tmp_tf:
|
|
144
|
+
with tarfile.open(archive, mode_map[compression]) as compressed_tf:
|
|
145
|
+
for member in tmp_tf.getmembers():
|
|
146
|
+
compressed_tf.addfile(member, tmp_tf.extractfile(member))
|
|
147
|
+
|
|
148
|
+
finally:
|
|
149
|
+
# Clean up temporary file
|
|
150
|
+
if tmp_tar_path.exists():
|
|
151
|
+
tmp_tar_path.unlink()
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
Company: eXonware.com
|
|
5
5
|
Author: Eng. Muhammad AlShehri
|
|
6
6
|
Email: connect@exonware.com
|
|
7
|
-
Version: 0.1.0.
|
|
7
|
+
Version: 0.1.0.3
|
|
8
8
|
Generation Date: November 1, 2025
|
|
9
9
|
|
|
10
10
|
WIM (Windows Imaging) format - RANK #9 SYSTEM IMAGES.
|
|
@@ -24,10 +24,17 @@ from typing import Optional
|
|
|
24
24
|
from ...contracts import IArchiveFormat
|
|
25
25
|
from ...errors import ArchiveError
|
|
26
26
|
|
|
27
|
-
#
|
|
27
|
+
# Optional dependency: wimlib
|
|
28
|
+
import importlib.util
|
|
28
29
|
try:
|
|
29
|
-
|
|
30
|
-
|
|
30
|
+
_wimlib_spec = importlib.util.find_spec('wimlib')
|
|
31
|
+
if _wimlib_spec is not None and _wimlib_spec.loader is not None:
|
|
32
|
+
import wimlib
|
|
33
|
+
else:
|
|
34
|
+
wimlib = None # type: ignore
|
|
35
|
+
except (ValueError, AttributeError, ImportError):
|
|
36
|
+
# Handle case where find_spec raises ValueError (e.g., module.__spec__ is None)
|
|
37
|
+
# or other import-related errors
|
|
31
38
|
wimlib = None # type: ignore
|
|
32
39
|
|
|
33
40
|
|
|
@@ -132,4 +139,3 @@ class WimArchiver(IArchiveFormat):
|
|
|
132
139
|
wim.write()
|
|
133
140
|
except Exception as e:
|
|
134
141
|
raise ArchiveError(f"Failed to add image to WIM: {e}")
|
|
135
|
-
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
Company: eXonware.com
|
|
5
5
|
Author: Eng. Muhammad AlShehri
|
|
6
6
|
Email: connect@exonware.com
|
|
7
|
-
Version: 0.1.0.
|
|
7
|
+
Version: 0.1.0.3
|
|
8
8
|
Generation Date: 30-Oct-2025
|
|
9
9
|
|
|
10
10
|
ZIP archive format implementation.
|
|
@@ -86,4 +86,3 @@ class ZipArchiver(IArchiveFormat):
|
|
|
86
86
|
arcname = arcname or file.name
|
|
87
87
|
with zipfile.ZipFile(archive, 'a') as zf:
|
|
88
88
|
zf.write(file, arcname=arcname)
|
|
89
|
-
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
Company: eXonware.com
|
|
5
5
|
Author: Eng. Muhammad AlShehri
|
|
6
6
|
Email: connect@exonware.com
|
|
7
|
-
Version: 0.1.0.
|
|
7
|
+
Version: 0.1.0.3
|
|
8
8
|
Generation Date: November 1, 2025
|
|
9
9
|
|
|
10
10
|
ZPAQ journaled compression format - RANK #8 EXTREME COMPRESSION.
|
|
@@ -150,4 +150,3 @@ class ZpaqArchiver(IArchiveFormat):
|
|
|
150
150
|
raise ArchiveError(f"ZPAQ add failed: {e.stderr}")
|
|
151
151
|
except Exception as e:
|
|
152
152
|
raise ArchiveError(f"Failed to add file to zpaq: {e}")
|
|
153
|
-
|