exonware-xwsystem 0.0.1.410__py3-none-any.whl → 0.0.1.411__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 +1 -1
- exonware/conf.py +1 -1
- exonware/xwsystem/__init__.py +2 -2
- exonware/xwsystem/caching/__init__.py +1 -1
- exonware/xwsystem/caching/base.py +2 -2
- exonware/xwsystem/caching/bloom_cache.py +2 -2
- exonware/xwsystem/caching/cache_manager.py +1 -1
- exonware/xwsystem/caching/conditional.py +2 -2
- exonware/xwsystem/caching/contracts.py +1 -1
- exonware/xwsystem/caching/decorators.py +2 -2
- exonware/xwsystem/caching/defs.py +1 -1
- exonware/xwsystem/caching/disk_cache.py +1 -1
- exonware/xwsystem/caching/distributed.py +1 -1
- exonware/xwsystem/caching/errors.py +1 -1
- exonware/xwsystem/caching/events.py +2 -2
- exonware/xwsystem/caching/eviction_strategies.py +1 -1
- exonware/xwsystem/caching/fluent.py +1 -1
- exonware/xwsystem/caching/integrity.py +1 -1
- exonware/xwsystem/caching/lfu_cache.py +2 -2
- exonware/xwsystem/caching/lfu_optimized.py +3 -3
- exonware/xwsystem/caching/lru_cache.py +2 -2
- exonware/xwsystem/caching/memory_bounded.py +2 -2
- exonware/xwsystem/caching/metrics_exporter.py +2 -2
- exonware/xwsystem/caching/observable_cache.py +1 -1
- exonware/xwsystem/caching/pluggable_cache.py +2 -2
- exonware/xwsystem/caching/rate_limiter.py +1 -1
- exonware/xwsystem/caching/read_through.py +2 -2
- exonware/xwsystem/caching/secure_cache.py +1 -1
- exonware/xwsystem/caching/serializable.py +2 -2
- exonware/xwsystem/caching/stats.py +1 -1
- exonware/xwsystem/caching/tagging.py +2 -2
- exonware/xwsystem/caching/ttl_cache.py +1 -1
- exonware/xwsystem/caching/two_tier_cache.py +1 -1
- exonware/xwsystem/caching/utils.py +1 -1
- exonware/xwsystem/caching/validation.py +1 -1
- exonware/xwsystem/caching/warming.py +2 -2
- exonware/xwsystem/caching/write_behind.py +2 -2
- exonware/xwsystem/cli/__init__.py +1 -1
- exonware/xwsystem/cli/args.py +1 -1
- exonware/xwsystem/cli/base.py +1 -1
- exonware/xwsystem/cli/colors.py +1 -1
- exonware/xwsystem/cli/console.py +1 -1
- exonware/xwsystem/cli/contracts.py +1 -1
- exonware/xwsystem/cli/defs.py +1 -1
- exonware/xwsystem/cli/errors.py +1 -1
- exonware/xwsystem/cli/progress.py +1 -1
- exonware/xwsystem/cli/prompts.py +1 -1
- exonware/xwsystem/cli/tables.py +1 -1
- exonware/xwsystem/config/__init__.py +1 -1
- exonware/xwsystem/config/base.py +2 -2
- exonware/xwsystem/config/contracts.py +1 -1
- exonware/xwsystem/config/defaults.py +1 -1
- exonware/xwsystem/config/defs.py +1 -1
- exonware/xwsystem/config/errors.py +2 -2
- exonware/xwsystem/config/logging.py +1 -1
- exonware/xwsystem/config/logging_setup.py +2 -2
- exonware/xwsystem/config/performance.py +1 -1
- exonware/xwsystem/http_client/__init__.py +1 -1
- exonware/xwsystem/http_client/advanced_client.py +2 -2
- exonware/xwsystem/http_client/base.py +2 -2
- exonware/xwsystem/http_client/client.py +2 -2
- exonware/xwsystem/http_client/contracts.py +1 -1
- exonware/xwsystem/http_client/defs.py +1 -1
- exonware/xwsystem/http_client/errors.py +2 -2
- exonware/xwsystem/io/__init__.py +1 -1
- exonware/xwsystem/io/archive/__init__.py +1 -1
- exonware/xwsystem/io/archive/archive.py +1 -1
- exonware/xwsystem/io/archive/archive_files.py +1 -1
- exonware/xwsystem/io/archive/archivers.py +2 -2
- exonware/xwsystem/io/archive/base.py +6 -6
- exonware/xwsystem/io/archive/codec_integration.py +1 -1
- exonware/xwsystem/io/archive/compression.py +1 -1
- exonware/xwsystem/io/archive/formats/__init__.py +1 -1
- exonware/xwsystem/io/archive/formats/brotli_format.py +6 -3
- exonware/xwsystem/io/archive/formats/lz4_format.py +6 -3
- exonware/xwsystem/io/archive/formats/rar.py +6 -3
- exonware/xwsystem/io/archive/formats/sevenzip.py +6 -3
- exonware/xwsystem/io/archive/formats/squashfs_format.py +1 -1
- exonware/xwsystem/io/archive/formats/tar.py +1 -1
- exonware/xwsystem/io/archive/formats/wim_format.py +6 -3
- exonware/xwsystem/io/archive/formats/zip.py +1 -1
- exonware/xwsystem/io/archive/formats/zpaq_format.py +1 -1
- exonware/xwsystem/io/archive/formats/zstandard.py +6 -3
- exonware/xwsystem/io/base.py +1 -1
- exonware/xwsystem/io/codec/__init__.py +1 -1
- exonware/xwsystem/io/codec/base.py +6 -6
- exonware/xwsystem/io/codec/contracts.py +1 -1
- exonware/xwsystem/io/codec/registry.py +5 -5
- exonware/xwsystem/io/common/__init__.py +1 -1
- exonware/xwsystem/io/common/base.py +1 -1
- exonware/xwsystem/io/common/lock.py +1 -1
- exonware/xwsystem/io/common/watcher.py +1 -1
- exonware/xwsystem/io/contracts.py +1 -1
- exonware/xwsystem/io/data_operations.py +480 -0
- exonware/xwsystem/io/defs.py +1 -1
- exonware/xwsystem/io/errors.py +1 -1
- exonware/xwsystem/io/facade.py +2 -2
- exonware/xwsystem/io/file/__init__.py +1 -1
- exonware/xwsystem/io/file/base.py +1 -1
- exonware/xwsystem/io/file/conversion.py +1 -1
- exonware/xwsystem/io/file/file.py +8 -6
- exonware/xwsystem/io/file/paged_source.py +8 -1
- exonware/xwsystem/io/file/paging/__init__.py +1 -1
- exonware/xwsystem/io/file/paging/byte_paging.py +1 -1
- exonware/xwsystem/io/file/paging/line_paging.py +1 -1
- exonware/xwsystem/io/file/paging/record_paging.py +1 -1
- exonware/xwsystem/io/file/paging/registry.py +4 -4
- exonware/xwsystem/io/file/source.py +20 -9
- exonware/xwsystem/io/filesystem/__init__.py +1 -1
- exonware/xwsystem/io/filesystem/base.py +1 -1
- exonware/xwsystem/io/filesystem/local.py +9 -1
- exonware/xwsystem/io/folder/__init__.py +1 -1
- exonware/xwsystem/io/folder/base.py +1 -1
- exonware/xwsystem/io/folder/folder.py +2 -2
- exonware/xwsystem/io/serialization/__init__.py +1 -1
- exonware/xwsystem/io/serialization/auto_serializer.py +52 -39
- exonware/xwsystem/io/serialization/base.py +165 -1
- exonware/xwsystem/io/serialization/contracts.py +88 -1
- exonware/xwsystem/io/serialization/defs.py +1 -1
- exonware/xwsystem/io/serialization/errors.py +1 -1
- exonware/xwsystem/io/serialization/flyweight.py +10 -10
- exonware/xwsystem/io/serialization/format_detector.py +8 -5
- exonware/xwsystem/io/serialization/formats/__init__.py +1 -1
- exonware/xwsystem/io/serialization/formats/binary/bson.py +1 -1
- exonware/xwsystem/io/serialization/formats/binary/cbor.py +1 -1
- exonware/xwsystem/io/serialization/formats/binary/marshal.py +1 -1
- exonware/xwsystem/io/serialization/formats/binary/msgpack.py +1 -1
- exonware/xwsystem/io/serialization/formats/binary/pickle.py +1 -1
- exonware/xwsystem/io/serialization/formats/binary/plistlib.py +1 -1
- exonware/xwsystem/io/serialization/formats/database/dbm.py +53 -1
- exonware/xwsystem/io/serialization/formats/database/shelve.py +48 -1
- exonware/xwsystem/io/serialization/formats/database/sqlite3.py +85 -1
- exonware/xwsystem/io/serialization/formats/text/configparser.py +1 -1
- exonware/xwsystem/io/serialization/formats/text/csv.py +1 -1
- exonware/xwsystem/io/serialization/formats/text/formdata.py +1 -1
- exonware/xwsystem/io/serialization/formats/text/json.py +1 -1
- exonware/xwsystem/io/serialization/formats/text/json5.py +7 -5
- exonware/xwsystem/io/serialization/formats/text/jsonlines.py +229 -19
- exonware/xwsystem/io/serialization/formats/text/multipart.py +1 -1
- exonware/xwsystem/io/serialization/formats/text/toml.py +19 -3
- exonware/xwsystem/io/serialization/formats/text/xml.py +8 -1
- exonware/xwsystem/io/serialization/formats/text/yaml.py +52 -2
- exonware/xwsystem/io/serialization/registry.py +1 -1
- exonware/xwsystem/io/serialization/serializer.py +175 -3
- exonware/xwsystem/io/serialization/utils/__init__.py +1 -1
- exonware/xwsystem/io/serialization/utils/path_ops.py +1 -1
- exonware/xwsystem/io/stream/__init__.py +1 -1
- exonware/xwsystem/io/stream/async_operations.py +1 -1
- exonware/xwsystem/io/stream/base.py +1 -1
- exonware/xwsystem/io/stream/codec_io.py +1 -1
- exonware/xwsystem/ipc/async_fabric.py +1 -2
- exonware/xwsystem/ipc/base.py +2 -2
- exonware/xwsystem/ipc/contracts.py +2 -2
- exonware/xwsystem/ipc/defs.py +1 -1
- exonware/xwsystem/ipc/errors.py +2 -2
- exonware/xwsystem/ipc/pipes.py +2 -2
- exonware/xwsystem/ipc/shared_memory.py +2 -2
- exonware/xwsystem/monitoring/base.py +2 -2
- exonware/xwsystem/monitoring/contracts.py +1 -1
- exonware/xwsystem/monitoring/defs.py +1 -1
- exonware/xwsystem/monitoring/error_recovery.py +2 -2
- exonware/xwsystem/monitoring/errors.py +2 -2
- exonware/xwsystem/monitoring/memory_monitor.py +1 -1
- exonware/xwsystem/monitoring/performance_manager_generic.py +2 -2
- exonware/xwsystem/monitoring/performance_validator.py +1 -1
- exonware/xwsystem/monitoring/system_monitor.py +2 -2
- exonware/xwsystem/monitoring/tracing.py +2 -2
- exonware/xwsystem/monitoring/tracker.py +1 -1
- exonware/xwsystem/operations/__init__.py +1 -1
- exonware/xwsystem/operations/base.py +1 -1
- exonware/xwsystem/operations/defs.py +1 -1
- exonware/xwsystem/operations/diff.py +1 -1
- exonware/xwsystem/operations/merge.py +1 -1
- exonware/xwsystem/operations/patch.py +1 -1
- exonware/xwsystem/patterns/base.py +2 -2
- exonware/xwsystem/patterns/context_manager.py +2 -2
- exonware/xwsystem/patterns/contracts.py +9 -9
- exonware/xwsystem/patterns/defs.py +1 -1
- exonware/xwsystem/patterns/dynamic_facade.py +8 -8
- exonware/xwsystem/patterns/errors.py +5 -5
- exonware/xwsystem/patterns/handler_factory.py +6 -6
- exonware/xwsystem/patterns/object_pool.py +7 -7
- exonware/xwsystem/patterns/registry.py +3 -3
- exonware/xwsystem/plugins/__init__.py +1 -1
- exonware/xwsystem/plugins/base.py +5 -5
- exonware/xwsystem/plugins/contracts.py +5 -5
- exonware/xwsystem/plugins/defs.py +1 -1
- exonware/xwsystem/plugins/errors.py +4 -4
- exonware/xwsystem/runtime/__init__.py +1 -1
- exonware/xwsystem/runtime/base.py +6 -6
- exonware/xwsystem/runtime/contracts.py +6 -6
- exonware/xwsystem/runtime/defs.py +1 -1
- exonware/xwsystem/runtime/env.py +2 -2
- exonware/xwsystem/runtime/errors.py +1 -1
- exonware/xwsystem/runtime/reflection.py +8 -8
- exonware/xwsystem/security/auth.py +1 -1
- exonware/xwsystem/security/base.py +2 -2
- exonware/xwsystem/security/contracts.py +1 -1
- exonware/xwsystem/security/crypto.py +2 -2
- exonware/xwsystem/security/defs.py +1 -1
- exonware/xwsystem/security/errors.py +2 -2
- exonware/xwsystem/security/hazmat.py +2 -2
- exonware/xwsystem/shared/__init__.py +1 -1
- exonware/xwsystem/shared/base.py +1 -1
- exonware/xwsystem/shared/contracts.py +1 -1
- exonware/xwsystem/shared/defs.py +1 -1
- exonware/xwsystem/shared/errors.py +1 -1
- exonware/xwsystem/structures/__init__.py +1 -1
- exonware/xwsystem/structures/base.py +2 -2
- exonware/xwsystem/structures/contracts.py +1 -1
- exonware/xwsystem/structures/defs.py +1 -1
- exonware/xwsystem/structures/errors.py +2 -2
- exonware/xwsystem/threading/async_primitives.py +2 -2
- exonware/xwsystem/threading/base.py +2 -2
- exonware/xwsystem/threading/contracts.py +1 -1
- exonware/xwsystem/threading/defs.py +1 -1
- exonware/xwsystem/threading/errors.py +2 -2
- exonware/xwsystem/threading/safe_factory.py +6 -6
- exonware/xwsystem/utils/base.py +2 -2
- exonware/xwsystem/utils/contracts.py +1 -1
- exonware/xwsystem/utils/dt/__init__.py +1 -1
- exonware/xwsystem/utils/dt/base.py +2 -2
- exonware/xwsystem/utils/dt/contracts.py +1 -1
- exonware/xwsystem/utils/dt/defs.py +1 -1
- exonware/xwsystem/utils/dt/errors.py +2 -2
- exonware/xwsystem/utils/dt/formatting.py +1 -1
- exonware/xwsystem/utils/dt/humanize.py +2 -2
- exonware/xwsystem/utils/dt/parsing.py +1 -1
- exonware/xwsystem/utils/dt/timezone_utils.py +1 -1
- exonware/xwsystem/utils/errors.py +2 -2
- exonware/xwsystem/utils/test_runner.py +1 -1
- exonware/xwsystem/utils/utils_contracts.py +1 -1
- exonware/xwsystem/validation/__init__.py +1 -1
- exonware/xwsystem/validation/base.py +15 -15
- exonware/xwsystem/validation/contracts.py +1 -1
- exonware/xwsystem/validation/data_validator.py +10 -0
- exonware/xwsystem/validation/declarative.py +9 -9
- exonware/xwsystem/validation/defs.py +1 -1
- exonware/xwsystem/validation/errors.py +2 -2
- exonware/xwsystem/validation/fluent_validator.py +4 -4
- exonware/xwsystem/version.py +2 -2
- {exonware_xwsystem-0.0.1.410.dist-info → exonware_xwsystem-0.0.1.411.dist-info}/METADATA +3 -3
- exonware_xwsystem-0.0.1.411.dist-info/RECORD +274 -0
- exonware_xwsystem-0.0.1.410.dist-info/RECORD +0 -273
- {exonware_xwsystem-0.0.1.410.dist-info → exonware_xwsystem-0.0.1.411.dist-info}/WHEEL +0 -0
- {exonware_xwsystem-0.0.1.410.dist-info → exonware_xwsystem-0.0.1.411.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
#exonware\
|
|
1
|
+
#exonware\xwsystem\serialization\flyweight.py
|
|
2
2
|
"""
|
|
3
3
|
Company: eXonware.com
|
|
4
4
|
Author: Eng. Muhammad AlShehri
|
|
5
5
|
Email: connect@exonware.com
|
|
6
|
-
Version: 0.0.1.
|
|
6
|
+
Version: 0.0.1.411
|
|
7
7
|
Generation Date: September 05, 2025
|
|
8
8
|
|
|
9
9
|
Flyweight Pattern Implementation for Serializers
|
|
@@ -14,7 +14,7 @@ configuration, which is especially important for high-throughput applications.
|
|
|
14
14
|
"""
|
|
15
15
|
|
|
16
16
|
import threading
|
|
17
|
-
from typing import Any, Hashable, Optional,
|
|
17
|
+
from typing import Any, Hashable, Optional, Union
|
|
18
18
|
# Root cause: Migrating to Python 3.12 built-in generic syntax for consistency
|
|
19
19
|
# Priority #3: Maintainability - Modern type annotations improve code clarity
|
|
20
20
|
from weakref import WeakValueDictionary
|
|
@@ -22,7 +22,7 @@ from weakref import WeakValueDictionary
|
|
|
22
22
|
from ...config.logging_setup import get_logger
|
|
23
23
|
from .contracts import ISerialization
|
|
24
24
|
|
|
25
|
-
logger = get_logger("
|
|
25
|
+
logger = get_logger("xwsystem.serialization.flyweight")
|
|
26
26
|
|
|
27
27
|
|
|
28
28
|
class SerializerFlyweight:
|
|
@@ -46,7 +46,7 @@ class SerializerFlyweight:
|
|
|
46
46
|
|
|
47
47
|
def get_serializer[T: ISerialization](
|
|
48
48
|
self,
|
|
49
|
-
serializer_class:
|
|
49
|
+
serializer_class: type[T],
|
|
50
50
|
**config: Any
|
|
51
51
|
) -> T:
|
|
52
52
|
"""
|
|
@@ -85,7 +85,7 @@ class SerializerFlyweight:
|
|
|
85
85
|
logger.error(f"Failed to create {serializer_class.__name__} instance: {e}")
|
|
86
86
|
raise
|
|
87
87
|
|
|
88
|
-
def _create_cache_key[T: ISerialization](self, serializer_class:
|
|
88
|
+
def _create_cache_key[T: ISerialization](self, serializer_class: type[T], config: dict[str, Any]) -> str:
|
|
89
89
|
"""
|
|
90
90
|
Create a hashable cache key from class and configuration.
|
|
91
91
|
|
|
@@ -172,7 +172,7 @@ class SerializerFlyweight:
|
|
|
172
172
|
_serializer_flyweight = SerializerFlyweight()
|
|
173
173
|
|
|
174
174
|
|
|
175
|
-
def get_serializer[T: ISerialization](serializer_class:
|
|
175
|
+
def get_serializer[T: ISerialization](serializer_class: type[T], **config: Any) -> T:
|
|
176
176
|
"""
|
|
177
177
|
Get a serializer instance using the flyweight pattern.
|
|
178
178
|
|
|
@@ -187,7 +187,7 @@ def get_serializer[T: ISerialization](serializer_class: Type[T], **config: Any)
|
|
|
187
187
|
Shared serializer instance
|
|
188
188
|
|
|
189
189
|
Example:
|
|
190
|
-
>>> from
|
|
190
|
+
>>> from xwsystem.serialization import JsonSerializer
|
|
191
191
|
>>> # These will return the same instance
|
|
192
192
|
>>> json1 = get_serializer(JsonSerializer, validate_input=True)
|
|
193
193
|
>>> json2 = get_serializer(JsonSerializer, validate_input=True)
|
|
@@ -248,7 +248,7 @@ class SerializerPool:
|
|
|
248
248
|
self._counter = 0
|
|
249
249
|
self._lock = threading.RLock()
|
|
250
250
|
|
|
251
|
-
def get_serializer[T: ISerialization](self, serializer_class:
|
|
251
|
+
def get_serializer[T: ISerialization](self, serializer_class: type[T], **config: Any) -> T:
|
|
252
252
|
"""Get serializer from pool with size-limited caching."""
|
|
253
253
|
cache_key = self._create_cache_key(serializer_class, config)
|
|
254
254
|
|
|
@@ -302,7 +302,7 @@ class SerializerPool:
|
|
|
302
302
|
|
|
303
303
|
logger.debug(f"Evicted serializer instance: {lru_key[:32]}...")
|
|
304
304
|
|
|
305
|
-
def _create_cache_key[T: ISerialization](self, serializer_class:
|
|
305
|
+
def _create_cache_key[T: ISerialization](self, serializer_class: type[T], config: dict[str, Any]) -> str:
|
|
306
306
|
"""Create cache key (same as flyweight implementation)."""
|
|
307
307
|
return _serializer_flyweight._create_cache_key(serializer_class, config)
|
|
308
308
|
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
#exonware\
|
|
1
|
+
#exonware\xwsystem\serialization\format_detector.py
|
|
2
2
|
"""
|
|
3
3
|
Company: eXonware.com
|
|
4
4
|
Author: Eng. Muhammad AlShehri
|
|
5
5
|
Email: connect@exonware.com
|
|
6
|
-
Version: 0.0.1.
|
|
6
|
+
Version: 0.0.1.411
|
|
7
7
|
Generation Date: September 04, 2025
|
|
8
8
|
|
|
9
9
|
Intelligent format detection for automatic serialization format selection.
|
|
@@ -15,7 +15,7 @@ from typing import Any, Optional, Union
|
|
|
15
15
|
|
|
16
16
|
from ...config.logging_setup import get_logger
|
|
17
17
|
|
|
18
|
-
logger = get_logger("
|
|
18
|
+
logger = get_logger("xwsystem.serialization.format_detector")
|
|
19
19
|
|
|
20
20
|
|
|
21
21
|
class FormatDetector:
|
|
@@ -26,12 +26,15 @@ class FormatDetector:
|
|
|
26
26
|
|
|
27
27
|
__slots__ = ('_extension_map', '_magic_bytes', '_content_patterns', '_confidence_threshold')
|
|
28
28
|
|
|
29
|
-
def __init__(self, confidence_threshold: float = 0.
|
|
29
|
+
def __init__(self, confidence_threshold: float = 0.3):
|
|
30
30
|
"""
|
|
31
31
|
Initialize format detector.
|
|
32
32
|
|
|
33
33
|
Args:
|
|
34
|
-
confidence_threshold: Minimum confidence level for format detection
|
|
34
|
+
confidence_threshold: Minimum confidence level for format detection.
|
|
35
|
+
Default is 0.3 so that simple, high-signal heuristics like
|
|
36
|
+
extension-only detection (e.g. ``test.json``) are accepted
|
|
37
|
+
without requiring magic-bytes or content analysis.
|
|
35
38
|
"""
|
|
36
39
|
self._confidence_threshold = confidence_threshold
|
|
37
40
|
self._extension_map = self._build_extension_map()
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
Company: eXonware.com
|
|
3
3
|
Author: Eng. Muhammad AlShehri
|
|
4
4
|
Email: connect@exonware.com
|
|
5
|
-
Version: 0.0.1.
|
|
5
|
+
Version: 0.0.1.411
|
|
6
6
|
Generation Date: November 2, 2025
|
|
7
7
|
|
|
8
8
|
DBM serialization - Unix database manager.
|
|
@@ -13,6 +13,7 @@ Following I→A pattern:
|
|
|
13
13
|
- Concrete: DbmSerializer
|
|
14
14
|
"""
|
|
15
15
|
|
|
16
|
+
import json
|
|
16
17
|
import dbm
|
|
17
18
|
from typing import Any, Optional, Union
|
|
18
19
|
from pathlib import Path
|
|
@@ -70,3 +71,54 @@ class DbmSerializer(ASerialization):
|
|
|
70
71
|
"""DBM decode requires file path - use load_file() instead."""
|
|
71
72
|
raise NotImplementedError("DBM requires file-based operations - use load_file()")
|
|
72
73
|
|
|
74
|
+
# ---------------------------------------------------------------------
|
|
75
|
+
# FILE-BASED OPERATIONS
|
|
76
|
+
# ---------------------------------------------------------------------
|
|
77
|
+
|
|
78
|
+
def save_file(self, data: Any, file_path: Union[str, Path], **options: Any) -> None:
|
|
79
|
+
"""
|
|
80
|
+
Save Python data into a DBM database file.
|
|
81
|
+
|
|
82
|
+
Root cause: Generic ``save_file`` tried to call ``encode`` which is
|
|
83
|
+
intentionally unimplemented for DBM. Fix by performing file-based
|
|
84
|
+
operations directly and storing a single JSON payload under a fixed
|
|
85
|
+
key.
|
|
86
|
+
"""
|
|
87
|
+
path = Path(file_path)
|
|
88
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
89
|
+
|
|
90
|
+
try:
|
|
91
|
+
with dbm.open(str(path), "c") as db:
|
|
92
|
+
payload = json.dumps(data).encode("utf-8")
|
|
93
|
+
db[b"root"] = payload
|
|
94
|
+
except Exception as e:
|
|
95
|
+
raise SerializationError(
|
|
96
|
+
f"Failed to save DBM file '{path}': {e}",
|
|
97
|
+
format_name=self.format_name,
|
|
98
|
+
original_error=e,
|
|
99
|
+
) from e
|
|
100
|
+
|
|
101
|
+
def load_file(self, file_path: Union[str, Path], **options: Any) -> Any:
|
|
102
|
+
"""
|
|
103
|
+
Load Python data from a DBM database file.
|
|
104
|
+
|
|
105
|
+
Returns the JSON-decoded payload stored under the ``root`` key.
|
|
106
|
+
"""
|
|
107
|
+
path = Path(file_path)
|
|
108
|
+
|
|
109
|
+
try:
|
|
110
|
+
with dbm.open(str(path), "r") as db:
|
|
111
|
+
raw = db.get(b"root")
|
|
112
|
+
if raw is None:
|
|
113
|
+
return None
|
|
114
|
+
return json.loads(raw.decode("utf-8"))
|
|
115
|
+
except FileNotFoundError:
|
|
116
|
+
# Mirror other serializers' behaviour when file is missing
|
|
117
|
+
raise
|
|
118
|
+
except Exception as e:
|
|
119
|
+
raise SerializationError(
|
|
120
|
+
f"Failed to load DBM file '{path}': {e}",
|
|
121
|
+
format_name=self.format_name,
|
|
122
|
+
original_error=e,
|
|
123
|
+
) from e
|
|
124
|
+
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
Company: eXonware.com
|
|
3
3
|
Author: Eng. Muhammad AlShehri
|
|
4
4
|
Email: connect@exonware.com
|
|
5
|
-
Version: 0.0.1.
|
|
5
|
+
Version: 0.0.1.411
|
|
6
6
|
Generation Date: November 2, 2025
|
|
7
7
|
|
|
8
8
|
Shelve serialization - Persistent dictionary storage.
|
|
@@ -70,3 +70,50 @@ class ShelveSerializer(ASerialization):
|
|
|
70
70
|
"""Shelve decode requires file path - use load_file() instead."""
|
|
71
71
|
raise NotImplementedError("Shelve requires file-based operations - use load_file()")
|
|
72
72
|
|
|
73
|
+
# ---------------------------------------------------------------------
|
|
74
|
+
# FILE-BASED OPERATIONS
|
|
75
|
+
# ---------------------------------------------------------------------
|
|
76
|
+
|
|
77
|
+
def save_file(self, data: Any, file_path: Union[str, Path], **options: Any) -> None:
|
|
78
|
+
"""
|
|
79
|
+
Save Python data into a shelve database file.
|
|
80
|
+
|
|
81
|
+
Uses a single key ``'root'`` to store the provided object, which is
|
|
82
|
+
sufficient for the dict-style usage expected by the tests and APIs.
|
|
83
|
+
"""
|
|
84
|
+
path = Path(file_path)
|
|
85
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
86
|
+
|
|
87
|
+
try:
|
|
88
|
+
with shelve.open(str(path)) as db:
|
|
89
|
+
db["root"] = data
|
|
90
|
+
except Exception as e:
|
|
91
|
+
raise SerializationError(
|
|
92
|
+
f"Failed to save Shelve file '{path}': {e}",
|
|
93
|
+
format_name=self.format_name,
|
|
94
|
+
original_error=e,
|
|
95
|
+
) from e
|
|
96
|
+
|
|
97
|
+
def load_file(self, file_path: Union[str, Path], **options: Any) -> Any:
|
|
98
|
+
"""
|
|
99
|
+
Load Python data from a shelve database file.
|
|
100
|
+
|
|
101
|
+
Returns the object stored under the ``'root'`` key (or ``None`` if
|
|
102
|
+
not present), mirroring the behaviour of other serializers that
|
|
103
|
+
operate on a single top-level payload.
|
|
104
|
+
"""
|
|
105
|
+
path = Path(file_path)
|
|
106
|
+
|
|
107
|
+
try:
|
|
108
|
+
with shelve.open(str(path)) as db:
|
|
109
|
+
return db.get("root")
|
|
110
|
+
except FileNotFoundError:
|
|
111
|
+
# Mirror other serializers' behaviour when file is missing
|
|
112
|
+
raise
|
|
113
|
+
except Exception as e:
|
|
114
|
+
raise SerializationError(
|
|
115
|
+
f"Failed to load Shelve file '{path}': {e}",
|
|
116
|
+
format_name=self.format_name,
|
|
117
|
+
original_error=e,
|
|
118
|
+
) from e
|
|
119
|
+
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
Company: eXonware.com
|
|
3
3
|
Author: Eng. Muhammad AlShehri
|
|
4
4
|
Email: connect@exonware.com
|
|
5
|
-
Version: 0.0.1.
|
|
5
|
+
Version: 0.0.1.411
|
|
6
6
|
Generation Date: November 2, 2025
|
|
7
7
|
|
|
8
8
|
SQLite3 serialization - Embedded database storage.
|
|
@@ -13,6 +13,7 @@ Following I→A pattern:
|
|
|
13
13
|
- Concrete: Sqlite3Serializer
|
|
14
14
|
"""
|
|
15
15
|
|
|
16
|
+
import json
|
|
16
17
|
import sqlite3
|
|
17
18
|
from typing import Any, Optional, Union
|
|
18
19
|
from pathlib import Path
|
|
@@ -70,3 +71,86 @@ class Sqlite3Serializer(ASerialization):
|
|
|
70
71
|
"""SQLite3 decode requires file path - use load_file() instead."""
|
|
71
72
|
raise NotImplementedError("SQLite3 requires file-based operations - use load_file()")
|
|
72
73
|
|
|
74
|
+
# ---------------------------------------------------------------------
|
|
75
|
+
# FILE-BASED OPERATIONS (override ASerialization defaults)
|
|
76
|
+
# ---------------------------------------------------------------------
|
|
77
|
+
|
|
78
|
+
def save_file(self, data: Any, file_path: Union[str, Path], **options: Any) -> None:
|
|
79
|
+
"""
|
|
80
|
+
Save Python data into a SQLite3 database file.
|
|
81
|
+
|
|
82
|
+
Root cause: The generic ``ASerialization.save_file`` implementation
|
|
83
|
+
expects an in-memory ``encode`` operation, but SQLite3 is inherently
|
|
84
|
+
file-backed and our ``encode``/``decode`` are intentionally
|
|
85
|
+
unimplemented. Calling the base implementation raised a
|
|
86
|
+
``NotImplementedError`` wrapped in ``SerializationError``.
|
|
87
|
+
|
|
88
|
+
Solution: Override ``save_file`` / ``load_file`` to perform
|
|
89
|
+
file-based operations directly using ``sqlite3`` while still
|
|
90
|
+
presenting a simple dict-like API to callers and tests.
|
|
91
|
+
"""
|
|
92
|
+
path = Path(file_path)
|
|
93
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
94
|
+
|
|
95
|
+
# For now we implement a minimal schema:
|
|
96
|
+
# - Single table ``data``
|
|
97
|
+
# - Single row with id=1 storing JSON representation of ``data``
|
|
98
|
+
try:
|
|
99
|
+
conn = sqlite3.connect(path)
|
|
100
|
+
try:
|
|
101
|
+
cur = conn.cursor()
|
|
102
|
+
cur.execute(
|
|
103
|
+
"CREATE TABLE IF NOT EXISTS data ("
|
|
104
|
+
"id INTEGER PRIMARY KEY, "
|
|
105
|
+
"json TEXT NOT NULL"
|
|
106
|
+
")"
|
|
107
|
+
)
|
|
108
|
+
json_str = json.dumps(data)
|
|
109
|
+
# Ensure id=1 holds the latest payload
|
|
110
|
+
cur.execute("DELETE FROM data WHERE id = 1")
|
|
111
|
+
cur.execute("INSERT INTO data (id, json) VALUES (1, ?)", (json_str,))
|
|
112
|
+
conn.commit()
|
|
113
|
+
finally:
|
|
114
|
+
conn.close()
|
|
115
|
+
except sqlite3.Error as e:
|
|
116
|
+
raise SerializationError(
|
|
117
|
+
f"Failed to save SQLite3 file '{path}': {e}",
|
|
118
|
+
format_name=self.format_name,
|
|
119
|
+
original_error=e,
|
|
120
|
+
) from e
|
|
121
|
+
|
|
122
|
+
def load_file(self, file_path: Union[str, Path], **options: Any) -> Any:
|
|
123
|
+
"""
|
|
124
|
+
Load Python data from a SQLite3 database file.
|
|
125
|
+
|
|
126
|
+
Reads row with ``id = 1`` from the ``data`` table and returns the
|
|
127
|
+
JSON-decoded payload. This mirrors the simple dict-based contract
|
|
128
|
+
used by the tests and higher-level APIs.
|
|
129
|
+
"""
|
|
130
|
+
path = Path(file_path)
|
|
131
|
+
if not path.exists():
|
|
132
|
+
raise FileNotFoundError(f"SQLite3 file not found: {path}")
|
|
133
|
+
|
|
134
|
+
try:
|
|
135
|
+
conn = sqlite3.connect(path)
|
|
136
|
+
try:
|
|
137
|
+
cur = conn.cursor()
|
|
138
|
+
cur.execute(
|
|
139
|
+
"SELECT json FROM data WHERE id = 1"
|
|
140
|
+
)
|
|
141
|
+
row = cur.fetchone()
|
|
142
|
+
if row is None or row[0] is None:
|
|
143
|
+
# No payload stored yet – mirror behaviour of other
|
|
144
|
+
# serializers by returning None.
|
|
145
|
+
return None
|
|
146
|
+
|
|
147
|
+
return json.loads(row[0])
|
|
148
|
+
finally:
|
|
149
|
+
conn.close()
|
|
150
|
+
except sqlite3.Error as e:
|
|
151
|
+
raise SerializationError(
|
|
152
|
+
f"Failed to load SQLite3 file '{path}': {e}",
|
|
153
|
+
format_name=self.format_name,
|
|
154
|
+
original_error=e,
|
|
155
|
+
) from e
|
|
156
|
+
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
Company: eXonware.com
|
|
5
5
|
Author: Eng. Muhammad AlShehri
|
|
6
6
|
Email: connect@exonware.com
|
|
7
|
-
Version: 0.0.1.
|
|
7
|
+
Version: 0.0.1.411
|
|
8
8
|
Generation Date: 02-Nov-2025
|
|
9
9
|
|
|
10
10
|
JSON5 Serialization - Extended JSON with Comments and Trailing Commas
|
|
@@ -29,12 +29,11 @@ from pathlib import Path
|
|
|
29
29
|
# Lazy import for json5 - the lazy hook will automatically handle ImportError
|
|
30
30
|
import json5
|
|
31
31
|
|
|
32
|
-
from
|
|
33
|
-
from ...contracts import ISerialization
|
|
32
|
+
from .json import JsonSerializer
|
|
34
33
|
from ....errors import SerializationError
|
|
35
34
|
|
|
36
35
|
|
|
37
|
-
class Json5Serializer(
|
|
36
|
+
class Json5Serializer(JsonSerializer):
|
|
38
37
|
"""
|
|
39
38
|
JSON5 serializer with comment support.
|
|
40
39
|
|
|
@@ -58,7 +57,10 @@ class Json5Serializer(ASerialization):
|
|
|
58
57
|
Priority #1: Security - Prevent DoS via excessive nesting
|
|
59
58
|
Priority #4: Performance - Prevent hangs on large data
|
|
60
59
|
"""
|
|
61
|
-
# JSON5 parser has known performance issues, use stricter limits
|
|
60
|
+
# JSON5 parser has known performance issues, use stricter limits.
|
|
61
|
+
# We still rely on the JsonSerializer base for all generic JSON
|
|
62
|
+
# behaviour (path operations, queries, etc.), only overriding the
|
|
63
|
+
# concrete encode/decode layer.
|
|
62
64
|
super().__init__(max_depth=max_depth, max_size_mb=max_size_mb)
|
|
63
65
|
if json5 is None:
|
|
64
66
|
raise ImportError("json5 library required. Install with: pip install json5")
|