exonware-xwsystem 0.1.0.1__py3-none-any.whl → 0.1.0.4__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.4.dist-info}/METADATA +71 -4
- exonware_xwsystem-0.1.0.4.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.4.dist-info}/WHEEL +0 -0
- {exonware_xwsystem-0.1.0.1.dist-info → exonware_xwsystem-0.1.0.4.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,443 @@
|
|
|
1
|
+
#exonware/xwsystem/src/exonware/xwsystem/io/indexing/facade.py
|
|
2
|
+
"""
|
|
3
|
+
Company: eXonware.com
|
|
4
|
+
Author: Eng. Muhammad AlShehri
|
|
5
|
+
Email: connect@exonware.com
|
|
6
|
+
Version: 0.1.0.4
|
|
7
|
+
Generation Date: January 2026
|
|
8
|
+
|
|
9
|
+
XWIndex - Unified Indexing Facade
|
|
10
|
+
|
|
11
|
+
Simplified API for indexing line-oriented files (JSONL/NDJSON):
|
|
12
|
+
- Build indexes with line offsets
|
|
13
|
+
- ID-based indexing
|
|
14
|
+
- Paging support
|
|
15
|
+
- Streaming operations
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
from pathlib import Path
|
|
19
|
+
from typing import Any, Optional, Callable, List, Iterator
|
|
20
|
+
|
|
21
|
+
from ..data_operations import (
|
|
22
|
+
ADataOperations,
|
|
23
|
+
JsonIndex,
|
|
24
|
+
JsonIndexMeta,
|
|
25
|
+
JsonMatchFn,
|
|
26
|
+
JsonUpdateFn,
|
|
27
|
+
)
|
|
28
|
+
from ..serialization.parsers.registry import get_best_available_parser
|
|
29
|
+
from ...config.logging_setup import get_logger
|
|
30
|
+
|
|
31
|
+
logger = get_logger(__name__)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class JsonlDataOperations(ADataOperations):
|
|
35
|
+
"""Concrete implementation for JSONL/NDJSON files."""
|
|
36
|
+
|
|
37
|
+
def stream_read(
|
|
38
|
+
self,
|
|
39
|
+
file_path: str | Path,
|
|
40
|
+
match: JsonMatchFn,
|
|
41
|
+
path: Optional[List[object]] = None,
|
|
42
|
+
encoding: str = "utf-8",
|
|
43
|
+
) -> Any:
|
|
44
|
+
"""Return the first record that matches the predicate."""
|
|
45
|
+
parser = get_best_available_parser()
|
|
46
|
+
|
|
47
|
+
with open(file_path, "r", encoding=encoding) as f:
|
|
48
|
+
for line in f:
|
|
49
|
+
line = line.strip()
|
|
50
|
+
if not line:
|
|
51
|
+
continue
|
|
52
|
+
|
|
53
|
+
try:
|
|
54
|
+
obj = parser.loads(line)
|
|
55
|
+
if match(obj):
|
|
56
|
+
return obj
|
|
57
|
+
except Exception:
|
|
58
|
+
continue
|
|
59
|
+
|
|
60
|
+
return None
|
|
61
|
+
|
|
62
|
+
def stream_update(
|
|
63
|
+
self,
|
|
64
|
+
file_path: str | Path,
|
|
65
|
+
match: JsonMatchFn,
|
|
66
|
+
updater: JsonUpdateFn,
|
|
67
|
+
*,
|
|
68
|
+
encoding: str = "utf-8",
|
|
69
|
+
newline: str = "\n",
|
|
70
|
+
atomic: bool = True,
|
|
71
|
+
) -> int:
|
|
72
|
+
"""Stream-copy the backing store, applying updater to matching records."""
|
|
73
|
+
import tempfile
|
|
74
|
+
import shutil
|
|
75
|
+
|
|
76
|
+
parser = get_best_available_parser()
|
|
77
|
+
updated_count = 0
|
|
78
|
+
|
|
79
|
+
file_path = Path(file_path)
|
|
80
|
+
temp_path = file_path.with_suffix(file_path.suffix + ".tmp")
|
|
81
|
+
|
|
82
|
+
try:
|
|
83
|
+
with open(file_path, "r", encoding=encoding) as infile, \
|
|
84
|
+
open(temp_path, "w", encoding=encoding) as outfile:
|
|
85
|
+
|
|
86
|
+
for line in infile:
|
|
87
|
+
original_line = line
|
|
88
|
+
line = line.strip()
|
|
89
|
+
|
|
90
|
+
if not line:
|
|
91
|
+
outfile.write(original_line)
|
|
92
|
+
continue
|
|
93
|
+
|
|
94
|
+
try:
|
|
95
|
+
obj = parser.loads(line)
|
|
96
|
+
if match(obj):
|
|
97
|
+
updated_obj = updater(obj)
|
|
98
|
+
updated_line = parser.dumps(updated_obj) + newline
|
|
99
|
+
outfile.write(updated_line)
|
|
100
|
+
updated_count += 1
|
|
101
|
+
else:
|
|
102
|
+
outfile.write(original_line)
|
|
103
|
+
except Exception:
|
|
104
|
+
outfile.write(original_line)
|
|
105
|
+
|
|
106
|
+
if atomic:
|
|
107
|
+
shutil.move(str(temp_path), str(file_path))
|
|
108
|
+
else:
|
|
109
|
+
shutil.copy2(str(temp_path), str(file_path))
|
|
110
|
+
temp_path.unlink()
|
|
111
|
+
|
|
112
|
+
except Exception as e:
|
|
113
|
+
if temp_path.exists():
|
|
114
|
+
temp_path.unlink()
|
|
115
|
+
raise
|
|
116
|
+
|
|
117
|
+
return updated_count
|
|
118
|
+
|
|
119
|
+
def build_index(
|
|
120
|
+
self,
|
|
121
|
+
file_path: str | Path,
|
|
122
|
+
*,
|
|
123
|
+
encoding: str = "utf-8",
|
|
124
|
+
id_field: str | None = None,
|
|
125
|
+
max_id_index: int | None = None,
|
|
126
|
+
) -> JsonIndex:
|
|
127
|
+
"""Build an index structure suitable for random access and paging."""
|
|
128
|
+
import os
|
|
129
|
+
import time
|
|
130
|
+
|
|
131
|
+
parser = get_best_available_parser()
|
|
132
|
+
file_path = Path(file_path)
|
|
133
|
+
|
|
134
|
+
line_offsets: List[int] = []
|
|
135
|
+
id_index: Optional[dict[str, int]] = {} if id_field else None
|
|
136
|
+
|
|
137
|
+
stat = file_path.stat()
|
|
138
|
+
size = stat.st_size
|
|
139
|
+
mtime = stat.st_mtime
|
|
140
|
+
|
|
141
|
+
with open(file_path, "rb") as f:
|
|
142
|
+
current_offset = 0
|
|
143
|
+
|
|
144
|
+
while True:
|
|
145
|
+
line_start = current_offset
|
|
146
|
+
line = f.readline()
|
|
147
|
+
|
|
148
|
+
if not line:
|
|
149
|
+
break
|
|
150
|
+
|
|
151
|
+
current_offset = f.tell()
|
|
152
|
+
|
|
153
|
+
# Skip empty lines
|
|
154
|
+
if not line.strip():
|
|
155
|
+
continue
|
|
156
|
+
|
|
157
|
+
line_offsets.append(line_start)
|
|
158
|
+
line_idx = len(line_offsets) - 1
|
|
159
|
+
|
|
160
|
+
# Build ID index if requested
|
|
161
|
+
if id_field and id_index is not None:
|
|
162
|
+
if max_id_index is None or len(id_index) < max_id_index:
|
|
163
|
+
try:
|
|
164
|
+
obj = parser.loads(line)
|
|
165
|
+
if isinstance(obj, dict) and id_field in obj:
|
|
166
|
+
id_val = str(obj[id_field])
|
|
167
|
+
id_index[id_val] = line_idx
|
|
168
|
+
except Exception:
|
|
169
|
+
pass
|
|
170
|
+
|
|
171
|
+
meta = JsonIndexMeta(
|
|
172
|
+
path=str(file_path),
|
|
173
|
+
size=size,
|
|
174
|
+
mtime=mtime,
|
|
175
|
+
version=1
|
|
176
|
+
)
|
|
177
|
+
|
|
178
|
+
return JsonIndex(
|
|
179
|
+
meta=meta,
|
|
180
|
+
line_offsets=line_offsets,
|
|
181
|
+
id_index=id_index if id_index else None
|
|
182
|
+
)
|
|
183
|
+
|
|
184
|
+
def indexed_get_by_line(
|
|
185
|
+
self,
|
|
186
|
+
file_path: str | Path,
|
|
187
|
+
line_number: int,
|
|
188
|
+
*,
|
|
189
|
+
encoding: str = "utf-8",
|
|
190
|
+
index: Optional[JsonIndex] = None,
|
|
191
|
+
) -> Any:
|
|
192
|
+
"""Random-access a specific record by line number."""
|
|
193
|
+
parser = get_best_available_parser()
|
|
194
|
+
|
|
195
|
+
if index is None:
|
|
196
|
+
index = self.build_index(file_path, encoding=encoding)
|
|
197
|
+
|
|
198
|
+
if line_number < 0 or line_number >= len(index.line_offsets):
|
|
199
|
+
return None
|
|
200
|
+
|
|
201
|
+
offset = index.line_offsets[line_number]
|
|
202
|
+
|
|
203
|
+
with open(file_path, "rb") as f:
|
|
204
|
+
f.seek(offset)
|
|
205
|
+
line = f.readline().decode(encoding).strip()
|
|
206
|
+
|
|
207
|
+
if not line:
|
|
208
|
+
return None
|
|
209
|
+
|
|
210
|
+
try:
|
|
211
|
+
return parser.loads(line)
|
|
212
|
+
except Exception:
|
|
213
|
+
return None
|
|
214
|
+
|
|
215
|
+
def indexed_get_by_id(
|
|
216
|
+
self,
|
|
217
|
+
file_path: str | Path,
|
|
218
|
+
id_value: Any,
|
|
219
|
+
*,
|
|
220
|
+
encoding: str = "utf-8",
|
|
221
|
+
id_field: str = "id",
|
|
222
|
+
index: Optional[JsonIndex] = None,
|
|
223
|
+
) -> Any:
|
|
224
|
+
"""Random-access a record by logical ID."""
|
|
225
|
+
if index is None:
|
|
226
|
+
index = self.build_index(file_path, encoding=encoding, id_field=id_field)
|
|
227
|
+
|
|
228
|
+
if index.id_index is None:
|
|
229
|
+
# Fallback to linear scan
|
|
230
|
+
return self.stream_read(
|
|
231
|
+
file_path,
|
|
232
|
+
match=lambda obj: isinstance(obj, dict) and obj.get(id_field) == id_value,
|
|
233
|
+
encoding=encoding
|
|
234
|
+
)
|
|
235
|
+
|
|
236
|
+
id_str = str(id_value)
|
|
237
|
+
if id_str not in index.id_index:
|
|
238
|
+
return None
|
|
239
|
+
|
|
240
|
+
line_number = index.id_index[id_str]
|
|
241
|
+
return self.indexed_get_by_line(file_path, line_number, encoding=encoding, index=index)
|
|
242
|
+
|
|
243
|
+
def get_page(
|
|
244
|
+
self,
|
|
245
|
+
file_path: str | Path,
|
|
246
|
+
page_number: int,
|
|
247
|
+
page_size: int,
|
|
248
|
+
*,
|
|
249
|
+
encoding: str = "utf-8",
|
|
250
|
+
index: Optional[JsonIndex] = None,
|
|
251
|
+
) -> List[Any]:
|
|
252
|
+
"""Return a page of records using index."""
|
|
253
|
+
if index is None:
|
|
254
|
+
index = self.build_index(file_path, encoding=encoding)
|
|
255
|
+
|
|
256
|
+
start_idx = page_number * page_size
|
|
257
|
+
end_idx = start_idx + page_size
|
|
258
|
+
|
|
259
|
+
results = []
|
|
260
|
+
for line_number in range(start_idx, min(end_idx, len(index.line_offsets))):
|
|
261
|
+
record = self.indexed_get_by_line(file_path, line_number, encoding=encoding, index=index)
|
|
262
|
+
if record is not None:
|
|
263
|
+
results.append(record)
|
|
264
|
+
|
|
265
|
+
return results
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
class XWIndex:
|
|
269
|
+
"""
|
|
270
|
+
Unified indexing facade - simple API for indexing line-oriented files.
|
|
271
|
+
|
|
272
|
+
Examples:
|
|
273
|
+
>>> # Simple indexing
|
|
274
|
+
>>> index = XWIndex("data.jsonl") # Auto-detects JSONL
|
|
275
|
+
>>> index = XWIndex("data.ndjson", format="jsonl")
|
|
276
|
+
|
|
277
|
+
>>> # Build index
|
|
278
|
+
>>> index.build() # Builds line offsets + optional ID index
|
|
279
|
+
|
|
280
|
+
>>> # Query
|
|
281
|
+
>>> record = index.get_by_line(42)
|
|
282
|
+
>>> record = index.get_by_id("user_123")
|
|
283
|
+
|
|
284
|
+
>>> # Paging
|
|
285
|
+
>>> page = index.get_page(page=1, size=10)
|
|
286
|
+
|
|
287
|
+
>>> # Streaming
|
|
288
|
+
>>> for record in index.stream(match=lambda r: r["active"]):
|
|
289
|
+
... print(record)
|
|
290
|
+
"""
|
|
291
|
+
|
|
292
|
+
def __init__(
|
|
293
|
+
self,
|
|
294
|
+
file_path: str | Path,
|
|
295
|
+
*,
|
|
296
|
+
format: Optional[str] = None,
|
|
297
|
+
encoding: str = "utf-8",
|
|
298
|
+
id_field: Optional[str] = None,
|
|
299
|
+
):
|
|
300
|
+
"""
|
|
301
|
+
Initialize unified index.
|
|
302
|
+
|
|
303
|
+
Args:
|
|
304
|
+
file_path: Path to line-oriented file (JSONL/NDJSON)
|
|
305
|
+
format: File format ("jsonl", "ndjson") - auto-detected if None
|
|
306
|
+
encoding: File encoding (default: "utf-8")
|
|
307
|
+
id_field: Optional field name for ID-based indexing
|
|
308
|
+
"""
|
|
309
|
+
self.file_path = Path(file_path)
|
|
310
|
+
self.format = format or self._detect_format()
|
|
311
|
+
self.encoding = encoding
|
|
312
|
+
self.id_field = id_field
|
|
313
|
+
|
|
314
|
+
self._operations = JsonlDataOperations()
|
|
315
|
+
self._index: Optional[JsonIndex] = None
|
|
316
|
+
|
|
317
|
+
def _detect_format(self) -> str:
|
|
318
|
+
"""Auto-detect format from file extension."""
|
|
319
|
+
ext = self.file_path.suffix.lower()
|
|
320
|
+
if ext in (".jsonl", ".ndjson", ".jsonlines"):
|
|
321
|
+
return "jsonl"
|
|
322
|
+
return "jsonl" # Default to JSONL
|
|
323
|
+
|
|
324
|
+
def build(
|
|
325
|
+
self,
|
|
326
|
+
*,
|
|
327
|
+
id_field: Optional[str] = None,
|
|
328
|
+
max_id_index: Optional[int] = None,
|
|
329
|
+
force: bool = False,
|
|
330
|
+
) -> JsonIndex:
|
|
331
|
+
"""
|
|
332
|
+
Build index structure.
|
|
333
|
+
|
|
334
|
+
Args:
|
|
335
|
+
id_field: Field name for ID-based indexing (uses instance id_field if None)
|
|
336
|
+
max_id_index: Maximum number of IDs to index
|
|
337
|
+
force: Force rebuild even if index exists
|
|
338
|
+
|
|
339
|
+
Returns:
|
|
340
|
+
JsonIndex object
|
|
341
|
+
"""
|
|
342
|
+
if self._index is None or force:
|
|
343
|
+
self._index = self._operations.build_index(
|
|
344
|
+
self.file_path,
|
|
345
|
+
encoding=self.encoding,
|
|
346
|
+
id_field=id_field or self.id_field,
|
|
347
|
+
max_id_index=max_id_index,
|
|
348
|
+
)
|
|
349
|
+
|
|
350
|
+
return self._index
|
|
351
|
+
|
|
352
|
+
def get_by_line(self, line_number: int) -> Any:
|
|
353
|
+
"""Get record by line number (0-based)."""
|
|
354
|
+
if self._index is None:
|
|
355
|
+
self.build()
|
|
356
|
+
|
|
357
|
+
return self._operations.indexed_get_by_line(
|
|
358
|
+
self.file_path,
|
|
359
|
+
line_number,
|
|
360
|
+
encoding=self.encoding,
|
|
361
|
+
index=self._index,
|
|
362
|
+
)
|
|
363
|
+
|
|
364
|
+
def get_by_id(self, id_value: Any, id_field: Optional[str] = None) -> Any:
|
|
365
|
+
"""Get record by ID."""
|
|
366
|
+
if self._index is None:
|
|
367
|
+
self.build(id_field=id_field or self.id_field)
|
|
368
|
+
|
|
369
|
+
return self._operations.indexed_get_by_id(
|
|
370
|
+
self.file_path,
|
|
371
|
+
id_value,
|
|
372
|
+
encoding=self.encoding,
|
|
373
|
+
id_field=id_field or self.id_field or "id",
|
|
374
|
+
index=self._index,
|
|
375
|
+
)
|
|
376
|
+
|
|
377
|
+
def get_page(self, page: int = 0, size: int = 10) -> List[Any]:
|
|
378
|
+
"""Get a page of records."""
|
|
379
|
+
if self._index is None:
|
|
380
|
+
self.build()
|
|
381
|
+
|
|
382
|
+
return self._operations.get_page(
|
|
383
|
+
self.file_path,
|
|
384
|
+
page,
|
|
385
|
+
size,
|
|
386
|
+
encoding=self.encoding,
|
|
387
|
+
index=self._index,
|
|
388
|
+
)
|
|
389
|
+
|
|
390
|
+
def stream(self, match: Optional[Callable[[Any], bool]] = None) -> Iterator[Any]:
|
|
391
|
+
"""
|
|
392
|
+
Stream records matching predicate.
|
|
393
|
+
|
|
394
|
+
Args:
|
|
395
|
+
match: Optional predicate function (returns all records if None)
|
|
396
|
+
"""
|
|
397
|
+
parser = get_best_available_parser()
|
|
398
|
+
|
|
399
|
+
with open(self.file_path, "r", encoding=self.encoding) as f:
|
|
400
|
+
for line in f:
|
|
401
|
+
line = line.strip()
|
|
402
|
+
if not line:
|
|
403
|
+
continue
|
|
404
|
+
|
|
405
|
+
try:
|
|
406
|
+
obj = parser.loads(line)
|
|
407
|
+
if match is None or match(obj):
|
|
408
|
+
yield obj
|
|
409
|
+
except Exception:
|
|
410
|
+
continue
|
|
411
|
+
|
|
412
|
+
def update(
|
|
413
|
+
self,
|
|
414
|
+
match: Callable[[Any], bool],
|
|
415
|
+
updater: Callable[[Any], Any],
|
|
416
|
+
*,
|
|
417
|
+
atomic: bool = True,
|
|
418
|
+
) -> int:
|
|
419
|
+
"""
|
|
420
|
+
Update records matching predicate.
|
|
421
|
+
|
|
422
|
+
Args:
|
|
423
|
+
match: Predicate function to match records
|
|
424
|
+
updater: Function to update matched records
|
|
425
|
+
atomic: Use atomic file replacement
|
|
426
|
+
|
|
427
|
+
Returns:
|
|
428
|
+
Number of updated records
|
|
429
|
+
"""
|
|
430
|
+
return self._operations.stream_update(
|
|
431
|
+
self.file_path,
|
|
432
|
+
match,
|
|
433
|
+
updater,
|
|
434
|
+
encoding=self.encoding,
|
|
435
|
+
atomic=atomic,
|
|
436
|
+
)
|
|
437
|
+
|
|
438
|
+
@property
|
|
439
|
+
def index(self) -> Optional[JsonIndex]:
|
|
440
|
+
"""Get current index (builds if needed)."""
|
|
441
|
+
if self._index is None:
|
|
442
|
+
self.build()
|
|
443
|
+
return self._index
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
#exonware/xwsystem/src/exonware/xwsystem/io/path_parser.py
|
|
4
|
+
|
|
5
|
+
Generic Path Parser for xwsystem.
|
|
6
|
+
|
|
7
|
+
Provides thread-safe path parsing with caching that can be used by any library.
|
|
8
|
+
|
|
9
|
+
Company: eXonware.com
|
|
10
|
+
Author: Eng. Muhammad AlShehri
|
|
11
|
+
Email: connect@exonware.com
|
|
12
|
+
Version: 0.1.0.4
|
|
13
|
+
Generation Date: 26-Jan-2025
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
import threading
|
|
17
|
+
from typing import List
|
|
18
|
+
from exonware.xwsystem.caching import create_cache
|
|
19
|
+
from exonware.xwsystem import get_logger
|
|
20
|
+
|
|
21
|
+
logger = get_logger(__name__)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class PathParser:
|
|
25
|
+
"""
|
|
26
|
+
Thread-safe path parser with caching.
|
|
27
|
+
|
|
28
|
+
Performance Optimization:
|
|
29
|
+
- Uses xwsystem create_cache() for 10-50x faster cache operations
|
|
30
|
+
- Automatic LRU eviction when capacity is reached
|
|
31
|
+
- Thread-safe by default (via xwsystem cache)
|
|
32
|
+
|
|
33
|
+
Can be used by any library for path parsing operations.
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
def __init__(self, max_cache_size: int = 1024, namespace: str = "xwsystem"):
|
|
37
|
+
"""
|
|
38
|
+
Initialize path parser.
|
|
39
|
+
|
|
40
|
+
Args:
|
|
41
|
+
max_cache_size: Maximum cache size
|
|
42
|
+
namespace: Cache namespace
|
|
43
|
+
"""
|
|
44
|
+
# Use xwsystem optimized cache for 10-50x faster operations
|
|
45
|
+
# Provides automatic LRU eviction and thread-safety
|
|
46
|
+
self._cache = create_cache(
|
|
47
|
+
capacity=max_cache_size,
|
|
48
|
+
namespace=namespace,
|
|
49
|
+
name='path_parser_cache'
|
|
50
|
+
)
|
|
51
|
+
self._max_cache_size = max_cache_size
|
|
52
|
+
# Lock for potential future stats tracking if needed
|
|
53
|
+
self._lock = threading.RLock()
|
|
54
|
+
|
|
55
|
+
def parse(self, path: str) -> List[str]:
|
|
56
|
+
"""
|
|
57
|
+
Parse a path string into parts (O(1) cache lookup with xwsystem cache).
|
|
58
|
+
|
|
59
|
+
Args:
|
|
60
|
+
path: Path string to parse
|
|
61
|
+
|
|
62
|
+
Returns:
|
|
63
|
+
List of path parts
|
|
64
|
+
"""
|
|
65
|
+
# Check xwsystem cache first (O(1) with automatic LRU eviction)
|
|
66
|
+
cached_parts = self._cache.get(path)
|
|
67
|
+
if cached_parts is not None:
|
|
68
|
+
return cached_parts
|
|
69
|
+
|
|
70
|
+
# Cache miss - parse path
|
|
71
|
+
parts = self._parse_path(path)
|
|
72
|
+
|
|
73
|
+
# Cache the result (automatic LRU eviction when full)
|
|
74
|
+
self._cache.put(path, parts)
|
|
75
|
+
|
|
76
|
+
return parts
|
|
77
|
+
|
|
78
|
+
def _parse_path(self, path: str) -> List[str]:
|
|
79
|
+
"""
|
|
80
|
+
Internal path parsing logic.
|
|
81
|
+
|
|
82
|
+
Args:
|
|
83
|
+
path: Path string to parse
|
|
84
|
+
|
|
85
|
+
Returns:
|
|
86
|
+
List of path parts
|
|
87
|
+
"""
|
|
88
|
+
if not path:
|
|
89
|
+
return []
|
|
90
|
+
|
|
91
|
+
# Simple dot-separated path parsing
|
|
92
|
+
return [part for part in path.split('.') if part]
|
|
93
|
+
|
|
94
|
+
def clear_cache(self) -> None:
|
|
95
|
+
"""Clear the path parser cache."""
|
|
96
|
+
# Clear cache (implementation depends on cache type)
|
|
97
|
+
if hasattr(self._cache, 'clear'):
|
|
98
|
+
self._cache.clear()
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
+
#exonware/xwsystem/src/exonware/xwsystem/io/serialization/__init__.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.4
|
|
6
7
|
Generation Date: November 2, 2025
|
|
7
8
|
|
|
8
9
|
Serialization module - 29+ serialization formats with I→A→XW pattern.
|
|
@@ -23,6 +24,16 @@ from .base import ASerialization, ASchemaRegistry
|
|
|
23
24
|
# Registry
|
|
24
25
|
from .registry import SerializationRegistry, get_serialization_registry
|
|
25
26
|
|
|
27
|
+
# Universal options
|
|
28
|
+
from .universal_options import (
|
|
29
|
+
map_universal_options,
|
|
30
|
+
get_supported_universal_options,
|
|
31
|
+
validate_universal_options,
|
|
32
|
+
get_all_supported_formats,
|
|
33
|
+
get_format_option_info,
|
|
34
|
+
UniversalOption,
|
|
35
|
+
)
|
|
36
|
+
|
|
26
37
|
# NOTE: Schema Registry moved to exonware-xwschema
|
|
27
38
|
# from .schema_registry import (
|
|
28
39
|
# SchemaInfo,
|
|
@@ -106,7 +117,7 @@ for _serializer_class in [
|
|
|
106
117
|
pass # Skip if already registered or missing dependencies
|
|
107
118
|
|
|
108
119
|
# NOTE: xwformats auto-discovery removed per DEV_GUIDELINES.md
|
|
109
|
-
# "NO TRY/EXCEPT FOR IMPORTS" - Users
|
|
120
|
+
# "NO TRY/EXCEPT FOR IMPORTS" - Users explicitly import xwformats when needed:
|
|
110
121
|
# from exonware.xwformats import AvroSerializer, ProtobufSerializer, ...
|
|
111
122
|
# xwformats auto-registers its formats on import
|
|
112
123
|
|
|
@@ -160,6 +171,14 @@ __all__ = [
|
|
|
160
171
|
"detect_format",
|
|
161
172
|
"AutoSerializer",
|
|
162
173
|
"XWSerializer",
|
|
174
|
+
|
|
175
|
+
# Universal options
|
|
176
|
+
"map_universal_options",
|
|
177
|
+
"get_supported_universal_options",
|
|
178
|
+
"validate_universal_options",
|
|
179
|
+
"get_all_supported_formats",
|
|
180
|
+
"get_format_option_info",
|
|
181
|
+
"UniversalOption",
|
|
163
182
|
]
|
|
164
183
|
|
|
165
184
|
# NOTE: Enterprise formats available in exonware-xwformats:
|
|
@@ -169,4 +188,3 @@ __all__ = [
|
|
|
169
188
|
# - Binary: UBJSON (1 format)
|
|
170
189
|
# Total: 16 enterprise formats (~87 MB)
|
|
171
190
|
# Install with: pip install exonware-xwformats
|
|
172
|
-
|