exonware-xwsystem 0.0.1.411__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 +73 -391
- 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 +279 -14
- 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 +199 -0
- 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 +65 -33
- exonware/xwsystem/io/serialization/formats/text/json5.py +8 -4
- exonware/xwsystem/io/serialization/formats/text/jsonlines.py +113 -25
- 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 +16 -0
- exonware/xwsystem/io/serialization/parsers/base.py +60 -0
- exonware/xwsystem/io/serialization/parsers/hybrid_parser.py +62 -0
- exonware/xwsystem/io/serialization/parsers/msgspec_parser.py +48 -0
- exonware/xwsystem/io/serialization/parsers/orjson_direct_parser.py +54 -0
- exonware/xwsystem/io/serialization/parsers/orjson_parser.py +62 -0
- exonware/xwsystem/io/serialization/parsers/pysimdjson_parser.py +55 -0
- exonware/xwsystem/io/serialization/parsers/rapidjson_parser.py +53 -0
- exonware/xwsystem/io/serialization/parsers/registry.py +91 -0
- exonware/xwsystem/io/serialization/parsers/standard.py +44 -0
- exonware/xwsystem/io/serialization/parsers/ujson_parser.py +53 -0
- 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 +139 -480
- 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 +4 -4
- {exonware_xwsystem-0.0.1.411.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/caching/USAGE_GUIDE.md +0 -779
- 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.0.1.411.dist-info/RECORD +0 -274
- {exonware_xwsystem-0.0.1.411.dist-info → exonware_xwsystem-0.1.0.3.dist-info}/WHEEL +0 -0
- {exonware_xwsystem-0.0.1.411.dist-info → exonware_xwsystem-0.1.0.3.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
#exonware/xwsystem/src/exonware/xwsystem/io/serialization/parsers/hybrid_parser.py
|
|
2
|
+
"""Hybrid parser: msgspec for reading, orjson for writing (direct, no try/catch)."""
|
|
3
|
+
|
|
4
|
+
from typing import Any
|
|
5
|
+
import msgspec # Direct import for reading
|
|
6
|
+
import orjson # Direct import for writing
|
|
7
|
+
|
|
8
|
+
from .base import AJsonParser
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class HybridParser(AJsonParser):
|
|
12
|
+
"""
|
|
13
|
+
Hybrid parser - fastest combination:
|
|
14
|
+
- msgspec for reading (1.36x faster than orjson)
|
|
15
|
+
- orjson for writing (2.27x faster than msgspec)
|
|
16
|
+
|
|
17
|
+
Direct imports (no try/catch) - assumes both are available.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
@property
|
|
21
|
+
def parser_name(self) -> str:
|
|
22
|
+
return "hybrid"
|
|
23
|
+
|
|
24
|
+
@property
|
|
25
|
+
def tier(self) -> int:
|
|
26
|
+
return 1
|
|
27
|
+
|
|
28
|
+
@property
|
|
29
|
+
def is_available(self) -> bool:
|
|
30
|
+
return True # Assumes both msgspec and orjson are available
|
|
31
|
+
|
|
32
|
+
def loads(self, s: str | bytes) -> Any:
|
|
33
|
+
"""Parse JSON using msgspec.json.decode() - fastest for reading."""
|
|
34
|
+
if isinstance(s, str):
|
|
35
|
+
s = s.encode("utf-8")
|
|
36
|
+
# msgspec.json.decode accepts bytes directly
|
|
37
|
+
return msgspec.json.decode(s)
|
|
38
|
+
|
|
39
|
+
def dumps(self, obj: Any, **kwargs) -> str | bytes:
|
|
40
|
+
"""Serialize JSON using orjson.dumps() - fastest for writing."""
|
|
41
|
+
option = 0
|
|
42
|
+
|
|
43
|
+
# orjson options
|
|
44
|
+
if not kwargs.get("ensure_ascii", True):
|
|
45
|
+
# orjson outputs UTF-8, so ensure_ascii=False is default
|
|
46
|
+
pass
|
|
47
|
+
|
|
48
|
+
# Handle indent (orjson doesn't support indent directly)
|
|
49
|
+
indent = kwargs.get("indent", None)
|
|
50
|
+
if indent:
|
|
51
|
+
# For pretty printing, use orjson.OPT_INDENT_2
|
|
52
|
+
option |= orjson.OPT_INDENT_2
|
|
53
|
+
|
|
54
|
+
# Sort keys
|
|
55
|
+
if kwargs.get("sort_keys", False):
|
|
56
|
+
option |= orjson.OPT_SORT_KEYS
|
|
57
|
+
|
|
58
|
+
result = orjson.dumps(obj, option=option)
|
|
59
|
+
|
|
60
|
+
# Return as bytes (orjson returns bytes)
|
|
61
|
+
# Caller can decode if string is needed
|
|
62
|
+
return result
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
#exonware/xwsystem/src/exonware/xwsystem/io/serialization/parsers/msgspec_parser.py
|
|
2
|
+
"""msgspec parser - Tier 1 (Rust-based, very fast)."""
|
|
3
|
+
|
|
4
|
+
from typing import Any
|
|
5
|
+
import importlib.util
|
|
6
|
+
|
|
7
|
+
_msgspec_spec = importlib.util.find_spec('msgspec')
|
|
8
|
+
if _msgspec_spec is not None:
|
|
9
|
+
import msgspec
|
|
10
|
+
MSGSPEC_AVAILABLE = True
|
|
11
|
+
else:
|
|
12
|
+
MSGSPEC_AVAILABLE = False
|
|
13
|
+
msgspec = None
|
|
14
|
+
|
|
15
|
+
from .base import AJsonParser
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class MsgspecParser(AJsonParser):
|
|
19
|
+
"""msgspec parser - Tier 1 (Rust-based, very fast, close to orjson)."""
|
|
20
|
+
|
|
21
|
+
@property
|
|
22
|
+
def parser_name(self) -> str:
|
|
23
|
+
return "msgspec"
|
|
24
|
+
|
|
25
|
+
@property
|
|
26
|
+
def tier(self) -> int:
|
|
27
|
+
return 1
|
|
28
|
+
|
|
29
|
+
@property
|
|
30
|
+
def is_available(self) -> bool:
|
|
31
|
+
return MSGSPEC_AVAILABLE
|
|
32
|
+
|
|
33
|
+
def loads(self, s: str | bytes) -> Any:
|
|
34
|
+
"""Parse JSON using msgspec.json.decode()."""
|
|
35
|
+
if isinstance(s, str):
|
|
36
|
+
s = s.encode("utf-8")
|
|
37
|
+
# msgspec.json.decode accepts bytes directly
|
|
38
|
+
return msgspec.json.decode(s)
|
|
39
|
+
|
|
40
|
+
def dumps(self, obj: Any, **kwargs) -> str | bytes:
|
|
41
|
+
"""Serialize JSON using msgspec.json.encode()."""
|
|
42
|
+
result = msgspec.json.encode(obj)
|
|
43
|
+
|
|
44
|
+
# msgspec returns bytes, decode if string needed
|
|
45
|
+
if isinstance(result, bytes) and kwargs.get("return_str", False):
|
|
46
|
+
return result.decode("utf-8")
|
|
47
|
+
|
|
48
|
+
return result
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
#exonware/xwsystem/src/exonware/xwsystem/io/serialization/parsers/orjson_direct_parser.py
|
|
2
|
+
"""orjson parser - DIRECT (no try/catch, assumes orjson is available)."""
|
|
3
|
+
|
|
4
|
+
from typing import Any
|
|
5
|
+
import orjson # Direct import, no try/catch
|
|
6
|
+
|
|
7
|
+
from .base import AJsonParser
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class OrjsonDirectParser(AJsonParser):
|
|
11
|
+
"""orjson parser - DIRECT (no try/catch, assumes orjson is available)."""
|
|
12
|
+
|
|
13
|
+
@property
|
|
14
|
+
def parser_name(self) -> str:
|
|
15
|
+
return "orjson_direct"
|
|
16
|
+
|
|
17
|
+
@property
|
|
18
|
+
def tier(self) -> int:
|
|
19
|
+
return 1
|
|
20
|
+
|
|
21
|
+
@property
|
|
22
|
+
def is_available(self) -> bool:
|
|
23
|
+
return True # Assumes orjson is available
|
|
24
|
+
|
|
25
|
+
def loads(self, s: str | bytes) -> Any:
|
|
26
|
+
"""Parse JSON using orjson.loads()."""
|
|
27
|
+
if isinstance(s, str):
|
|
28
|
+
s = s.encode("utf-8")
|
|
29
|
+
return orjson.loads(s)
|
|
30
|
+
|
|
31
|
+
def dumps(self, obj: Any, **kwargs) -> str | bytes:
|
|
32
|
+
"""Serialize JSON using orjson.dumps()."""
|
|
33
|
+
option = 0
|
|
34
|
+
|
|
35
|
+
# orjson options
|
|
36
|
+
if not kwargs.get("ensure_ascii", True):
|
|
37
|
+
# orjson outputs UTF-8, so ensure_ascii=False is default
|
|
38
|
+
pass
|
|
39
|
+
|
|
40
|
+
# Handle indent (orjson doesn't support indent directly)
|
|
41
|
+
indent = kwargs.get("indent", None)
|
|
42
|
+
if indent:
|
|
43
|
+
# For pretty printing, use orjson.OPT_INDENT_2
|
|
44
|
+
option |= orjson.OPT_INDENT_2
|
|
45
|
+
|
|
46
|
+
# Sort keys
|
|
47
|
+
if kwargs.get("sort_keys", False):
|
|
48
|
+
option |= orjson.OPT_SORT_KEYS
|
|
49
|
+
|
|
50
|
+
result = orjson.dumps(obj, option=option)
|
|
51
|
+
|
|
52
|
+
# Return as bytes (orjson returns bytes)
|
|
53
|
+
# Caller can decode if string is needed
|
|
54
|
+
return result
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
#exonware/xwsystem/src/exonware/xwsystem/io/serialization/parsers/orjson_parser.py
|
|
2
|
+
"""orjson parser - Tier 1 (3-4x faster than stdlib)."""
|
|
3
|
+
|
|
4
|
+
from typing import Any
|
|
5
|
+
import importlib.util
|
|
6
|
+
|
|
7
|
+
_orjson_spec = importlib.util.find_spec('orjson')
|
|
8
|
+
if _orjson_spec is not None:
|
|
9
|
+
import orjson
|
|
10
|
+
ORJSON_AVAILABLE = True
|
|
11
|
+
else:
|
|
12
|
+
ORJSON_AVAILABLE = False
|
|
13
|
+
orjson = None
|
|
14
|
+
|
|
15
|
+
from .base import AJsonParser
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class OrjsonParser(AJsonParser):
|
|
19
|
+
"""orjson parser - Tier 1 (3-4x faster than stdlib)."""
|
|
20
|
+
|
|
21
|
+
@property
|
|
22
|
+
def parser_name(self) -> str:
|
|
23
|
+
return "orjson"
|
|
24
|
+
|
|
25
|
+
@property
|
|
26
|
+
def tier(self) -> int:
|
|
27
|
+
return 1
|
|
28
|
+
|
|
29
|
+
@property
|
|
30
|
+
def is_available(self) -> bool:
|
|
31
|
+
return ORJSON_AVAILABLE
|
|
32
|
+
|
|
33
|
+
def loads(self, s: str | bytes) -> Any:
|
|
34
|
+
"""Parse JSON using orjson.loads()."""
|
|
35
|
+
if isinstance(s, str):
|
|
36
|
+
s = s.encode("utf-8")
|
|
37
|
+
return orjson.loads(s)
|
|
38
|
+
|
|
39
|
+
def dumps(self, obj: Any, **kwargs) -> str | bytes:
|
|
40
|
+
"""Serialize JSON using orjson.dumps()."""
|
|
41
|
+
option = 0
|
|
42
|
+
|
|
43
|
+
# orjson options
|
|
44
|
+
if not kwargs.get("ensure_ascii", True):
|
|
45
|
+
# orjson outputs UTF-8, so ensure_ascii=False is default
|
|
46
|
+
pass
|
|
47
|
+
|
|
48
|
+
# Handle indent (orjson doesn't support indent directly)
|
|
49
|
+
indent = kwargs.get("indent", None)
|
|
50
|
+
if indent:
|
|
51
|
+
# For pretty printing, use orjson.OPT_INDENT_2
|
|
52
|
+
option |= orjson.OPT_INDENT_2
|
|
53
|
+
|
|
54
|
+
# Sort keys
|
|
55
|
+
if kwargs.get("sort_keys", False):
|
|
56
|
+
option |= orjson.OPT_SORT_KEYS
|
|
57
|
+
|
|
58
|
+
result = orjson.dumps(obj, option=option)
|
|
59
|
+
|
|
60
|
+
# Return as bytes (orjson returns bytes)
|
|
61
|
+
# Caller can decode if string is needed
|
|
62
|
+
return result
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
#exonware/xwsystem/src/exonware/xwsystem/io/serialization/parsers/pysimdjson_parser.py
|
|
2
|
+
"""pysimdjson parser - Tier 1 (C++ simdjson, excellent for partial parsing)."""
|
|
3
|
+
|
|
4
|
+
from typing import Any
|
|
5
|
+
import importlib.util
|
|
6
|
+
|
|
7
|
+
_simdjson_spec = importlib.util.find_spec('simdjson')
|
|
8
|
+
if _simdjson_spec is not None:
|
|
9
|
+
import simdjson
|
|
10
|
+
PYSIMDJSON_AVAILABLE = True
|
|
11
|
+
else:
|
|
12
|
+
PYSIMDJSON_AVAILABLE = False
|
|
13
|
+
simdjson = None
|
|
14
|
+
|
|
15
|
+
from .base import AJsonParser
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class PysimdjsonParser(AJsonParser):
|
|
19
|
+
"""pysimdjson parser - Tier 1 (C++ simdjson, excellent for partial parsing)."""
|
|
20
|
+
|
|
21
|
+
@property
|
|
22
|
+
def parser_name(self) -> str:
|
|
23
|
+
return "pysimdjson"
|
|
24
|
+
|
|
25
|
+
@property
|
|
26
|
+
def tier(self) -> int:
|
|
27
|
+
return 1
|
|
28
|
+
|
|
29
|
+
@property
|
|
30
|
+
def is_available(self) -> bool:
|
|
31
|
+
return PYSIMDJSON_AVAILABLE
|
|
32
|
+
|
|
33
|
+
def loads(self, s: str | bytes) -> Any:
|
|
34
|
+
"""Parse JSON using simdjson.loads()."""
|
|
35
|
+
if isinstance(s, str):
|
|
36
|
+
s = s.encode("utf-8")
|
|
37
|
+
return simdjson.loads(s)
|
|
38
|
+
|
|
39
|
+
def dumps(self, obj: Any, **kwargs) -> str | bytes:
|
|
40
|
+
"""Serialize JSON using pysimdjson.dumps()."""
|
|
41
|
+
# pysimdjson doesn't have dumps, fallback to orjson or stdlib
|
|
42
|
+
# For now, use orjson if available, else stdlib
|
|
43
|
+
_orjson_spec = importlib.util.find_spec('orjson')
|
|
44
|
+
if _orjson_spec is not None:
|
|
45
|
+
import orjson
|
|
46
|
+
result = orjson.dumps(obj)
|
|
47
|
+
if isinstance(result, bytes) and kwargs.get("return_str", False):
|
|
48
|
+
return result.decode("utf-8")
|
|
49
|
+
return result
|
|
50
|
+
else:
|
|
51
|
+
import json
|
|
52
|
+
result = json.dumps(obj, **kwargs)
|
|
53
|
+
if isinstance(result, str) and kwargs.get("return_bytes", False):
|
|
54
|
+
return result.encode("utf-8")
|
|
55
|
+
return result
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
#exonware/xwsystem/src/exonware/xwsystem/io/serialization/parsers/rapidjson_parser.py
|
|
2
|
+
"""python-rapidjson parser - Tier 1 (C++ rapidjson)."""
|
|
3
|
+
|
|
4
|
+
from typing import Any
|
|
5
|
+
import importlib.util
|
|
6
|
+
|
|
7
|
+
_rapidjson_spec = importlib.util.find_spec('rapidjson')
|
|
8
|
+
if _rapidjson_spec is not None:
|
|
9
|
+
import rapidjson
|
|
10
|
+
RAPIDJSON_AVAILABLE = True
|
|
11
|
+
else:
|
|
12
|
+
RAPIDJSON_AVAILABLE = False
|
|
13
|
+
rapidjson = None
|
|
14
|
+
|
|
15
|
+
from .base import AJsonParser
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class RapidjsonParser(AJsonParser):
|
|
19
|
+
"""python-rapidjson parser - Tier 1 (C++ rapidjson)."""
|
|
20
|
+
|
|
21
|
+
@property
|
|
22
|
+
def parser_name(self) -> str:
|
|
23
|
+
return "rapidjson"
|
|
24
|
+
|
|
25
|
+
@property
|
|
26
|
+
def tier(self) -> int:
|
|
27
|
+
return 1
|
|
28
|
+
|
|
29
|
+
@property
|
|
30
|
+
def is_available(self) -> bool:
|
|
31
|
+
return RAPIDJSON_AVAILABLE
|
|
32
|
+
|
|
33
|
+
def loads(self, s: str | bytes) -> Any:
|
|
34
|
+
"""Parse JSON using rapidjson.loads()."""
|
|
35
|
+
if isinstance(s, bytes):
|
|
36
|
+
s = s.decode("utf-8")
|
|
37
|
+
return rapidjson.loads(s)
|
|
38
|
+
|
|
39
|
+
def dumps(self, obj: Any, **kwargs) -> str | bytes:
|
|
40
|
+
"""Serialize JSON using rapidjson.dumps()."""
|
|
41
|
+
# rapidjson supports most stdlib kwargs
|
|
42
|
+
result = rapidjson.dumps(
|
|
43
|
+
obj,
|
|
44
|
+
ensure_ascii=kwargs.get("ensure_ascii", True),
|
|
45
|
+
indent=kwargs.get("indent", None),
|
|
46
|
+
sort_keys=kwargs.get("sort_keys", False),
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
# rapidjson returns str, encode if bytes needed
|
|
50
|
+
if isinstance(result, str) and kwargs.get("return_bytes", False):
|
|
51
|
+
return result.encode("utf-8")
|
|
52
|
+
|
|
53
|
+
return result
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
#exonware/xwsystem/src/exonware/xwsystem/io/serialization/parsers/registry.py
|
|
2
|
+
"""Parser registry for JSON parser selection and auto-detection."""
|
|
3
|
+
|
|
4
|
+
from typing import Optional, Type
|
|
5
|
+
|
|
6
|
+
from .base import AJsonParser
|
|
7
|
+
from .standard import StandardJsonParser
|
|
8
|
+
|
|
9
|
+
# Import hybrid parser (direct, no try/catch - assumes msgspec and orjson available)
|
|
10
|
+
from .hybrid_parser import HybridParser
|
|
11
|
+
|
|
12
|
+
# Registry of available parsers
|
|
13
|
+
_PARSERS: dict[str, Type[AJsonParser]] = {
|
|
14
|
+
"hybrid": HybridParser, # Default: msgspec for reading, orjson for writing
|
|
15
|
+
"standard": StandardJsonParser, # Fallback only
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
# Cache of parser instances
|
|
19
|
+
_PARSER_INSTANCES: dict[str, AJsonParser] = {}
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def get_best_available_parser() -> AJsonParser:
|
|
23
|
+
"""
|
|
24
|
+
Auto-detect and return the best available parser.
|
|
25
|
+
|
|
26
|
+
Default: hybrid (msgspec for reading, orjson for writing)
|
|
27
|
+
- Fastest combination: msgspec reads 1.36x faster, orjson writes 2.27x faster
|
|
28
|
+
- Direct imports (no try/catch) - assumes both are available
|
|
29
|
+
|
|
30
|
+
Fallback: standard (stdlib json)
|
|
31
|
+
|
|
32
|
+
Returns:
|
|
33
|
+
Best available parser instance
|
|
34
|
+
"""
|
|
35
|
+
# Try hybrid first (default)
|
|
36
|
+
parser_class = _PARSERS.get("hybrid")
|
|
37
|
+
if parser_class:
|
|
38
|
+
parser = parser_class()
|
|
39
|
+
if parser.is_available:
|
|
40
|
+
return parser
|
|
41
|
+
|
|
42
|
+
# Fallback to standard (stdlib)
|
|
43
|
+
return StandardJsonParser()
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def get_parser(name: Optional[str] = None) -> AJsonParser:
|
|
47
|
+
"""
|
|
48
|
+
Get parser by name or auto-detect best available.
|
|
49
|
+
|
|
50
|
+
Args:
|
|
51
|
+
name: Parser name ("standard", "orjson", or None for auto-detect)
|
|
52
|
+
|
|
53
|
+
Returns:
|
|
54
|
+
Parser instance (falls back to best available if requested parser unavailable)
|
|
55
|
+
"""
|
|
56
|
+
if name is None:
|
|
57
|
+
return get_best_available_parser()
|
|
58
|
+
|
|
59
|
+
# Check cache first
|
|
60
|
+
if name in _PARSER_INSTANCES:
|
|
61
|
+
parser = _PARSER_INSTANCES[name]
|
|
62
|
+
if parser.is_available:
|
|
63
|
+
return parser
|
|
64
|
+
|
|
65
|
+
# Create new instance
|
|
66
|
+
parser_class = _PARSERS.get(name, StandardJsonParser)
|
|
67
|
+
parser = parser_class()
|
|
68
|
+
|
|
69
|
+
# Cache if available
|
|
70
|
+
if parser.is_available:
|
|
71
|
+
_PARSER_INSTANCES[name] = parser
|
|
72
|
+
else:
|
|
73
|
+
# Fallback to available parser if requested parser unavailable
|
|
74
|
+
if name != "standard":
|
|
75
|
+
return get_best_available_parser()
|
|
76
|
+
|
|
77
|
+
return parser
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def register_parser(name: str, parser_class: Type[AJsonParser]):
|
|
81
|
+
"""
|
|
82
|
+
Register a new parser implementation.
|
|
83
|
+
|
|
84
|
+
Args:
|
|
85
|
+
name: Parser identifier
|
|
86
|
+
parser_class: Parser class implementing AJsonParser
|
|
87
|
+
"""
|
|
88
|
+
_PARSERS[name] = parser_class
|
|
89
|
+
# Clear cache to allow new parser to be used
|
|
90
|
+
if name in _PARSER_INSTANCES:
|
|
91
|
+
del _PARSER_INSTANCES[name]
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
#exonware/xwsystem/src/exonware/xwsystem/io/serialization/parsers/standard.py
|
|
2
|
+
"""Standard library JSON parser (baseline implementation)."""
|
|
3
|
+
|
|
4
|
+
import json
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
from .base import AJsonParser
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class StandardJsonParser(AJsonParser):
|
|
11
|
+
"""Standard library JSON parser - Tier 0 (baseline)."""
|
|
12
|
+
|
|
13
|
+
@property
|
|
14
|
+
def parser_name(self) -> str:
|
|
15
|
+
return "standard"
|
|
16
|
+
|
|
17
|
+
@property
|
|
18
|
+
def tier(self) -> int:
|
|
19
|
+
return 0
|
|
20
|
+
|
|
21
|
+
@property
|
|
22
|
+
def is_available(self) -> bool:
|
|
23
|
+
return True # Available (stdlib)
|
|
24
|
+
|
|
25
|
+
def loads(self, s: str | bytes) -> Any:
|
|
26
|
+
"""Parse JSON using stdlib json.loads()."""
|
|
27
|
+
if isinstance(s, bytes):
|
|
28
|
+
s = s.decode("utf-8")
|
|
29
|
+
return json.loads(s)
|
|
30
|
+
|
|
31
|
+
def dumps(self, obj: Any, **kwargs) -> str | bytes:
|
|
32
|
+
"""Serialize JSON using stdlib json.dumps()."""
|
|
33
|
+
ensure_ascii = kwargs.get("ensure_ascii", False)
|
|
34
|
+
indent = kwargs.get("indent", None)
|
|
35
|
+
sort_keys = kwargs.get("sort_keys", False)
|
|
36
|
+
|
|
37
|
+
return json.dumps(
|
|
38
|
+
obj,
|
|
39
|
+
ensure_ascii=ensure_ascii,
|
|
40
|
+
indent=indent,
|
|
41
|
+
sort_keys=sort_keys,
|
|
42
|
+
default=kwargs.get("default", None),
|
|
43
|
+
cls=kwargs.get("cls", None),
|
|
44
|
+
)
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
#exonware/xwsystem/src/exonware/xwsystem/io/serialization/parsers/ujson_parser.py
|
|
2
|
+
"""ujson parser - Tier 1 (C-based, fast)."""
|
|
3
|
+
|
|
4
|
+
from typing import Any
|
|
5
|
+
import importlib.util
|
|
6
|
+
|
|
7
|
+
_ujson_spec = importlib.util.find_spec('ujson')
|
|
8
|
+
if _ujson_spec is not None:
|
|
9
|
+
import ujson
|
|
10
|
+
UJSON_AVAILABLE = True
|
|
11
|
+
else:
|
|
12
|
+
UJSON_AVAILABLE = False
|
|
13
|
+
ujson = None
|
|
14
|
+
|
|
15
|
+
from .base import AJsonParser
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class UjsonParser(AJsonParser):
|
|
19
|
+
"""ujson parser - Tier 1 (C-based, fast)."""
|
|
20
|
+
|
|
21
|
+
@property
|
|
22
|
+
def parser_name(self) -> str:
|
|
23
|
+
return "ujson"
|
|
24
|
+
|
|
25
|
+
@property
|
|
26
|
+
def tier(self) -> int:
|
|
27
|
+
return 1
|
|
28
|
+
|
|
29
|
+
@property
|
|
30
|
+
def is_available(self) -> bool:
|
|
31
|
+
return UJSON_AVAILABLE
|
|
32
|
+
|
|
33
|
+
def loads(self, s: str | bytes) -> Any:
|
|
34
|
+
"""Parse JSON using ujson.loads()."""
|
|
35
|
+
if isinstance(s, bytes):
|
|
36
|
+
s = s.decode("utf-8")
|
|
37
|
+
return ujson.loads(s)
|
|
38
|
+
|
|
39
|
+
def dumps(self, obj: Any, **kwargs) -> str | bytes:
|
|
40
|
+
"""Serialize JSON using ujson.dumps()."""
|
|
41
|
+
# ujson supports most stdlib kwargs
|
|
42
|
+
result = ujson.dumps(
|
|
43
|
+
obj,
|
|
44
|
+
ensure_ascii=kwargs.get("ensure_ascii", True),
|
|
45
|
+
indent=kwargs.get("indent", None),
|
|
46
|
+
sort_keys=kwargs.get("sort_keys", False),
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
# ujson returns str, encode if bytes needed
|
|
50
|
+
if isinstance(result, str) and kwargs.get("return_bytes", False):
|
|
51
|
+
return result.encode("utf-8")
|
|
52
|
+
|
|
53
|
+
return result
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
+
#exonware/xwsystem/src/exonware/xwsystem/io/serialization/registry.py
|
|
1
2
|
"""
|
|
2
3
|
Company: eXonware.com
|
|
3
4
|
Author: Eng. Muhammad AlShehri
|
|
4
5
|
Email: connect@exonware.com
|
|
5
|
-
Version: 0.0.
|
|
6
|
+
Version: 0.1.0.3
|
|
6
7
|
Generation Date: November 2, 2025
|
|
7
8
|
|
|
8
9
|
Serialization Registry - Delegates to UniversalCodecRegistry.
|
|
@@ -10,7 +11,7 @@ Serialization Registry - Delegates to UniversalCodecRegistry.
|
|
|
10
11
|
Provides serialization-specific convenience methods for format discovery.
|
|
11
12
|
"""
|
|
12
13
|
|
|
13
|
-
from typing import Optional
|
|
14
|
+
from typing import Optional
|
|
14
15
|
from pathlib import Path
|
|
15
16
|
|
|
16
17
|
from ..codec.registry import UniversalCodecRegistry, get_registry
|
|
@@ -68,7 +69,7 @@ class SerializationRegistry:
|
|
|
68
69
|
"""
|
|
69
70
|
return self._codec_registry.get_by_id(format_id)
|
|
70
71
|
|
|
71
|
-
def detect_from_file(self, file_path:
|
|
72
|
+
def detect_from_file(self, file_path: str | Path) -> Optional[ISerialization]:
|
|
72
73
|
"""
|
|
73
74
|
Auto-detect serializer from file path.
|
|
74
75
|
|
|
@@ -184,4 +185,3 @@ def get_serialization_registry() -> SerializationRegistry:
|
|
|
184
185
|
if _global_serialization_registry is None:
|
|
185
186
|
_global_serialization_registry = SerializationRegistry()
|
|
186
187
|
return _global_serialization_registry
|
|
187
|
-
|