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
|
@@ -16,7 +16,7 @@ lazy, paged, and atomic access features without re-implementing I/O logic.
|
|
|
16
16
|
Company: eXonware.com
|
|
17
17
|
Author: Eng. Muhammad AlShehri
|
|
18
18
|
Email: connect@exonware.com
|
|
19
|
-
Version: 0.1.0.
|
|
19
|
+
Version: 0.1.0.3
|
|
20
20
|
Generation Date: 15-Dec-2025
|
|
21
21
|
"""
|
|
22
22
|
|
|
@@ -28,6 +28,8 @@ from typing import Any, Callable, Optional
|
|
|
28
28
|
from abc import ABC, abstractmethod
|
|
29
29
|
import json
|
|
30
30
|
import os
|
|
31
|
+
import platform
|
|
32
|
+
import sys
|
|
31
33
|
import tempfile
|
|
32
34
|
import multiprocessing as mp
|
|
33
35
|
from concurrent.futures import ProcessPoolExecutor, as_completed
|
|
@@ -55,11 +57,8 @@ def _process_chunk_worker(args: tuple[int, int, int, str, str, str | None, int |
|
|
|
55
57
|
lines_processed = 0
|
|
56
58
|
|
|
57
59
|
# Import parser in worker process (can't pickle serializer)
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
parser = get_best_available_parser()
|
|
61
|
-
except ImportError:
|
|
62
|
-
import json as parser
|
|
60
|
+
from exonware.xwsystem.io.serialization.parsers.registry import get_best_available_parser
|
|
61
|
+
parser = get_best_available_parser()
|
|
63
62
|
|
|
64
63
|
try:
|
|
65
64
|
with open(file_path_str, "rb") as f:
|
|
@@ -99,7 +98,7 @@ def _process_chunk_worker(args: tuple[int, int, int, str, str, str | None, int |
|
|
|
99
98
|
id_val = str(obj[id_field_arg])
|
|
100
99
|
chunk_id_index[id_val] = line_idx
|
|
101
100
|
except Exception:
|
|
102
|
-
# Skip invalid lines (
|
|
101
|
+
# Skip invalid lines (fallback indexing)
|
|
103
102
|
pass
|
|
104
103
|
|
|
105
104
|
lines_processed += 1
|
|
@@ -353,7 +352,7 @@ class NDJSONDataOperations(ADataOperations):
|
|
|
353
352
|
try:
|
|
354
353
|
tmp_path.unlink()
|
|
355
354
|
except OSError:
|
|
356
|
-
#
|
|
355
|
+
# Cleanup attempt; do not mask original error.
|
|
357
356
|
logger.debug("Failed to cleanup temp file %s", tmp_path)
|
|
358
357
|
|
|
359
358
|
# ------------------------------------------------------------------
|
|
@@ -433,11 +432,8 @@ class NDJSONDataOperations(ADataOperations):
|
|
|
433
432
|
mtime = target.stat().st_mtime
|
|
434
433
|
|
|
435
434
|
# Cache parser instance (matches example code pattern)
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
parser = get_best_available_parser()
|
|
439
|
-
except ImportError:
|
|
440
|
-
import json as parser
|
|
435
|
+
from exonware.xwsystem.io.serialization.parsers.registry import get_best_available_parser
|
|
436
|
+
parser = get_best_available_parser()
|
|
441
437
|
|
|
442
438
|
offset = 0
|
|
443
439
|
with target.open("rb") as f:
|
|
@@ -461,7 +457,7 @@ class NDJSONDataOperations(ADataOperations):
|
|
|
461
457
|
if max_id_index is None or len(id_index) < max_id_index:
|
|
462
458
|
id_index[id_val] = line_no
|
|
463
459
|
except Exception:
|
|
464
|
-
# Index
|
|
460
|
+
# Index is robust to bad lines.
|
|
465
461
|
# Skip invalid lines silently for performance
|
|
466
462
|
pass
|
|
467
463
|
|
|
@@ -492,9 +488,14 @@ class NDJSONDataOperations(ADataOperations):
|
|
|
492
488
|
# ProcessPoolExecutor max_workers limit is 61 on Windows
|
|
493
489
|
file_size_mb = file_path.stat().st_size / 1_048_576 # 1024 * 1024
|
|
494
490
|
calculated_workers = int(file_size_mb / 10) # 1 worker per 10MB
|
|
495
|
-
# Cap at 61 (ProcessPoolExecutor limit) or CPU count, whichever is higher
|
|
496
491
|
cpu_count = mp.cpu_count()
|
|
497
|
-
|
|
492
|
+
# Windows has a hard limit of 61 workers for ProcessPoolExecutor
|
|
493
|
+
# Unix/Linux systems have no such limit
|
|
494
|
+
# Use Python's native platform module for cross-platform detection
|
|
495
|
+
if platform.system() == 'Windows':
|
|
496
|
+
num_workers = max(cpu_count, min(61, calculated_workers))
|
|
497
|
+
else:
|
|
498
|
+
num_workers = max(cpu_count, calculated_workers)
|
|
498
499
|
|
|
499
500
|
file_size = file_path.stat().st_size
|
|
500
501
|
chunk_size_bytes = chunk_size_mb * 1_048_576 # 1024 * 1024
|
|
@@ -559,10 +560,10 @@ class NDJSONDataOperations(ADataOperations):
|
|
|
559
560
|
|
|
560
561
|
# Merge results (process in order by chunk_id)
|
|
561
562
|
if build_line_offsets:
|
|
562
|
-
# Optimize: Pre-calculate total size for
|
|
563
|
+
# Optimize: Pre-calculate total size for memory allocation
|
|
563
564
|
total_offsets = sum(len(offsets) if offsets else 0 for offsets, _ in chunk_results_dict.values())
|
|
564
565
|
if total_offsets > 0:
|
|
565
|
-
# Pre-allocate list for
|
|
566
|
+
# Pre-allocate list for performance
|
|
566
567
|
line_offsets = [0] * total_offsets
|
|
567
568
|
current_idx = 0
|
|
568
569
|
else:
|
|
@@ -742,5 +743,3 @@ __all__ = [
|
|
|
742
743
|
"ADataOperations",
|
|
743
744
|
"NDJSONDataOperations",
|
|
744
745
|
]
|
|
745
|
-
|
|
746
|
-
|
exonware/xwsystem/io/defs.py
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
+
#exonware/xwsystem/src/exonware/xwsystem/io/defs.py
|
|
1
2
|
"""
|
|
2
3
|
Company: eXonware.com
|
|
3
4
|
Author: Eng. Muhammad AlShehri
|
|
4
5
|
Email: connect@exonware.com
|
|
5
|
-
Version: 0.1.0.
|
|
6
|
+
Version: 0.1.0.3
|
|
6
7
|
Generation Date: 30-Oct-2025
|
|
7
8
|
|
|
8
9
|
IO module definitions - ALL enums and types in ONE place.
|
|
@@ -117,7 +118,7 @@ class PagingMode(Enum):
|
|
|
117
118
|
LINE = "line" # Page by line counts
|
|
118
119
|
RECORD = "record" # Page by record boundaries
|
|
119
120
|
SMART = "smart" # Adaptive paging
|
|
120
|
-
AUTO = "auto" # Auto-detect
|
|
121
|
+
AUTO = "auto" # Auto-detect strategy
|
|
121
122
|
|
|
122
123
|
|
|
123
124
|
# From file
|
|
@@ -221,7 +222,7 @@ class CompressionLevel(Enum):
|
|
|
221
222
|
"""Compression level presets."""
|
|
222
223
|
FAST = 1 # Fastest compression
|
|
223
224
|
BALANCED = 6 # Balance speed/size
|
|
224
|
-
BEST = 9 #
|
|
225
|
+
BEST = 9 # Maximum compression
|
|
225
226
|
|
|
226
227
|
|
|
227
228
|
|
exonware/xwsystem/io/errors.py
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
+
#exonware/xwsystem/src/exonware/xwsystem/io/errors.py
|
|
1
2
|
"""
|
|
2
3
|
Company: eXonware.com
|
|
3
4
|
Author: Eng. Muhammad AlShehri
|
|
4
5
|
Email: connect@exonware.com
|
|
5
|
-
Version: 0.1.0.
|
|
6
|
+
Version: 0.1.0.3
|
|
6
7
|
Generation Date: 30-Oct-2025
|
|
7
8
|
|
|
8
9
|
IO module errors - ALL exceptions in ONE place.
|
|
@@ -10,7 +11,7 @@ IO module errors - ALL exceptions in ONE place.
|
|
|
10
11
|
Consolidated from all submodules for maintainability.
|
|
11
12
|
"""
|
|
12
13
|
|
|
13
|
-
from typing import Any, Optional
|
|
14
|
+
from typing import Any, Optional
|
|
14
15
|
from pathlib import Path
|
|
15
16
|
|
|
16
17
|
|
exonware/xwsystem/io/facade.py
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
+
#exonware/xwsystem/src/exonware/xwsystem/io/facade.py
|
|
1
2
|
"""
|
|
2
3
|
Company: eXonware.com
|
|
3
4
|
Author: Eng. Muhammad AlShehri
|
|
4
5
|
Email: connect@exonware.com
|
|
5
|
-
Version: 0.1.0.
|
|
6
|
+
Version: 0.1.0.3
|
|
6
7
|
Generation Date: September 04, 2025
|
|
7
8
|
|
|
8
9
|
XWIO - Main facade for all I/O operations (MANDATORY facade pattern).
|
|
@@ -10,12 +11,14 @@ XWIO - Main facade for all I/O operations (MANDATORY facade pattern).
|
|
|
10
11
|
This is the primary entry point for the IO module, following GUIDELINES_DEV.md.
|
|
11
12
|
"""
|
|
12
13
|
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
13
16
|
import os
|
|
14
17
|
import shutil
|
|
15
18
|
import tempfile
|
|
16
19
|
import time
|
|
17
20
|
from pathlib import Path
|
|
18
|
-
from typing import Any, Optional,
|
|
21
|
+
from typing import Any, Optional, BinaryIO, TextIO
|
|
19
22
|
|
|
20
23
|
from .base import AUnifiedIO
|
|
21
24
|
from .contracts import FileMode, FileType, PathType, OperationResult, LockType, IUnifiedIO
|
|
@@ -54,7 +57,7 @@ class XWIO(AUnifiedIO):
|
|
|
54
57
|
- Delegates to specialized components
|
|
55
58
|
"""
|
|
56
59
|
|
|
57
|
-
def __init__(self, file_path: Optional[
|
|
60
|
+
def __init__(self, file_path: Optional[str | Path] = None, **config):
|
|
58
61
|
"""
|
|
59
62
|
Initialize XWIO facade.
|
|
60
63
|
|
|
@@ -81,7 +84,7 @@ class XWIO(AUnifiedIO):
|
|
|
81
84
|
# FILE OPERATIONS
|
|
82
85
|
# ============================================================================
|
|
83
86
|
|
|
84
|
-
def open_file(self, file_path: Optional[
|
|
87
|
+
def open_file(self, file_path: Optional[str | Path] = None, mode: FileMode = FileMode.READ) -> None:
|
|
85
88
|
"""Open file with validation and monitoring."""
|
|
86
89
|
target_path = Path(file_path) if file_path else self.file_path
|
|
87
90
|
if not target_path:
|
|
@@ -100,7 +103,7 @@ class XWIO(AUnifiedIO):
|
|
|
100
103
|
self.file_path = target_path
|
|
101
104
|
logger.debug(f"File opened: {target_path} in mode {mode.value}")
|
|
102
105
|
|
|
103
|
-
def open_stream(self, stream:
|
|
106
|
+
def open_stream(self, stream: BinaryIO | TextIO) -> None:
|
|
104
107
|
"""Open stream for stream operations."""
|
|
105
108
|
self._stream = stream
|
|
106
109
|
self._position = 0
|
|
@@ -110,12 +113,12 @@ class XWIO(AUnifiedIO):
|
|
|
110
113
|
# ABSTRACT METHOD IMPLEMENTATIONS (from AFile)
|
|
111
114
|
# ============================================================================
|
|
112
115
|
|
|
113
|
-
#
|
|
116
|
+
# Delegate to file operations
|
|
114
117
|
def open(self, mode: FileMode = FileMode.READ) -> None:
|
|
115
118
|
"""Open file with validation and monitoring (alias for open_file())."""
|
|
116
119
|
self.open_file(mode=mode)
|
|
117
120
|
|
|
118
|
-
def read(self, size: Optional[int] = None) ->
|
|
121
|
+
def read(self, size: Optional[int] = None) -> str | bytes:
|
|
119
122
|
"""
|
|
120
123
|
Read from file (implements AFile abstract method).
|
|
121
124
|
|
|
@@ -133,7 +136,7 @@ class XWIO(AUnifiedIO):
|
|
|
133
136
|
# File operation
|
|
134
137
|
return self.read_file(size)
|
|
135
138
|
|
|
136
|
-
def write(self, data:
|
|
139
|
+
def write(self, data: str | bytes) -> int:
|
|
137
140
|
"""
|
|
138
141
|
Write to file (implements AFile abstract method).
|
|
139
142
|
|
|
@@ -151,26 +154,7 @@ class XWIO(AUnifiedIO):
|
|
|
151
154
|
# File operation
|
|
152
155
|
return self.write_file(data)
|
|
153
156
|
|
|
154
|
-
def
|
|
155
|
-
"""
|
|
156
|
-
Save data to specific path (implements AFile abstract method).
|
|
157
|
-
|
|
158
|
-
Args:
|
|
159
|
-
path: Target file path
|
|
160
|
-
data: Data to save
|
|
161
|
-
**kwargs: Additional options
|
|
162
|
-
|
|
163
|
-
Returns:
|
|
164
|
-
True if successful, False otherwise
|
|
165
|
-
"""
|
|
166
|
-
try:
|
|
167
|
-
self.save(data, file_path=path, **kwargs)
|
|
168
|
-
return True
|
|
169
|
-
except Exception as e:
|
|
170
|
-
logger.error(f"Failed to save data to {path}: {e}")
|
|
171
|
-
return False
|
|
172
|
-
|
|
173
|
-
def to_file(self, path: Union[str, Path], **kwargs) -> bool:
|
|
157
|
+
def to_file(self, path: str | Path, **kwargs) -> bool:
|
|
174
158
|
"""
|
|
175
159
|
Write current data to file (implements AFile abstract method).
|
|
176
160
|
|
|
@@ -198,7 +182,7 @@ class XWIO(AUnifiedIO):
|
|
|
198
182
|
logger.warning("No data to write to file")
|
|
199
183
|
return False
|
|
200
184
|
|
|
201
|
-
def from_file(self, path:
|
|
185
|
+
def from_file(self, path: str | Path, **kwargs) -> XWIO:
|
|
202
186
|
"""
|
|
203
187
|
Load data from file and return new XWIO instance (implements AFile abstract method).
|
|
204
188
|
|
|
@@ -212,8 +196,17 @@ class XWIO(AUnifiedIO):
|
|
|
212
196
|
new_instance = XWIO(file_path=path, **self.__dict__.get('_config', {}))
|
|
213
197
|
new_instance._current_data = new_instance.load(file_path=path, **kwargs)
|
|
214
198
|
return new_instance
|
|
199
|
+
|
|
200
|
+
def load_from(self, path: str | Path, **kwargs) -> Any:
|
|
201
|
+
"""
|
|
202
|
+
Load data from a specific path (convenience alias).
|
|
203
|
+
|
|
204
|
+
This matches the facade-style API used in core tests:
|
|
205
|
+
- `load_from(path)` delegates to `load(file_path=...)`.
|
|
206
|
+
"""
|
|
207
|
+
return self.load(file_path=path, **kwargs)
|
|
215
208
|
|
|
216
|
-
def read_file(self, size: Optional[int] = None) ->
|
|
209
|
+
def read_file(self, size: Optional[int] = None) -> str | bytes:
|
|
217
210
|
"""Read from file with validation."""
|
|
218
211
|
if not self.is_open():
|
|
219
212
|
raise ValueError("File not open")
|
|
@@ -226,7 +219,7 @@ class XWIO(AUnifiedIO):
|
|
|
226
219
|
|
|
227
220
|
return data
|
|
228
221
|
|
|
229
|
-
def write_file(self, data:
|
|
222
|
+
def write_file(self, data: str | bytes) -> int:
|
|
230
223
|
"""Write to file with validation."""
|
|
231
224
|
if not self.is_open():
|
|
232
225
|
raise ValueError("File not open")
|
|
@@ -238,14 +231,20 @@ class XWIO(AUnifiedIO):
|
|
|
238
231
|
return self._handle.write(data)
|
|
239
232
|
|
|
240
233
|
|
|
241
|
-
def save(self, data: Any, file_path: Optional[
|
|
242
|
-
"""
|
|
234
|
+
def save(self, data: Any, file_path: Optional[str | Path] = None) -> bool:
|
|
235
|
+
"""
|
|
236
|
+
Save data to file with atomic operations.
|
|
237
|
+
|
|
238
|
+
Returns:
|
|
239
|
+
True if successful.
|
|
240
|
+
"""
|
|
243
241
|
target_path = Path(file_path) if file_path else self.file_path
|
|
244
242
|
if not target_path:
|
|
245
243
|
raise ValueError("No file path specified")
|
|
246
244
|
|
|
247
245
|
if self.validate_paths:
|
|
248
|
-
|
|
246
|
+
# Saving is a write operation; allow creating new files in valid directories.
|
|
247
|
+
self._path_validator.validate_path(target_path, for_writing=True, create_dirs=True)
|
|
249
248
|
|
|
250
249
|
if self.validate_data:
|
|
251
250
|
self._data_validator.validate_data(data)
|
|
@@ -253,18 +252,21 @@ class XWIO(AUnifiedIO):
|
|
|
253
252
|
with performance_monitor("file_save"):
|
|
254
253
|
if self.use_atomic_operations:
|
|
255
254
|
# Use atomic file writer
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
writer.write(data
|
|
259
|
-
|
|
255
|
+
if isinstance(data, bytes):
|
|
256
|
+
with AtomicFileWriter(target_path, mode="wb", backup=self.auto_backup) as writer:
|
|
257
|
+
writer.write(data)
|
|
258
|
+
else:
|
|
259
|
+
# Treat as text (most common path for XWIO facade)
|
|
260
|
+
with AtomicFileWriter(target_path, mode="w", encoding="utf-8", backup=self.auto_backup) as writer:
|
|
260
261
|
writer.write(data)
|
|
261
262
|
else:
|
|
262
263
|
# Direct write
|
|
263
264
|
target_path.parent.mkdir(parents=True, exist_ok=True)
|
|
264
265
|
with open(target_path, 'wb' if isinstance(data, bytes) else 'w') as f:
|
|
265
266
|
f.write(data)
|
|
267
|
+
return True
|
|
266
268
|
|
|
267
|
-
def load(self, file_path: Optional[
|
|
269
|
+
def load(self, file_path: Optional[str | Path] = None) -> Any:
|
|
268
270
|
"""Load data from file with validation."""
|
|
269
271
|
target_path = Path(file_path) if file_path else self.file_path
|
|
270
272
|
if not target_path:
|
|
@@ -342,7 +344,7 @@ class XWIO(AUnifiedIO):
|
|
|
342
344
|
# ATOMIC OPERATIONS
|
|
343
345
|
# ============================================================================
|
|
344
346
|
|
|
345
|
-
def atomic_write(self, file_path:
|
|
347
|
+
def atomic_write(self, file_path: str | Path, data: str | bytes,
|
|
346
348
|
backup: bool = True) -> OperationResult:
|
|
347
349
|
"""Atomically write data to file."""
|
|
348
350
|
target_path = Path(file_path)
|
|
@@ -365,7 +367,7 @@ class XWIO(AUnifiedIO):
|
|
|
365
367
|
logger.error(f"Atomic write failed for {target_path}: {e}")
|
|
366
368
|
return OperationResult.FAILED
|
|
367
369
|
|
|
368
|
-
def atomic_copy(self, source:
|
|
370
|
+
def atomic_copy(self, source: str | Path, destination: str | Path) -> OperationResult:
|
|
369
371
|
"""Atomically copy file."""
|
|
370
372
|
source_path = Path(source)
|
|
371
373
|
dest_path = Path(destination)
|
|
@@ -385,7 +387,7 @@ class XWIO(AUnifiedIO):
|
|
|
385
387
|
logger.error(f"Atomic copy failed from {source_path} to {dest_path}: {e}")
|
|
386
388
|
return OperationResult.FAILED
|
|
387
389
|
|
|
388
|
-
def atomic_move(self, source:
|
|
390
|
+
def atomic_move(self, source: str | Path, destination: str | Path) -> OperationResult:
|
|
389
391
|
"""Atomically move file."""
|
|
390
392
|
source_path = Path(source)
|
|
391
393
|
dest_path = Path(destination)
|
|
@@ -411,7 +413,7 @@ class XWIO(AUnifiedIO):
|
|
|
411
413
|
logger.error(f"Atomic move failed from {source_path} to {dest_path}: {e}")
|
|
412
414
|
return OperationResult.FAILED
|
|
413
415
|
|
|
414
|
-
def atomic_delete(self, file_path:
|
|
416
|
+
def atomic_delete(self, file_path: str | Path, backup: bool = True) -> OperationResult:
|
|
415
417
|
"""Atomically delete file."""
|
|
416
418
|
target_path = Path(file_path)
|
|
417
419
|
|
|
@@ -431,7 +433,7 @@ class XWIO(AUnifiedIO):
|
|
|
431
433
|
logger.error(f"Atomic delete failed for {target_path}: {e}")
|
|
432
434
|
return OperationResult.FAILED
|
|
433
435
|
|
|
434
|
-
def atomic_rename(self, old_path:
|
|
436
|
+
def atomic_rename(self, old_path: str | Path, new_path: str | Path) -> OperationResult:
|
|
435
437
|
"""Atomically rename file."""
|
|
436
438
|
old_file = Path(old_path)
|
|
437
439
|
new_file = Path(new_path)
|
|
@@ -455,7 +457,7 @@ class XWIO(AUnifiedIO):
|
|
|
455
457
|
# BACKUP OPERATIONS
|
|
456
458
|
# ============================================================================
|
|
457
459
|
|
|
458
|
-
def create_backup(self, source:
|
|
460
|
+
def create_backup(self, source: str | Path, backup_dir: str | Path) -> Optional[Path]:
|
|
459
461
|
"""Create backup of file or directory."""
|
|
460
462
|
source_path = Path(source)
|
|
461
463
|
backup_path = Path(backup_dir)
|
|
@@ -484,7 +486,7 @@ class XWIO(AUnifiedIO):
|
|
|
484
486
|
logger.error(f"Backup creation failed for {source_path}: {e}")
|
|
485
487
|
return None
|
|
486
488
|
|
|
487
|
-
def restore_backup(self, backup_path:
|
|
489
|
+
def restore_backup(self, backup_path: str | Path, target: str | Path) -> OperationResult:
|
|
488
490
|
"""Restore from backup."""
|
|
489
491
|
backup = Path(backup_path)
|
|
490
492
|
target_path = Path(target)
|
|
@@ -553,7 +555,7 @@ class XWIO(AUnifiedIO):
|
|
|
553
555
|
# ASYNC OPERATIONS
|
|
554
556
|
# ============================================================================
|
|
555
557
|
|
|
556
|
-
async def aread(self, size: Optional[int] = None) ->
|
|
558
|
+
async def aread(self, size: Optional[int] = None) -> str | bytes:
|
|
557
559
|
"""Async read operation."""
|
|
558
560
|
if not self._async_stream:
|
|
559
561
|
raise ValueError("Async stream not initialized")
|
|
@@ -561,7 +563,7 @@ class XWIO(AUnifiedIO):
|
|
|
561
563
|
with performance_monitor("async_read"):
|
|
562
564
|
return await self._async_stream.read(size)
|
|
563
565
|
|
|
564
|
-
async def awrite(self, data:
|
|
566
|
+
async def awrite(self, data: str | bytes) -> int:
|
|
565
567
|
"""Async write operation."""
|
|
566
568
|
if not self._async_stream:
|
|
567
569
|
raise ValueError("Async stream not initialized")
|
|
@@ -640,7 +642,7 @@ class XWIO(AUnifiedIO):
|
|
|
640
642
|
# CODEC INTEGRATION (UniversalCodecRegistry)
|
|
641
643
|
# ============================================================================
|
|
642
644
|
|
|
643
|
-
def serialize(self, data: Any, format_id: str, **options) ->
|
|
645
|
+
def serialize(self, data: Any, format_id: str, **options) -> bytes | str:
|
|
644
646
|
"""
|
|
645
647
|
Serialize data using specified format.
|
|
646
648
|
|
|
@@ -669,7 +671,7 @@ class XWIO(AUnifiedIO):
|
|
|
669
671
|
|
|
670
672
|
return codec.encode(data, options=options or None)
|
|
671
673
|
|
|
672
|
-
def deserialize(self, data:
|
|
674
|
+
def deserialize(self, data: bytes | str, format_id: str, **options) -> Any:
|
|
673
675
|
"""
|
|
674
676
|
Deserialize data using specified format.
|
|
675
677
|
|
|
@@ -698,7 +700,7 @@ class XWIO(AUnifiedIO):
|
|
|
698
700
|
|
|
699
701
|
return codec.decode(data, options=options or None)
|
|
700
702
|
|
|
701
|
-
def save_serialized(self, data: Any, file_path:
|
|
703
|
+
def save_serialized(self, data: Any, file_path: str | Path, format_id: Optional[str] = None, **options) -> None:
|
|
702
704
|
"""
|
|
703
705
|
Serialize and save data to file.
|
|
704
706
|
|
|
@@ -742,7 +744,7 @@ class XWIO(AUnifiedIO):
|
|
|
742
744
|
else:
|
|
743
745
|
path.write_text(repr_data, encoding='utf-8')
|
|
744
746
|
|
|
745
|
-
def load_serialized(self, file_path:
|
|
747
|
+
def load_serialized(self, file_path: str | Path, format_id: Optional[str] = None, **options) -> Any:
|
|
746
748
|
"""
|
|
747
749
|
Load and deserialize data from file.
|
|
748
750
|
|
|
@@ -789,7 +791,7 @@ class XWIO(AUnifiedIO):
|
|
|
789
791
|
# CONVENIENCE ALIASES (User-friendly API)
|
|
790
792
|
# ============================================================================
|
|
791
793
|
|
|
792
|
-
def load_as(self, file_path:
|
|
794
|
+
def load_as(self, file_path: str | Path, format_id: str, **options) -> Any:
|
|
793
795
|
"""
|
|
794
796
|
Load data from file using specified format (convenience alias).
|
|
795
797
|
|
|
@@ -810,16 +812,30 @@ class XWIO(AUnifiedIO):
|
|
|
810
812
|
"""
|
|
811
813
|
return self.load_serialized(file_path, format_id=format_id, **options)
|
|
812
814
|
|
|
813
|
-
def save_as(
|
|
815
|
+
def save_as(
|
|
816
|
+
self,
|
|
817
|
+
file_path: str | Path,
|
|
818
|
+
data: Any,
|
|
819
|
+
format_id: Optional[str] = None,
|
|
820
|
+
**options,
|
|
821
|
+
) -> bool:
|
|
814
822
|
"""
|
|
815
|
-
Save data to
|
|
823
|
+
Save data to a specific path.
|
|
824
|
+
|
|
825
|
+
This method intentionally supports **two** usage patterns:
|
|
826
|
+
|
|
827
|
+
1) **File-like save** (AFile-style):
|
|
828
|
+
- `save_as(path, data)` → writes raw text/bytes to the target path
|
|
829
|
+
|
|
830
|
+
2) **Serialization save** (format-aware):
|
|
831
|
+
- `save_as(path, data, format_id="json", ...)` → serializes and writes via codec registry
|
|
816
832
|
|
|
817
|
-
|
|
833
|
+
If you want a more explicit serialization name, prefer `write_as(...)`.
|
|
818
834
|
|
|
819
835
|
Args:
|
|
820
836
|
file_path: Path to save to
|
|
821
837
|
data: Data to serialize
|
|
822
|
-
format_id:
|
|
838
|
+
format_id: Optional format identifier (e.g., 'json', 'yaml', 'xml')
|
|
823
839
|
**options: Format-specific options
|
|
824
840
|
|
|
825
841
|
Examples:
|
|
@@ -827,9 +843,19 @@ class XWIO(AUnifiedIO):
|
|
|
827
843
|
>>> io.save_as("config.yml", config_dict, "yaml", indent=2)
|
|
828
844
|
>>> io.save_as("users.xml", users_list, "xml", pretty=True)
|
|
829
845
|
"""
|
|
830
|
-
|
|
846
|
+
try:
|
|
847
|
+
if format_id is None:
|
|
848
|
+
# Raw save (string/bytes) with path validation + atomic ops
|
|
849
|
+
return bool(self.save(data, file_path=file_path))
|
|
850
|
+
|
|
851
|
+
# Format-aware save via codec registry
|
|
852
|
+
self.save_serialized(data, file_path, format_id=format_id, **options)
|
|
853
|
+
return True
|
|
854
|
+
except Exception as e:
|
|
855
|
+
logger.error(f"Failed to save data to {file_path}: {e}")
|
|
856
|
+
return False
|
|
831
857
|
|
|
832
|
-
def read_as(self, file_path:
|
|
858
|
+
def read_as(self, file_path: str | Path, format_id: Optional[str] = None, **options) -> Any:
|
|
833
859
|
"""
|
|
834
860
|
Read and deserialize file (auto-detect or explicit format).
|
|
835
861
|
|
|
@@ -850,7 +876,7 @@ class XWIO(AUnifiedIO):
|
|
|
850
876
|
"""
|
|
851
877
|
return self.load_serialized(file_path, format_id=format_id, **options)
|
|
852
878
|
|
|
853
|
-
def write_as(self, file_path:
|
|
879
|
+
def write_as(self, file_path: str | Path, data: Any, format_id: Optional[str] = None, **options) -> None:
|
|
854
880
|
"""
|
|
855
881
|
Serialize and write to file (auto-detect or explicit format).
|
|
856
882
|
|
|
@@ -902,7 +928,7 @@ class XWIO(AUnifiedIO):
|
|
|
902
928
|
|
|
903
929
|
# Close async stream
|
|
904
930
|
if self._async_stream:
|
|
905
|
-
# Note:
|
|
931
|
+
# Note: Called in async context
|
|
906
932
|
logger.warning("Async stream still open - call aclose() in async context")
|
|
907
933
|
|
|
908
934
|
# Cleanup temporary resources
|
|
@@ -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
|
Base classes for file operations.
|
|
@@ -20,7 +20,7 @@ Priority 5 (Extensibility): Ready for new file types
|
|
|
20
20
|
|
|
21
21
|
from abc import ABC, abstractmethod
|
|
22
22
|
from pathlib import Path
|
|
23
|
-
from typing import
|
|
23
|
+
from typing import Optional, Any
|
|
24
24
|
|
|
25
25
|
from ..contracts import IFileSource, IPagedSource, IPagingStrategy
|
|
26
26
|
from ..defs import PagingMode
|
|
@@ -38,7 +38,7 @@ class AFileSource(IFileSource, ABC):
|
|
|
38
38
|
Provides common file source functionality.
|
|
39
39
|
"""
|
|
40
40
|
|
|
41
|
-
def __init__(self, path:
|
|
41
|
+
def __init__(self, path: str | Path, mode: str = 'rb', encoding: Optional[str] = None):
|
|
42
42
|
"""Initialize file source."""
|
|
43
43
|
self._path = Path(path)
|
|
44
44
|
self._mode = mode
|
|
@@ -64,12 +64,12 @@ class AFileSource(IFileSource, ABC):
|
|
|
64
64
|
self._path.unlink()
|
|
65
65
|
|
|
66
66
|
@abstractmethod
|
|
67
|
-
def read(self, **options) ->
|
|
67
|
+
def read(self, **options) -> bytes | str:
|
|
68
68
|
"""Read entire file content."""
|
|
69
69
|
pass
|
|
70
70
|
|
|
71
71
|
@abstractmethod
|
|
72
|
-
def write(self, data:
|
|
72
|
+
def write(self, data: bytes | str, **options) -> None:
|
|
73
73
|
"""Write entire content to file."""
|
|
74
74
|
pass
|
|
75
75
|
|
|
@@ -84,7 +84,7 @@ class APagedSource(IPagedSource, ABC):
|
|
|
84
84
|
|
|
85
85
|
def __init__(
|
|
86
86
|
self,
|
|
87
|
-
path:
|
|
87
|
+
path: str | Path,
|
|
88
88
|
mode: str = 'rb',
|
|
89
89
|
encoding: Optional[str] = None,
|
|
90
90
|
paging_strategy: Optional[IPagingStrategy] = None
|
|
@@ -116,7 +116,7 @@ class APagedSource(IPagedSource, ABC):
|
|
|
116
116
|
return -1
|
|
117
117
|
return self._path.stat().st_size
|
|
118
118
|
|
|
119
|
-
def read_page(self, page: int, page_size: int, **options) ->
|
|
119
|
+
def read_page(self, page: int, page_size: int, **options) -> bytes | str:
|
|
120
120
|
"""Read specific page using strategy."""
|
|
121
121
|
return self._paging_strategy.read_page(
|
|
122
122
|
self._path,
|
|
@@ -138,7 +138,7 @@ class APagedSource(IPagedSource, ABC):
|
|
|
138
138
|
)
|
|
139
139
|
|
|
140
140
|
@abstractmethod
|
|
141
|
-
def read_chunk(self, offset: int, size: int, **options) ->
|
|
141
|
+
def read_chunk(self, offset: int, size: int, **options) -> bytes | str:
|
|
142
142
|
"""Read chunk by byte offset."""
|
|
143
143
|
pass
|
|
144
144
|
|
|
@@ -146,4 +146,3 @@ class APagedSource(IPagedSource, ABC):
|
|
|
146
146
|
def iter_chunks(self, chunk_size: int, **options):
|
|
147
147
|
"""Iterate over chunks."""
|
|
148
148
|
pass
|
|
149
|
-
|
|
@@ -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
|
File Format Conversion - Convert between compatible formats.
|
|
@@ -22,7 +22,7 @@ Priority 5 (Extensibility): Works with any registered codec
|
|
|
22
22
|
"""
|
|
23
23
|
|
|
24
24
|
from pathlib import Path
|
|
25
|
-
from typing import Any, Optional
|
|
25
|
+
from typing import Any, Optional
|
|
26
26
|
|
|
27
27
|
from ..codec.base import get_global_registry
|
|
28
28
|
from ..contracts import ICodec
|
|
@@ -241,4 +241,3 @@ def convert_file(
|
|
|
241
241
|
>>> convert_file(Path("data.json"), Path("data.yaml"))
|
|
242
242
|
"""
|
|
243
243
|
_converter.convert_file(source_path, target_path, source_format, target_format, **options)
|
|
244
|
-
|